Render Time Render when, where, how, what, and why. Phil Hawksworth, Netlify

Oh, hello Phil Hawksworth Developer Experience, Netlify

Oh, hello @ PhilHawksworth Developer Experience, Netlify

Oh, hello @ PhilHawksworth @ indieweb.social Developer Experience, Netlify

Oh, hello PhilHawksworth . NAMING IS HARD hawksworx.com Developer Experience, Netlify

A slight change of pace after Evan Some foundations for talks to come

Rendering

HTML / DOM

“…something something rendering on the server…” — Phil Hawksworth, 2013

“…ha ha ha do you just mean serving HTML?” — The person listening to Phil Hawksworth, 2013

Server Client

Server Client

Server Client

Robustness

The rule of least power https://www.w3.org/2001/tag/doc/leastPower.html

Server Client

Build Server Client

Build Server Edge Client

“by thunder, there are a lot of ways to approach rendering!” — Phil Hawksworth, May 2023

Confusion

A place for rendering

A time and a place for rendering

What / Where / When / How / Why

A few mins 15 mins 10 mins / Into and twaddle / Examining rendering / Questioning / Applying techniques / Example / Lessons

SECTION 1 Examining rendering What even do these acronyms mean?

NAMING IS HARD Terminology

G / ISR / ODB / SPA / MPA / ESR PA / MPA / SSR / CSR / SSG / D / SPA / MPA / SSR / CSR / SSG / SSR / CSR / SSG / DPR / DSG SSR / CSR / SSG / DPR / DSG / ESR / ISR / ODB / SPA / MPA / NAMING IS HARD

RENDERING SSG Static Site Generation Build Server Edge Client

CI/CD Continuous Integration / Continuous Deployment

RENDERING SSG Static Site Generation Build Server Edge Client

TRADITIONAL STACK LOAD BALANCERS WEB SERVERS DATABASES VARIOUS INCREASINGLY POPULAR PROVIDERS ASSETS ON CDN BUILD AHEAD OF TIME CODE & CONTENT

RENDERING CSR Client side rendering Build Server Edge Client

When… the assets have arrived the user interacts

RENDERING SSR Server side rendering Build Server Edge Client

the-other-side Build Server Edge Client-side Client

Build Server Server-side Client-side Edge Client

Build Server Server-side? Client-side Edge Client

not-Client-side Build Server Edge Client-side Client

RENDERING SSR Server side rendering Build Server Edge Client

RENDERING ESR Edge side rendering Build Server Edge Client

TRADITIONAL STACK LOAD BALANCERS WEB SERVERS DATABASES VARIOUS INCREASINGLY POPULAR PROVIDERS SERVERLESS RUNTIME ASSETS ON CDN SERVERLESS RUNTIMES BUILD CODE & CONTENT

“so which one is best, Phil?” — Some of you, possibly, May 2023

“It depends” — Phil Hawksworth, May 2023

“Yeah. Great. Thanks.” — Some of you, possibly, May 2023

“It depends on what?” — Some of you, hopefully, May 2023

“I’m glad you ask” — Me again, May 2023

The rule of least power https://www.w3.org/2001/tag/doc/leastPower.html

Best shovel for digging a hole? https://unsplash.com/photos/qG6QtyOaOGQ

Serverside, doesn’t have to mean Serverful. If I can do things in advance, I will. If I can’t, but can do things serverless, I will. If I can’t, but can add a server, I will.

Increments DPR / ODB / DSG / ISR / FFS

Increments DPR / ODB / DSG / ISR

RENDERING DPR Distributed Persistent Rendering RENDERING RENDERING ODB DSG On-demand Builders Deferred Static Generation

DGIITBWUTFTIRTGIAATWWBE NAMING IS HARD Don’t generate it in the build. Wait until the first time it’s requested, then generate it and add it to what was built earlier.

TRADITIONAL STACK LOAD BALANCERS WEB SERVERS DATABASES VARIOUS INCREASINGLY POPULAR PROVIDERS SERVERLESS RUNTIME ASSETS ON CDN SERVERLESS RUNTIMES BUILD CODE & CONTENT

Increments DPR / ODB / DSG / ISR

RENDERING ISR Incremental Static Regeneration

RENDERING ISR Incremental Static Regeneration SWR Stale While Revalidate

“Which is better, ISR or DPR”? — Some of you, possibly, May 2023

“It depends”

Deciding demands questions

What are the requirements?

SECTION 2 Example Applying different rendering techniques

EXAMPLE Social posts stash Self-hosting thousands of posts

Some requirements A URL for each of the 24,000 tweets Index pages listing each tweet with its URL Ability to search the tweets Retain a reasonable build time Avoid client-side rendering if possible A logical model that fits in my head SSG ODB ESR

JSON

/ Social index pages / Content pages Build Assets User JSON & Templates

www.hawksworx.com/notes/1/

Build duration 2 seconds

