Demystifying incremental static regeneration

A presentation at Decoupled Days 2021 in July 2021 in by Phil Hawksworth

Slide 1

Slide 1

Demystifying Incremental Static Regeneration And raising the Jamstack ceiling Phil Hawksworth, Netlify

Slide 2

Slide 2

! @philhawksworth

Slide 3

Slide 3

These slides and links findthat.at/incremental @philhawksworth

Slide 4

Slide 4

Why this talk? Terminology / confusion / doubt / opportunity

Slide 5

Slide 5

Jamstack @philhawksworth

Slide 6

Slide 6

JavaScript / APIs / Markup ( but Jamstack means more than what it stands for ) @philhawksworth

Slide 7

Slide 7

Jamstack A way of thinking about how to build for the web. The UI is compiled, the frontend is decoupled, and data is pulled in as needed. @philhawksworth

Slide 8

Slide 8

Decoupling @philhawksworth

Slide 9

Slide 9

Compiling @philhawksworth

Slide 10

Slide 10

Pre-generating @philhawksworth

Slide 11

Slide 11

It used to be so simple ASK FOR STUFF GET STUFF @philhawksworth

Slide 12

Slide 12

Time and context TRADITIONAL STACK LOAD BALANCERS WEB SERVERS DATABASES JAMSTACK ASSETS ON CDN BUILD AHEAD OF TIME @philhawksworth CODE & CONTENT

Slide 13

Slide 13

Decoupling @philhawksworth

Slide 14

Slide 14

Front-end code is no longer limited to being a product of a back-end system @philhawksworth

Slide 15

Slide 15

Capable of being served directly from a CDN @philhawksworth

Slide 16

Slide 16

Offloading hosting complexity as a solved problem @philhawksworth

Slide 17

Slide 17

Pre-generation of a site + The workflows and automation that unlocks @philhawksworth

Slide 18

Slide 18

T I F E N E B HUGE Deploys are immutable and atomic @philhawksworth

Slide 19

Slide 19

Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 20

Slide 20

Deploy 89 Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 21

Slide 21

Live Deploy 89 Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 22

Slide 22

Deploy 89 Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 23

Slide 23

Deploy 89 Deploy 88 Deploy 87 Live Deploy 86 @philhawksworth Deploy 86

Slide 24

Slide 24

Zero burden on the developers for caching logic

Slide 25

Slide 25

Caching is one of the easiest things in computer science — Nobody ever. @philhawksworth

Slide 26

Slide 26

Confidence & certainty @philhawksworth

Slide 27

Slide 27

But… (And potentially a big but) @philhawksworth

Slide 28

Slide 28

WH ? T U O B A T A User generated content?

Slide 29

Slide 29

WH ? T U O B A T A Sites with huge numbers of pages?

Slide 30

Slide 30

Has Jamstack reached its ceiling? WH ? T U O AT AB Sites with huge numbers of pages? WH ? T U O AT AB User generated content?

Slide 31

Slide 31

Incremental builds @philhawksworth

Slide 32

Slide 32

@ Phil Hawksworth Director of Developer Experience, Netlify

Slide 33

Slide 33

findthat.at/jamstack/book

Slide 34

Slide 34

findthat.at/interesting

Slide 35

Slide 35

These slides and links findthat.at/incremental @philhawksworth

Slide 36

Slide 36

Let’s talk 1 2 Approaches to delivering incremental builds Understanding the benefits and the sacrifices 3 A practical example of a first step to incremental builds

Slide 37

Slide 37

1 Approaches to delivering incremental builds @philhawksworth

Slide 38

Slide 38

S E H C A O R APP ISR Incremental Static Regeneration @philhawksworth / DPR Distributed Persistent Rendering / BYO Bring Your Own

Slide 39

Slide 39

Incremental Static Regeneration (ISR) @philhawksworth

Slide 40

Slide 40

Added to Next.js by Vercel @philhawksworth

Slide 41

Slide 41

@philhawksworth Source: https://www.smashingmagazine.com/2021/04/incremental-static-regeneration-nextjs

Slide 42

Slide 42

When to render? Specifying the fallback fallback: false fallback: true fallback: blocking If the page was not generated in the build, request will 404 Serve a stale page or holding page but update the cache for future requests Generate a page ondemand and cache it for future @philhawksworth

