diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 7eb4ccd70189..8149a856c46f 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -566,12 +566,13 @@ export default async function build(dir: string, conf = null): Promise { ) staticCheckWorkers.end() - if (serverPropsPages.size > 0) { + if (serverPropsPages.size > 0 || ssgPages.size > 0) { // We update the routes manifest after the build with the - // serverProps routes since we can't determine this until after build - routesManifest.serverPropsRoutes = {} - - for (const page of serverPropsPages) { + // data routes since we can't determine these until after build + routesManifest.dataRoutes = getSortedRoutes([ + ...serverPropsPages, + ...ssgPages, + ]).map(page => { const pagePath = normalizePagePath(page) const dataRoute = path.posix.join( '/_next/data', @@ -579,7 +580,7 @@ export default async function build(dir: string, conf = null): Promise { `${pagePath}.json` ) - routesManifest.serverPropsRoutes[page] = { + return { page, dataRouteRegex: isDynamicRoute(page) ? getRouteRegex(dataRoute.replace(/\.json$/, '')).re.source.replace( @@ -594,7 +595,7 @@ export default async function build(dir: string, conf = null): Promise { )}$` ).source, } - } + }) await fsWriteFile( routesManifestPath, diff --git a/test/integration/getserverprops/test/index.test.js b/test/integration/getserverprops/test/index.test.js index 1c932da181e2..760db33379a1 100644 --- a/test/integration/getserverprops/test/index.test.js +++ b/test/integration/getserverprops/test/index.test.js @@ -24,72 +24,72 @@ let app let appPort let buildId -const expectedManifestRoutes = () => ({ - '/something': { - page: '/something', +const expectedManifestRoutes = () => [ + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/something.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/index.json$` ), + page: '/', }, - '/blog/[post]': { - page: '/blog/[post]', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog\\/([^/]+?)\\.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/another.json$` ), + page: '/another', }, - '/': { - page: '/', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/index.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog.json$` ), + page: '/blog', }, - '/default-revalidate': { - page: '/default-revalidate', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/default-revalidate.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog\\/([^\\/]+?)\\.json$` ), + page: '/blog/[post]', }, - '/catchall/[...path]': { - page: '/catchall/[...path]', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/catchall\\/(.+?)\\.json$` + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/blog\\/([^\\/]+?)\\/([^\\/]+?)\\.json$` ), + page: '/blog/[post]/[comment]', }, - '/blog': { - page: '/blog', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/catchall\\/(.+?)\\.json$` ), + page: '/catchall/[...path]', }, - '/blog/[post]/[comment]': { - page: '/blog/[post]/[comment]', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex( - buildId - )}\\/blog\\/([^/]+?)\\/([^/]+?)\\.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/default-revalidate.json$` ), + page: '/default-revalidate', }, - '/user/[user]/profile': { - page: '/user/[user]/profile', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex( - buildId - )}\\/user\\/([^/]+?)\\/profile\\.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/invalid-keys.json$` ), + page: '/invalid-keys', }, - '/another': { - page: '/another', + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/another.json$` + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/something.json$` ), + page: '/something', }, - '/invalid-keys': { + { dataRouteRegex: normalizeRegEx( - `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/invalid-keys.json$` + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/user\\/([^\\/]+?)\\/profile\\.json$` ), - page: '/invalid-keys', + page: '/user/[user]/profile', }, -}) +] const navigateTest = (dev = false) => { it('should navigate between pages successfully', async () => { @@ -208,7 +208,10 @@ const runTests = (dev = false) => { expect(JSON.parse(query)).toEqual({ path: ['first'] }) const data = JSON.parse( - await renderViaHTTP(appPort, `/_next/data/${buildId}/catchall/first.json`) + await renderViaHTTP( + appPort, + `/_next/data/${escapeRegex(buildId)}/catchall/first.json` + ) ) expect(data.pageProps.params).toEqual({ path: ['first'] }) @@ -216,7 +219,10 @@ const runTests = (dev = false) => { it('should return data correctly', async () => { const data = JSON.parse( - await renderViaHTTP(appPort, `/_next/data/${buildId}/something.json`) + await renderViaHTTP( + appPort, + `/_next/data/${escapeRegex(buildId)}/something.json` + ) ) expect(data.pageProps.world).toBe('world') }) @@ -225,7 +231,7 @@ const runTests = (dev = false) => { const data = JSON.parse( await renderViaHTTP( appPort, - `/_next/data/${buildId}/something.json?another=thing` + `/_next/data/${escapeRegex(buildId)}/something.json?another=thing` ) ) expect(data.pageProps.query.another).toBe('thing') @@ -233,7 +239,10 @@ const runTests = (dev = false) => { it('should return data correctly for dynamic page', async () => { const data = JSON.parse( - await renderViaHTTP(appPort, `/_next/data/${buildId}/blog/post-1.json`) + await renderViaHTTP( + appPort, + `/_next/data/${escapeRegex(buildId)}/blog/post-1.json` + ) ) expect(data.pageProps.post).toBe('post-1') }) @@ -341,15 +350,14 @@ const runTests = (dev = false) => { }) it('should output routes-manifest correctly', async () => { - const { serverPropsRoutes } = await fs.readJSON( + const { dataRoutes } = await fs.readJSON( join(appDir, '.next/routes-manifest.json') ) - for (const key of Object.keys(serverPropsRoutes)) { - const val = serverPropsRoutes[key].dataRouteRegex - serverPropsRoutes[key].dataRouteRegex = normalizeRegEx(val) + for (const route of dataRoutes) { + route.dataRouteRegex = normalizeRegEx(route.dataRouteRegex) } - expect(serverPropsRoutes).toEqual(expectedManifestRoutes()) + expect(dataRoutes).toEqual(expectedManifestRoutes()) }) it('should set no-cache, no-store, must-revalidate header', async () => { diff --git a/test/integration/prerender/test/index.test.js b/test/integration/prerender/test/index.test.js index 15cc1629d39d..d47e7b47f664 100644 --- a/test/integration/prerender/test/index.test.js +++ b/test/integration/prerender/test/index.test.js @@ -474,6 +474,83 @@ const runTests = (dev = false) => { expect(initialHtml).toMatch(/hello.*?world/) }) + it('outputs dataRoutes in routes-manifest correctly', async () => { + const { dataRoutes } = JSON.parse( + await fs.readFile(join(appDir, '.next/routes-manifest.json'), 'utf8') + ) + + for (const route of dataRoutes) { + route.dataRouteRegex = normalizeRegEx(route.dataRouteRegex) + } + + expect(dataRoutes).toEqual([ + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/index.json$` + ), + page: '/', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/another.json$` + ), + page: '/another', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog.json$` + ), + page: '/blog', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/blog\\/([^\\/]+?)\\.json$` + ), + page: '/blog/[post]', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/blog\\/([^\\/]+?)\\/([^\\/]+?)\\.json$` + ), + page: '/blog/[post]/[comment]', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/catchall\\/(.+?)\\.json$` + ), + page: '/catchall/[...slug]', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/default-revalidate.json$` + ), + page: '/default-revalidate', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/something.json$` + ), + page: '/something', + }, + { + dataRouteRegex: normalizeRegEx( + `^\\/_next\\/data\\/${escapeRegex( + buildId + )}\\/user\\/([^\\/]+?)\\/profile\\.json$` + ), + page: '/user/[user]/profile', + }, + ]) + }) + it('outputs a prerender-manifest correctly', async () => { const manifest = JSON.parse( await fs.readFile(join(appDir, '.next/prerender-manifest.json'), 'utf8')