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

! @philhawksworth

These slides and links findthat.at/incremental @philhawksworth

Why this talk? Terminology / confusion / doubt / opportunity

Jamstack @philhawksworth

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

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

Decoupling @philhawksworth

Compiling @philhawksworth

Pre-generating @philhawksworth

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

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

Decoupling @philhawksworth

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

Capable of being served directly from a CDN @philhawksworth

Offloading hosting complexity as a solved problem @philhawksworth

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

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

Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

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

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

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

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

Zero burden on the developers for caching logic

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

Confidence & certainty @philhawksworth

But… (And potentially a big but) @philhawksworth

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

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

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?

Incremental builds @philhawksworth

@ Phil Hawksworth Director of Developer Experience, Netlify

findthat.at/jamstack/book

findthat.at/interesting

These slides and links findthat.at/incremental @philhawksworth

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

1 Approaches to delivering incremental builds @philhawksworth

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

Incremental Static Regeneration (ISR) @philhawksworth

Added to Next.js by Vercel @philhawksworth

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

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

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

EARLI ER Distributed Persistent Rendering (DPR) @philhawksworth

Distributed Persistent Rendering (DPR) @philhawksworth

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

Code @philhawksworth

Code Build Deploy number 75 @philhawksworth

Code Build Deploy number 75 @philhawksworth On demand

Code Build Deploy number 75 @philhawksworth On demand

Code Build Deploy number 75 @philhawksworth On demand

Code Build Deploy number 76 @philhawksworth

Code Build Deploy number 76 @philhawksworth On demand

Code Build Deploy number 76 @philhawksworth On demand

Live Deploy 88 Deploy 87 Deploy 86 @philhawksworth Deploy 86

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

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

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

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

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

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

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

Use with any generator or framework @philhawksworth

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

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

2 Understanding the benefits and the sacrifices @philhawksworth

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

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

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

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

findthat.at findthat.at/thecode

_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

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

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

_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

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

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

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

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

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

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

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

findthat.at/qr/incremental

Wrapping up @philhawksworth

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

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

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

Thanks @philhawksworth findthat.at/incremental