/ Post page view / Social index pages / Content pages Build JSON & Templates Assets ODB User

www.hawksworx.com/note/mstdn/109913367394738833

/ Post page view / Social index pages / Content pages Build JSON & Templates Assets ODB ESR / Search results page User

www.hawksworx.com/notes/search/?str=palo+alto www.hawksworx.com/notes/search/?str=render

The rule of least power https://www.w3.org/2001/tag/doc/leastPower.html

Vitepress Generates pages SSG / CSR

Vitepress Generates pages SSG / CSR + ODB / ESR

At build time JSON At request time

Source archive of data into Vitepress tweets.data.js export default { load() { return { LOTS OF JSON } } } `

Source archive of data into Vitepress tweets.data.js const tweets = require(“./tweets.json”); export default { load() { return tweets } } `

ODB function — render a tweet netlify/functions/view-tweet.js const { builder } = require(‘@netlify/functions’); const notes = require(‘../../tweets.json’); const pageTemplate = require(‘./page/template.js’); const handler = async(event) =>” { const id = event.path.split(“tweet/”)[1]; const note = notes[id]; ` return { statusCode: 200, headers: {“Content-Type”: “text/html”}, body: pageTemplate(note) } } exports.handler = builder(handler);

ODB function — render a tweet netlify/functions/view-tweet.js const { builder } = require(‘@netlify/functions’); const notes = require(‘../../tweets.json’); const pageTemplate = require(‘./page/template.js’); const handler = async(event) =>” { const id = event.path.split(“tweet/”)[1]; const note = notes[id]; ` return { statusCode: 200, headers: {“Content-Type”: “text/html”}, body: pageTemplate(note) } } exports.handler = builder(handler);

ODB function — render a tweet netlify/functions/view-tweet.js const { builder } = require(‘@netlify/functions’); const notes = require(‘../../tweets.json’); const pageTemplate = require(‘./page/template.js’); const handler = async(event) =>” { const id = event.path.split(“tweet/”)[1]; const note = notes[id]; ` return { statusCode: 200, headers: {“Content-Type”: “text/html”}, body: pageTemplate(note) } } exports.handler = builder(handler);

ODB function — render a tweet netlify/functions/view-tweet.js const { builder } = require(‘@netlify/functions’); const notes = require(‘../../tweets.json’); const pageTemplate = require(‘./page/template.js’); const handler = async(event) =>” { const id = event.path.split(“tweet/”)[1]; const note = notes[id]; ` return { statusCode: 200, headers: {“Content-Type”: “text/html”}, body: pageTemplate(note) } } exports.handler = builder(handler);

ODB function — render a tweet netlify/functions/view-tweet.js const { builder } = require(‘@netlify/functions’); const notes = require(‘../../tweets.json’); const pageTemplate = require(‘./page/template.js’); const handler = async(event) =>” { const id = event.path.split(“tweet/”)[1]; const note = notes[id]; ` return { statusCode: 200, headers: {“Content-Type”: “text/html”}, body: pageTemplate(note) } } exports.handler = builder(handler);

ODB function — render a tweet netlify/functions/view-tweet.js const { builder } = require(‘@netlify/functions’); const notes = require(‘../../tweets.json’); const pageTemplate = require(‘./page/template.js’); const handler = async(event) =>” { const id = event.path.split(“tweet/”)[1]; const note = notes[id]; ` return { statusCode: 200, headers: {“Content-Type”: “text/html”}, body: pageTemplate(note) } } exports.handler = builder(handler);

ODB function — render a tweet netlify/functions/view-tweet.js const { builder } = require(‘@netlify/functions’); const notes = require(‘../../tweets.json’); const pageTemplate = require(‘./page/template.js’); const handler = async(event) =>” { const id = event.path.split(“tweet/”)[1]; const note = notes[id]; ` return { statusCode: 200, headers: {“Content-Type”: “text/html”}, body: pageTemplate(note) } } exports.handler = builder(handler);

Nuxt Supports several rendering patterns SSG / SSR / CSR / ESR

Nuxt’s route-based rendering configuration nuxt.config.ts export default defineNuxtConfig({ routeRules: { // Homepage pre-rendered at build time ‘/’: { prerender: true }, // Product page generated on-demand, revalidates in background ‘/products/$’: { swr: true }, ` // Blog post generated on-demand once until next deploy ‘/blog/$’: { isr: true }, } }) // Admin dashboard renders only on client-side ‘/admin/$’: { ssr: false },

SECTION 3 Lessons Amid the confusion, what did we learn?

There is no one right way

Do work ahead of time if you can

You can mix and match rendering methods

Never choose an approach until you understand the requirements

Not all of Phil’s tweets are pure gold

NAMING IS HARD

For more netlify.com/blog/tutorials nuxt.com/docs/guide/concepts/rendering twitter.com/philhawksworth Phil Hawksworth, Netlify

Thank you! Grab me for questions (or to say hello) Phil Hawksworth, Netlify