Skip to content

Commit

Permalink
fix: create cache entries for fallback pages to support next@canary
Browse files Browse the repository at this point in the history
  • Loading branch information
pieh committed Oct 11, 2024
1 parent 4b4b9a7 commit 057d339
Showing 1 changed file with 52 additions and 6 deletions.
58 changes: 52 additions & 6 deletions src/build/content/prerendered.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { existsSync } from 'node:fs'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { join } from 'node:path'
import { join as posixJoin } from 'node:path/posix'

import { trace } from '@opentelemetry/api'
import { wrapTracer } from '@opentelemetry/api/experimental'
Expand Down Expand Up @@ -41,17 +42,28 @@ const writeCacheEntry = async (
}

/**
* Normalize routes by stripping leading slashes and ensuring root path is index
* Normalize routes by ensuring leading slashes and ensuring root path is index
*/
const routeToFilePath = (path: string) => (path === '/' ? '/index' : path)
const routeToFilePath = (path: string) => {
if (path === '/') {
return '/index'
}

if (path.startsWith('/')) {
return path
}

return `/${path}`
}

const buildPagesCacheValue = async (
path: string,
shouldUseEnumKind: boolean,
shouldSkipJson = false,
): Promise<NetlifyCachedPageValue> => ({
kind: shouldUseEnumKind ? 'PAGES' : 'PAGE',
html: await readFile(`${path}.html`, 'utf-8'),
pageData: JSON.parse(await readFile(`${path}.json`, 'utf-8')),
pageData: shouldSkipJson ? {} : JSON.parse(await readFile(`${path}.json`, 'utf-8')),
headers: undefined,
status: undefined,
})
Expand Down Expand Up @@ -146,8 +158,8 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void>
})
: false

await Promise.all(
Object.entries(manifest.routes).map(
await Promise.all([
...Object.entries(manifest.routes).map(
([route, meta]): Promise<void> =>
limitConcurrentPrerenderContentHandling(async () => {
const lastModified = meta.initialRevalidateSeconds
Expand Down Expand Up @@ -195,7 +207,41 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void>
await writeCacheEntry(key, value, lastModified, ctx)
}),
),
)
...Object.entries(manifest.dynamicRoutes).map(async ([route, meta]) => {
// fallback can be `string | false | null`
// - `string` - when user use pages router with `fallback: true`, and then it's html file path
// - `null` - when user use pages router with `fallback: 'block'` or app router with `export const dynamicParams = true`
// - `false` - when user use pages router with `fallback: false` or app router with `export const dynamicParams = false`
if (typeof meta.fallback === 'string') {
// https://github.com/vercel/next.js/pull/68603 started using route cache to serve fallbacks
// so we have to seed blobs with fallback entries

// create cache entry for pages router with `fallback: true` case
await limitConcurrentPrerenderContentHandling(async () => {
// dynamic routes don't have entries for each locale so we have to generate them
// ourselves. If i18n is not used we use empty string as "locale" to be able to use
// same handling wether i18n is used or not
const locales = ctx.buildConfig.i18n?.locales ?? ['']

const lastModified = Date.now()
for (const locale of locales) {
const key = routeToFilePath(posixJoin(locale, route))
const value = await buildPagesCacheValue(
join(ctx.publishDir, 'server/pages', key),
shouldUseEnumKind,
true, // there is no corresponding json file for fallback, so we are skipping it for this entry
)
// Netlify Forms are not support and require a workaround
if (value.kind === 'PAGE' || value.kind === 'PAGES' || value.kind === 'APP_PAGE') {
verifyNetlifyForms(ctx, value.html)
}

await writeCacheEntry(key, value, lastModified, ctx)
}
})
}
}),
])

// app router 404 pages are not in the prerender manifest
// so we need to check for them manually
Expand Down

0 comments on commit 057d339

Please sign in to comment.