Skip to content

Commit

Permalink
Ensure prerender-manifest contains all i18n revalidate values (#21404)
Browse files Browse the repository at this point in the history
This insures we add entries for each locale version of a non-dynamic SSG page since they can have unique revalidate values. This requires a version bump in the `prerender-manifest` since the static routes now contain additional values which need to be handled separately. 

Fixes: #21568
  • Loading branch information
ijjk committed Jan 27, 2021
1 parent b785fbc commit 87ed37d
Show file tree
Hide file tree
Showing 4 changed files with 477 additions and 216 deletions.
91 changes: 57 additions & 34 deletions packages/next/build/index.ts
Expand Up @@ -85,6 +85,7 @@ import getBaseWebpackConfig from './webpack-config'
import { PagesManifest } from './webpack/plugins/pages-manifest-plugin'
import { writeBuildId } from './write-build-id'
import opentelemetryApi from '@opentelemetry/api'
import { normalizeLocalePath } from '../next-server/lib/i18n/normalize-locale-path'

const staticCheckWorker = require.resolve('./utils')

Expand All @@ -102,7 +103,7 @@ export type DynamicSsgRoute = {
}

export type PrerenderManifest = {
version: 2
version: 3
routes: { [route: string]: SsgRoute }
dynamicRoutes: { [route: string]: DynamicSsgRoute }
notFoundRoutes: string[]
Expand Down Expand Up @@ -880,6 +881,8 @@ export default async function build(

if (postCompileSpinner) postCompileSpinner.stopAndPersist()

const { i18n } = config

await traceAsyncFn(tracer.startSpan('static-generation'), async () => {
if (staticPages.size > 0 || ssgPages.size > 0 || useStatic404) {
const combinedPages = [...staticPages, ...ssgPages]
Expand Down Expand Up @@ -910,8 +913,6 @@ export default async function build(
// n.b. we cannot handle this above in combinedPages because the dynamic
// page must be in the `pages` array, but not in the mapping.
exportPathMap: (defaultMap: any) => {
const { i18n } = config

// Dynamically routed pages should be prerendered to be used as
// a client-side skeleton (fallback) while data is being fetched.
// This ensures the end-user never sees a 500 or slow response from the
Expand Down Expand Up @@ -1061,7 +1062,6 @@ export default async function build(
pagesManifest[page] = relativeDest
}

const { i18n } = config
const isNotFound = ssgNotFoundPaths.includes(page)

// for SSG files with i18n the non-prerendered variants are
Expand Down Expand Up @@ -1136,9 +1136,12 @@ export default async function build(
const hasAmp = hybridAmpPages.has(page)
const file = normalizePagePath(page)

// The dynamic version of SSG pages are only prerendered if the fallback
// is enabled. Below, we handle the specific prerenders of these.
if (!(isSsg && isDynamic && !isStaticSsgFallback)) {
// The dynamic version of SSG pages are only prerendered if the
// fallback is enabled. Below, we handle the specific prerenders
// of these.
const hasHtmlOutput = !(isSsg && isDynamic && !isStaticSsgFallback)

if (hasHtmlOutput) {
await moveExportedPage(page, page, file, isSsg, 'html')
}

Expand All @@ -1152,31 +1155,46 @@ export default async function build(
}

if (isSsg) {
const { i18n } = config

// For a non-dynamic SSG page, we must copy its data file from export.
// For a non-dynamic SSG page, we must copy its data file
// from export, we already moved the HTML file above
if (!isDynamic) {
await moveExportedPage(page, page, file, true, 'json')

const revalidationMapPath = i18n
? `/${i18n.defaultLocale}${page === '/' ? '' : page}`
: page

finalPrerenderRoutes[page] = {
initialRevalidateSeconds:
exportConfig.initialPageRevalidationMap[revalidationMapPath],
srcRoute: null,
dataRoute: path.posix.join(
'/_next/data',
buildId,
`${file}.json`
),
await moveExportedPage(page, page, file, isSsg, 'json')

if (i18n) {
// TODO: do we want to show all locale variants in build output
for (const locale of i18n.locales) {
const localePage = `/${locale}${page === '/' ? '' : page}`

if (!ssgNotFoundPaths.includes(localePage)) {
finalPrerenderRoutes[localePage] = {
initialRevalidateSeconds:
exportConfig.initialPageRevalidationMap[localePage],
srcRoute: null,
dataRoute: path.posix.join(
'/_next/data',
buildId,
`${file}.json`
),
}
}
}
} else {
finalPrerenderRoutes[page] = {
initialRevalidateSeconds:
exportConfig.initialPageRevalidationMap[page],
srcRoute: null,
dataRoute: path.posix.join(
'/_next/data',
buildId,
`${file}.json`
),
}
}
// Set Page Revalidation Interval
const pageInfo = pageInfos.get(page)
if (pageInfo) {
pageInfo.initialRevalidateSeconds =
exportConfig.initialPageRevalidationMap[revalidationMapPath]
exportConfig.initialPageRevalidationMap[page]
pageInfos.set(page, pageInfo)
}
} else {
Expand All @@ -1191,15 +1209,15 @@ export default async function build(
page,
route,
pageFile,
true,
isSsg,
'html',
true
)
await moveExportedPage(
page,
route,
pageFile,
true,
isSsg,
'json',
true
)
Expand All @@ -1210,15 +1228,15 @@ export default async function build(
page,
ampPage,
ampPage,
true,
isSsg,
'html',
true
)
await moveExportedPage(
page,
ampPage,
ampPage,
true,
isSsg,
'json',
true
)
Expand Down Expand Up @@ -1306,7 +1324,7 @@ export default async function build(
}
})
const prerenderManifest: PrerenderManifest = {
version: 2,
version: 3,
routes: finalPrerenderRoutes,
dynamicRoutes: finalDynamicRoutes,
notFoundRoutes: ssgNotFoundPaths,
Expand All @@ -1321,10 +1339,11 @@ export default async function build(
await generateClientSsgManifest(prerenderManifest, {
distDir,
buildId,
locales: config.i18n?.locales || [],
})
} else {
const prerenderManifest: PrerenderManifest = {
version: 2,
version: 3,
routes: {},
dynamicRoutes: {},
preview: previewProps,
Expand Down Expand Up @@ -1408,13 +1427,17 @@ export type ClientSsgManifest = Set<string>

function generateClientSsgManifest(
prerenderManifest: PrerenderManifest,
{ buildId, distDir }: { buildId: string; distDir: string }
{
buildId,
distDir,
locales,
}: { buildId: string; distDir: string; locales: string[] }
) {
const ssgPages: ClientSsgManifest = new Set<string>([
...Object.entries(prerenderManifest.routes)
// Filter out dynamic routes
.filter(([, { srcRoute }]) => srcRoute == null)
.map(([route]) => route),
.map(([route]) => normalizeLocalePath(route, locales).pathname),
...Object.keys(prerenderManifest.dynamicRoutes),
])

Expand Down
5 changes: 0 additions & 5 deletions packages/next/next-server/server/incremental-cache.ts
Expand Up @@ -3,7 +3,6 @@ import LRUCache from 'next/dist/compiled/lru-cache'
import path from 'path'
import { PrerenderManifest } from '../../build'
import { PRERENDER_MANIFEST } from '../lib/constants'
import { normalizeLocalePath } from '../lib/i18n/normalize-locale-path'
import { normalizePagePath } from './normalize-page-path'

function toRoute(pathname: string): string {
Expand Down Expand Up @@ -89,10 +88,6 @@ export class IncrementalCache {
private calculateRevalidate(pathname: string): number | false {
pathname = toRoute(pathname)

if (!this.prerenderManifest.routes[pathname]) {
pathname = toRoute(normalizeLocalePath(pathname, this.locales).pathname)
}

// in development we don't have a prerender-manifest
// and default to always revalidating to allow easier debugging
const curTime = new Date().getTime()
Expand Down

0 comments on commit 87ed37d

Please sign in to comment.