Skip to content

Commit

Permalink
docs: ADR 59: Incremental static regeneration (#5863)
Browse files Browse the repository at this point in the history
* ADR 59: Incremental static regeneration
A quick ADR to describe the consequences of static project page builds, from Engaging Crowds.

* A brief note about CDN caching

* Rewrite the explanation of rewrites

* Rearrange the middleware and add comments

---------

Co-authored-by: Delilah C <23665803+goplayoutside3@users.noreply.github.com>
  • Loading branch information
eatyourgreens and goplayoutside3 authored Feb 8, 2024
1 parent b69e525 commit 0f56899
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/arch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,4 @@
- [ADR 56: Use markdownz to parse markdown](adr-56.md)
- [ADR 57: Build @zooniverse/classifier and @zooniverse/react-components as ES modules](adr-57.md)
- [ADR 58: Internationalisation with the Panoptes translations API](adr-58.md)
- [ADR 59: Incremental Static Regeneration of project pages](adr-59.md)
21 changes: 21 additions & 0 deletions docs/arch/adr-59.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# ADR 58: Incremental Static Regeneration for project pages

## Status
Accepted

## Context
When the first Engaging Crowds projects launched, project pages were built dynamically with `getServerSideProps`. Page builds were slow, with pages sometimes taking several seconds to load in the browser ([#2741](https://github.com/zooniverse/front-end-monorepo/issues/2741).)

## Decision
Use [Incremental Static Regeneration](https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration) (ISR) to build project pages. ISR is a feature of Next.js, which allows page HTML and JSON to be built and cached on demand, then served with `stale-while-revalidate` cache control headers. While a page is building, visitors will get stale, cached content, resulting in a faster experience.

## Consequences
- Page builds were switched from `getServerSideProps` to `getStaticProps`, with a revalidation time of 60s. Revalidation can be set individually for each page route.
- `getStaticProps` can still be slow, when it runs, so data-fetching from the Panoptes API may need further optimisation ([#3341](https://github.com/zooniverse/front-end-monorepo/issues/3341).)
- Production projects and staging projects each have their own static routes: `/production/:owner/:project` and `/staging/:owner/:project`. Next.js middleware rewrites incoming request URLs to the production and staging routes used by the project app;
- `/projects/nora-dot-eisner/planet-hunters-tess` is rewritten (proxied) to `/projects/production/nora-dot-eisner/planet-hunters-tess`.
- `/projects/brooke/i-fancy-cats?env=staging` is rewritten (proxied) to `/projects/staging/brooke/i-fancy-cats`.
- API data isn't cached across page routes, so navigating between project pages will refetch the project and workflows etc. from the Panoptes API.
- When navigating between subjects, in a project that has page routes for individual subjects, `getStaticProps` is run for every subject. We worked around this by [shallow routing](https://nextjs.org/docs/pages/building-your-application/routing/linking-and-navigating#shallow-routing) client-side subject navigation, when the Done button is pressed. A better solution might be server-side caching of Panoptes API data across page routes, to avoid redundant computing of existing page props for each new subject.
- Volunteers no longer interact directly with the Next.js app. Browsers request page HTML, and JSON page props, from the `www.zooniverse.org` CDN. The CDN cache requests content from the Next.js app when cached content becomes stale.

21 changes: 18 additions & 3 deletions packages/app-project/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export function middleware(req, event) {
return NextResponse.next()
}

/*
Redirect /projects/[owner]/[project]?language=[lang] to /projects/[lang]/[owner]/[project].
*/
if (url.searchParams.has('language')) {
const locale = url.searchParams.get('language')
url.searchParams.delete('language')
Expand All @@ -46,21 +49,33 @@ export function middleware(req, event) {
return NextResponse.redirect(url)
}

/*
Don't rewrite project URLs that begin with /projects/production
*/
if (pathname.startsWith('/production')) {
return NextResponse.next()
}

/*
Don't rewrite project URLs that begin with /projects/staging
*/
if (pathname.startsWith('/staging')) {
return NextResponse.next()
}

/*
Project pages are served from /projects/staging/[owner]/[project]
and /projects/production/[owner]/[project]
Rewrite /projects/[owner]/[project] to /projects/production/[owner]/[project].
Rewrite /projects/[owner]/[project]?env=staging to /projects/staging/[owner]/[project].
*/
url.pathname = `/${panoptesEnv}${pathname}`

/*
Inject the locale, if present, into url.href.
Is this a bug in Next.js 13? It used to be handled automatically.
*/
if (url.locale) {
url.href = `${url.origin}/projects/${url.locale}/${panoptesEnv}${pathname}`
url.href = `${url.origin}/projects/${url.locale}${url.pathname}`
}

return NextResponse.rewrite(url)
}

0 comments on commit 0f56899

Please sign in to comment.