Skip to content

Commit

Permalink
Fix initialRevalidateSeconds manifest field with i18n (#17926)
Browse files Browse the repository at this point in the history
This makes sure the correct `initialRevalidateSeconds` field is populated in the `prerender-manifest` for non-dynamic SSG pages since they will be inserted into the `initialPageRevalidationMap` under their locale prefixed variant with `i18n` enabled

x-ref: #17370
  • Loading branch information
ijjk committed Oct 16, 2020
1 parent 75f75f3 commit f0ead09
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 8 deletions.
10 changes: 8 additions & 2 deletions packages/next/build/index.ts
Expand Up @@ -959,21 +959,27 @@ export default async function build(
}

if (isSsg) {
const { i18n } = config.experimental

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

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

finalPrerenderRoutes[page] = {
initialRevalidateSeconds:
exportConfig.initialPageRevalidationMap[page],
exportConfig.initialPageRevalidationMap[revalidationMapPath],
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[page]
exportConfig.initialPageRevalidationMap[revalidationMapPath]
pageInfos.set(page, pageInfo)
}
} else {
Expand Down
21 changes: 18 additions & 3 deletions packages/next/build/webpack/loaders/next-serverless-loader.ts
Expand Up @@ -248,6 +248,8 @@ const nextServerlessLoader: loader.Loader = function () {
let localeDomainRedirect
const localePathResult = normalizeLocalePath(parsedUrl.pathname, i18n.locales)
routeNoAssetPath = normalizeLocalePath(routeNoAssetPath, i18n.locales).pathname
if (localePathResult.detectedLocale) {
detectedLocale = localePathResult.detectedLocale
req.url = formatUrl({
Expand Down Expand Up @@ -337,6 +339,7 @@ const nextServerlessLoader: loader.Loader = function () {
res.end()
return
}
detectedLocale = detectedLocale || defaultLocale
`
: `
Expand Down Expand Up @@ -547,10 +550,10 @@ const nextServerlessLoader: loader.Loader = function () {
if (parsedUrl.pathname.match(/_next\\/data/)) {
const {
default: getrouteNoAssetPath,
default: getRouteNoAssetPath,
} = require('next/dist/next-server/lib/router/utils/get-route-from-asset-path');
_nextData = true;
parsedUrl.pathname = getrouteNoAssetPath(
parsedUrl.pathname = getRouteNoAssetPath(
parsedUrl.pathname.replace(
new RegExp('/_next/data/${escapedBuildId}/'),
'/'
Expand Down Expand Up @@ -609,12 +612,24 @@ const nextServerlessLoader: loader.Loader = function () {
? `const nowParams = req.headers && req.headers["x-now-route-matches"]
? getRouteMatcher(
(function() {
const { re, groups } = getRouteRegex("${page}");
const { re, groups, routeKeys } = getRouteRegex("${page}");
return {
re: {
// Simulate a RegExp match from the \`req.url\` input
exec: str => {
const obj = parseQs(str);
// favor named matches if available
const routeKeyNames = Object.keys(routeKeys)
if (routeKeyNames.every(name => obj[name])) {
return routeKeyNames.reduce((prev, keyName) => {
const paramName = routeKeys[keyName]
prev[groups[paramName].pos] = obj[keyName]
return prev
}, {})
}
return Object.keys(obj).reduce(
(prev, key) =>
Object.assign(prev, {
Expand Down
104 changes: 101 additions & 3 deletions test/integration/i18n-support/test/index.test.js
Expand Up @@ -5,6 +5,7 @@ import fs from 'fs-extra'
import cheerio from 'cheerio'
import { join } from 'path'
import webdriver from 'next-webdriver'
import escapeRegex from 'escape-string-regexp'
import {
fetchViaHTTP,
findPort,
Expand All @@ -15,6 +16,7 @@ import {
renderViaHTTP,
File,
waitFor,
normalizeRegEx,
} from 'next-test-utils'

jest.setTimeout(1000 * 60 * 2)
Expand All @@ -24,7 +26,7 @@ const nextConfig = new File(join(appDir, 'next.config.js'))
let app
let appPort
let buildPagesDir
// let buildId
let buildId

const locales = ['en-US', 'nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en']

Expand Down Expand Up @@ -59,6 +61,102 @@ function runTests(isDev) {
],
})
})

it('should output correct prerender-manifest', async () => {
const prerenderManifest = await fs.readJSON(
join(appDir, '.next/prerender-manifest.json')
)

for (const key of Object.keys(prerenderManifest.dynamicRoutes)) {
const item = prerenderManifest.dynamicRoutes[key]
item.routeRegex = normalizeRegEx(item.routeRegex)
item.dataRouteRegex = normalizeRegEx(item.dataRouteRegex)
}

expect(prerenderManifest.routes).toEqual({
'/en-US/gsp/fallback/first': {
dataRoute: `/_next/data/${buildId}/en-US/gsp/fallback/first.json`,
initialRevalidateSeconds: false,
srcRoute: '/gsp/fallback/[slug]',
},
'/en-US/gsp/fallback/second': {
dataRoute: `/_next/data/${buildId}/en-US/gsp/fallback/second.json`,
initialRevalidateSeconds: false,
srcRoute: '/gsp/fallback/[slug]',
},
'/en-US/gsp/no-fallback/first': {
dataRoute: `/_next/data/${buildId}/en-US/gsp/no-fallback/first.json`,
initialRevalidateSeconds: false,
srcRoute: '/gsp/no-fallback/[slug]',
},
'/en-US/gsp/no-fallback/second': {
dataRoute: `/_next/data/${buildId}/en-US/gsp/no-fallback/second.json`,
initialRevalidateSeconds: false,
srcRoute: '/gsp/no-fallback/[slug]',
},
'/en-US/not-found/fallback/first': {
dataRoute: `/_next/data/${buildId}/en-US/not-found/fallback/first.json`,
initialRevalidateSeconds: false,
srcRoute: '/not-found/fallback/[slug]',
},
'/en-US/not-found/fallback/second': {
dataRoute: `/_next/data/${buildId}/en-US/not-found/fallback/second.json`,
initialRevalidateSeconds: false,
srcRoute: '/not-found/fallback/[slug]',
},
'/gsp': {
dataRoute: `/_next/data/${buildId}/gsp.json`,
srcRoute: null,
initialRevalidateSeconds: false,
},
'/nl-NL/gsp/no-fallback/second': {
dataRoute: `/_next/data/${buildId}/nl-NL/gsp/no-fallback/second.json`,
initialRevalidateSeconds: false,
srcRoute: '/gsp/no-fallback/[slug]',
},
'/not-found': {
dataRoute: `/_next/data/${buildId}/not-found.json`,
srcRoute: null,
initialRevalidateSeconds: false,
},
})
expect(prerenderManifest.dynamicRoutes).toEqual({
'/gsp/fallback/[slug]': {
routeRegex: normalizeRegEx(
'^\\/gsp\\/fallback\\/([^\\/]+?)(?:\\/)?$'
),
dataRoute: `/_next/data/${buildId}/gsp/fallback/[slug].json`,
fallback: '/gsp/fallback/[slug].html',
dataRouteRegex: normalizeRegEx(
`^\\/_next\\/data\\/${escapeRegex(
buildId
)}\\/gsp\\/fallback\\/([^\\/]+?)\\.json$`
),
},
'/gsp/no-fallback/[slug]': {
routeRegex: normalizeRegEx(
'^\\/gsp\\/no\\-fallback\\/([^\\/]+?)(?:\\/)?$'
),
dataRoute: `/_next/data/${buildId}/gsp/no-fallback/[slug].json`,
fallback: false,
dataRouteRegex: normalizeRegEx(
`^/_next/data/${escapeRegex(
buildId
)}/gsp/no\\-fallback/([^/]+?)\\.json$`
),
},
'/not-found/fallback/[slug]': {
dataRoute: `/_next/data/${buildId}/not-found/fallback/[slug].json`,
dataRouteRegex: normalizeRegEx(
`^\\/_next\\/data\\/${escapeRegex(
buildId
)}\\/not\\-found\\/fallback\\/([^\\/]+?)\\.json$`
),
fallback: '/not-found/fallback/[slug].html',
routeRegex: normalizeRegEx('^/not\\-found/fallback/([^/]+?)(?:/)?$'),
},
})
})
}

it('should navigate with locale prop correctly', async () => {
Expand Down Expand Up @@ -1145,7 +1243,7 @@ describe('i18n Support', () => {
appPort = await findPort()
app = await nextStart(appDir, appPort)
buildPagesDir = join(appDir, '.next/server/pages')
// buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8')
buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8')
})
afterAll(() => killApp(app))

Expand All @@ -1161,7 +1259,7 @@ describe('i18n Support', () => {
appPort = await findPort()
app = await nextStart(appDir, appPort)
buildPagesDir = join(appDir, '.next/serverless/pages')
// buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8')
buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8')
})
afterAll(async () => {
nextConfig.restore()
Expand Down

0 comments on commit f0ead09

Please sign in to comment.