Render when? Render where? Render why? Render what?

A presentation at VueConf US in May 2023 in New Orleans, LA, USA by Phil Hawksworth

Slide 1

Slide 1

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

Slide 2

Slide 2

Oh, hello Phil Hawksworth Developer Experience, Netlify

Slide 3

Slide 3

Oh, hello @ PhilHawksworth Developer Experience, Netlify

Slide 4

Slide 4

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

Slide 5

Slide 5

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

Slide 6

Slide 6

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

Slide 7

Slide 7

Rendering

Slide 8

Slide 8

HTML / DOM

Slide 9

Slide 9

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

Slide 10

Slide 10

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

Slide 11

Slide 11

Server Client

Slide 12

Slide 12

Server Client

Slide 13

Slide 13

Server Client

Slide 14

Slide 14

Robustness

Slide 15

Slide 15

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

Slide 16

Slide 16

Server Client

Slide 17

Slide 17

Build Server Client

Slide 18

Slide 18

Build Server Edge Client

Slide 19

Slide 19

Slide 20

Slide 20

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

Slide 21

Slide 21

Confusion

Slide 22

Slide 22

A place for rendering

Slide 23

Slide 23

A time and a place for rendering

Slide 24

Slide 24

What / Where / When / How / Why

Slide 25

Slide 25

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

Slide 26

Slide 26

SECTION 1 Examining rendering What even do these acronyms mean?

Slide 27

Slide 27

NAMING IS HARD Terminology

Slide 28

Slide 28

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

Slide 29

Slide 29

RENDERING SSG Static Site Generation Build Server Edge Client

Slide 30

Slide 30

CI/CD Continuous Integration / Continuous Deployment

Slide 31

Slide 31

RENDERING SSG Static Site Generation Build Server Edge Client

Slide 32

Slide 32

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

Slide 33

Slide 33

RENDERING CSR Client side rendering Build Server Edge Client

Slide 34

Slide 34

When… the assets have arrived the user interacts

Slide 35

Slide 35

RENDERING SSR Server side rendering Build Server Edge Client

Slide 36

Slide 36

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

Slide 37

Slide 37

Build Server Server-side Client-side Edge Client

Slide 38

Slide 38

Build Server Server-side? Client-side Edge Client

Slide 39

Slide 39

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

Slide 40

Slide 40

RENDERING SSR Server side rendering Build Server Edge Client

Slide 41

Slide 41

RENDERING ESR Edge side rendering Build Server Edge Client

Slide 42

Slide 42

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

Slide 43

Slide 43

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

Slide 44

Slide 44

“It depends” — Phil Hawksworth, May 2023

Slide 45

Slide 45

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

Slide 46

Slide 46

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

Slide 47

Slide 47

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

Slide 48

Slide 48

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

Slide 49

Slide 49

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

Slide 50

Slide 50

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.

Slide 51

Slide 51

Increments DPR / ODB / DSG / ISR / FFS

Slide 52

Slide 52

Increments DPR / ODB / DSG / ISR

Slide 53

Slide 53

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

Slide 54

Slide 54

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.

Slide 55

Slide 55

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

Slide 56

Slide 56

Increments DPR / ODB / DSG / ISR

Slide 57

Slide 57

RENDERING ISR Incremental Static Regeneration

Slide 58

Slide 58

RENDERING ISR Incremental Static Regeneration SWR Stale While Revalidate

Slide 59

Slide 59

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

Slide 60

Slide 60

“It depends”

Slide 61

Slide 61

Deciding demands questions

Slide 62

Slide 62

What are the requirements?

Slide 63

Slide 63

SECTION 2 Example Applying different rendering techniques

Slide 64

Slide 64

EXAMPLE Social posts stash Self-hosting thousands of posts

Slide 65

Slide 65

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

Slide 66

Slide 66

JSON

Slide 67

Slide 67

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

Slide 68

Slide 68

www.hawksworx.com/notes/1/

Slide 69

Slide 69

Build duration 2 seconds

Slide 70

Slide 70

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

Slide 71

Slide 71

www.hawksworx.com/note/mstdn/109913367394738833

Slide 72

Slide 72

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

Slide 73

Slide 73

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

Slide 74

Slide 74

Slide 75

Slide 75

Slide 76

Slide 76

Slide 77

Slide 77

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

Slide 78

Slide 78

Vitepress Generates pages SSG / CSR

Slide 79

Slide 79

Vitepress Generates pages SSG / CSR + ODB / ESR

Slide 80

Slide 80

At build time JSON At request time

Slide 81

Slide 81

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

Slide 82

Slide 82

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

Slide 83

Slide 83

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);

Slide 84

Slide 84

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);

Slide 85

Slide 85

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);

Slide 86

Slide 86

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);

Slide 87

Slide 87

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);

Slide 88

Slide 88

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);

Slide 89

Slide 89

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);

Slide 90

Slide 90

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

Slide 91

Slide 91

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 },

Slide 92

Slide 92

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

Slide 93

Slide 93

There is no one right way

Slide 94

Slide 94

Do work ahead of time if you can

Slide 95

Slide 95

You can mix and match rendering methods

Slide 96

Slide 96

Never choose an approach until you understand the requirements

Slide 97

Slide 97

Not all of Phil’s tweets are pure gold

Slide 98

Slide 98

NAMING IS HARD

Slide 99

Slide 99

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

Slide 100

Slide 100

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