Slide 43

Slide 43

An excellent enhancement to Next.js Managing caching behaviours needs careful handling @philhawksworth

Slide 44

Slide 44

EARLI ER Distributed Persistent Rendering (DPR) @philhawksworth

Slide 45

Slide 45

Distributed Persistent Rendering (DPR) @philhawksworth

Slide 46

Slide 46

(Builds with a long tail) findthat.at/dpr @philhawksworth

Slide 47

Slide 47

Code @philhawksworth

Slide 48

Slide 48

Code Build Deploy number 75 @philhawksworth

Slide 49

Slide 49

Code Build Deploy number 75 @philhawksworth On demand

Slide 50

Slide 50

Code Build Deploy number 75 @philhawksworth On demand

Slide 51

Slide 51

Code Build Deploy number 75 @philhawksworth On demand

Slide 52

Slide 52

Code Build Deploy number 76 @philhawksworth

Slide 53

Slide 53

Code Build Deploy number 76 @philhawksworth On demand

Slide 54

Slide 54

Code Build Deploy number 76 @philhawksworth On demand

Slide 55

Slide 55

Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 56

Slide 56

Deploy 89 Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 57

Slide 57

Live Deploy 89 Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 58

Slide 58

Deploy 89 Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

Slide 59

Slide 59

A serverless function const handler = async event =>” { // return a view }; @philhawksworth

Slide 60

Slide 60

A serverless function const { builder } = require(“@netlify/functions”); const handler = async event =>” { // return a view }; exports.handler = builder(handler); @philhawksworth

Slide 61

Slide 61

Help to refine this pattern findthat.at/dpr/rfc findthat.at/dpr/csstricks @philhawksworth

Slide 62

Slide 62

Bring Your Own What are the underlying primitives you need? @philhawksworth

Slide 63

Slide 63

Use with any generator or framework @philhawksworth

Slide 64

Slide 64

A site without complex interdependencies between pages

  • An tool which can generate pages from a set of data
  • The ability to cache things between builds @philhawksworth

Slide 65

Slide 65

lolly.net thousands of pages of user content Each new deploy comes from the build cache And then generates new pages and adds them to the build cache @philhawksworth

Slide 66

Slide 66

2 Understanding the benefits and the sacrifices @philhawksworth

Slide 67

Slide 67

Generating pages on-demand S G N BRI The ability to serve far larger sites The ability to deliver previously unknown, dynamic content @philhawksworth

Slide 68

Slide 68

BUT Generating pages on-demand Can re-introduce the uncertainty of what lives at a URL Can violate the contract of atomic, immutable builds Can make architectures harder to reason about @philhawksworth

Slide 69

Slide 69

So consider your approach carefully Evaluate the functional and non-functional requirements of your project @philhawksworth

Slide 70

Slide 70

3 A practical example of a first step to incremental builds @philhawksworth

Slide 71

Slide 71

findthat.at findthat.at/thecode

Slide 72

Slide 72

_redirects /thecode /incremental /supasupa /magic-roundabout /learn/graphql /eleventail /cal /jamstack/london /jamstack/growing @philhawksworth https://github.com/philhawksworth/findthat https://noti.st/philhawksworth https://www.netlify.com/blog/2021/06/28/sa https://en.wikipedia.org/wiki/Magic_Rounda https://graphql.org/learn/ https://www.hawksworx.com/blog/eleventailhttps://calendar.google.com/calendar/u/0/r https://app.experiencewelcome.com/events/9 https://noti.st/philhawksworth/5Zh3rm/jams

Slide 73

Slide 73

Slide 74

Slide 74

Slide 75

Slide 75

BEH S R U AVIO Render the page the first time it is requested Persist the page as part of the latest deploy Start fresh after each new deploy @philhawksworth

Slide 76

Slide 76

We’ll need 1 2 A function to build the pages on-demand and persist them A way to direct requests to our function

Slide 77

Slide 77

_redirects /magic-roundabout /learn/graphql /eleventail /cal /jamstack/london /jamstack/growing https://en.wikipedia.org/wiki/Magic_Rounda https://graphql.org/learn/ https://www.hawksworx.com/blog/eleventailhttps://calendar.google.com/calendar/u/0/r https://app.experiencewelcome.com/events/9 https://noti.st/philhawksworth/5Zh3rm/jams /qr/*$ /.netlify/functions/show-qr @philhawksworth 200

Slide 78

Slide 78

show-qr.js const const const const const { builder } QRCode fetch pageTemplate rootURL = = = = = require(“@netlify/functions”); require(‘qrcode’); require(‘node-fetch’); require(‘../../includes/page.js’); “https://findthat.at”; const handler = async event =>” { // Get the original short URL (without the qr part of the path) const path = event.path.split(“/qr/”)[1]; const shortURL = ${rootURL}/${path}; // follow the redirect to get the destination to display const destinationURL = await fetch(shortURL); // make a QR cade and then return a page displaying it return QRCode.toString(shortURL, {‘type’:’svg’} ) .then(svg =>” { // render the data into the template return { statusCode: 200, body: pageTemplate({ shortURL : shortURL, destinationURL : destinationURL.url, svg: escape(svg) }) }; }) .catch(err =>” { console.error(err) }) }; exports.handler = builder(handler); @philhawksworth

Slide 79

Slide 79

show-qr.js const handler = async event =>” { // Get the original short URL (without the qr part of the path) const path = event.path.split(“/qr/”)[1]; const shortURL = ${rootURL}/${path}; // follow the redirect to get the destination to display const destinationURL = await fetch(shortURL); // make a QR cade and then return a page displaying it return QRCode.toString(shortURL, {‘type’:’svg’} ) .then(svg =>” { // render the data into the template return { statusCode: 200, body: pageTemplate({ shortURL : shortURL, destinationURL : destinationURL.url, svg: escape(svg) }) }; }) .catch(err =>” { console.error(err) }) }; @philhawksworth

Slide 80

Slide 80

show-qr.js const const const const const { builder } QRCode fetch pageTemplate rootURL @philhawksworth = = = = = require(“@netlify/functions”); require(‘qrcode’); require(‘node-fetch’); require(‘../../includes/page.js’); “https://findthat.at”;

Slide 81

Slide 81

page.js module.exports = (data) =>” { return <!DOCTYPE html> … <body> <header> <h1><a href="${ data.shortURL }">${ data.shortURL }</a></h1> <a class="dest" href="${ data.destinationURL }">${ data.destinationURL }</a> </header> <main> <img src='data:image/svg+xml;utf8,${ data.svg }'> </main> …;} @philhawksworth

Slide 82

Slide 82

show-qr.js const const const const const { builder } QRCode fetch pageTemplate rootURL = = = = = require(“@netlify/functions”); require(‘qrcode’); require(‘node-fetch’); require(‘../../includes/page.js’); “https://findthat.at”; const handler = async event =>” { // Get the original short URL (without the qr part of the path) const path = event.path.split(“/qr/”)[1]; const shortURL = ${rootURL}/${path}; // follow the redirect to get the destination to display const destinationURL = await fetch(shortURL); // make a QR cade and then return a page displaying it return QRCode.toString(shortURL, {‘type’:’svg’} ) .then(svg =>” { // render the data into the template return { statusCode: 200, body: pageTemplate({ shortURL : shortURL, destinationURL : destinationURL.url, svg: escape(svg) }) }; }) .catch(err =>” { console.error(err) }) }; exports.handler = builder(handler); @philhawksworth

Slide 83

Slide 83

show-qr.js const { builder } = require(“@netlify/functions”); const handler = async event =>” { … }; exports.handler = builder(handler); @philhawksworth

Slide 84

Slide 84

These slides and links findthat.at/incremental findthat.at/qr/incremental @philhawksworth

Slide 85

Slide 85

findthat.at/qr/incremental

Slide 86

Slide 86

Wrapping up @philhawksworth

Slide 87

Slide 87

R E B M E M RE Incremental builds are possible right now Sites built with any framework or generator can be enhanced Embracing the law of least power helps protect an architecture you can reason about @philhawksworth

Slide 88

Slide 88

R E B M E M RE The benefits of a Jamstack architecture are worth protecting Examine your use cases Please don’t make me have to understand and manage end-to-end caching @philhawksworth

Slide 89

Slide 89

Jamstack Community Survey 2021 findthat.at/jamstack/survey Jamstack Conf - Speak! jamstackconf.com/cfp

Slide 90

Slide 90

Thanks @philhawksworth findthat.at/incremental