diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index c8385cfa4d818ee..b6049f2bc96a57e 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -6,6 +6,7 @@ import { API_ROUTE, DOT_NEXT_ALIAS, PAGES_DIR_ALIAS } from '../lib/constants' import { isTargetLikeServerless } from '../next-server/server/config' import { warn } from './output/log' import { ServerlessLoaderQuery } from './webpack/loaders/next-serverless-loader' +import { normalizePagePath } from '../next-server/server/normalize-page-path' type PagesMapping = { [page: string]: string @@ -91,7 +92,7 @@ export function createEntrypoints( Object.keys(pages).forEach(page => { const absolutePagePath = pages[page] - const bundleFile = page === '/' ? '/index.js' : `${page}.js` + const bundleFile = `${normalizePagePath(page)}.js` const isApiRoute = page.match(API_ROUTE) const bundlePath = join('static', buildId, 'pages', bundleFile) diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 4d4307882bf0c25..22e0d4d1ba2cc3b 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -67,6 +67,7 @@ import { } from './utils' import getBaseWebpackConfig from './webpack-config' import { writeBuildId } from './write-build-id' +import { normalizePagePath } from '../next-server/server/normalize-page-path' const fsAccess = promisify(fs.access) const fsUnlink = promisify(fs.unlink) @@ -435,7 +436,7 @@ export default async function build(dir: string, conf = null): Promise { const analysisBegin = process.hrtime() await Promise.all( pageKeys.map(async page => { - const actualPage = page === '/' ? '/index' : page + const actualPage = normalizePagePath(page) const [selfSize, allSize] = await getPageSizeInKb( actualPage, distDir, @@ -554,10 +555,11 @@ export default async function build(dir: string, conf = null): Promise { routesManifest.serverPropsRoutes = {} for (const page of serverPropsPages) { + const pagePath = normalizePagePath(page) const dataRoute = path.posix.join( '/_next/data', buildId, - `${page === '/' ? '/index' : page}.json` + `${pagePath}.json` ) routesManifest.serverPropsRoutes[page] = { @@ -571,7 +573,7 @@ export default async function build(dir: string, conf = null): Promise { `^${path.posix.join( '/_next/data', escapeStringRegexp(buildId), - `${page === '/' ? '/index' : page}.json` + `${pagePath}.json` )}$` ).source, } @@ -709,7 +711,7 @@ export default async function build(dir: string, conf = null): Promise { for (const page of combinedPages) { const isSsg = ssgPages.has(page) const isDynamic = isDynamicRoute(page) - let file = page === '/' ? '/index' : page + const file = normalizePagePath(page) // The dynamic version of SSG pages are not prerendered. Below, we handle // the specific prerenders of these. if (!(isSsg && isDynamic)) { @@ -729,11 +731,7 @@ export default async function build(dir: string, conf = null): Promise { initialRevalidateSeconds: exportConfig.initialPageRevalidationMap[page], srcRoute: null, - dataRoute: path.posix.join( - '/_next/data', - buildId, - `${page === '/' ? '/index' : page}.json` - ), + dataRoute: path.posix.join('/_next/data', buildId, `${file}.json`), } } else { // For a dynamic SSG page, we did not copy its html nor data exports. @@ -750,7 +748,7 @@ export default async function build(dir: string, conf = null): Promise { dataRoute: path.posix.join( '/_next/data', buildId, - `${route === '/' ? '/index' : route}.json` + `${normalizePagePath(route)}.json` ), } } @@ -783,7 +781,7 @@ export default async function build(dir: string, conf = null): Promise { const dataRoute = path.posix.join( '/_next/data', buildId, - `${tbdRoute === '/' ? '/index' : tbdRoute}.json` + `${normalizePagePath(tbdRoute)}.json` ) finalDynamicRoutes[tbdRoute] = { diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 40f0c33ca68852a..386928105af9922 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -33,6 +33,7 @@ import loadConfig, { } from '../next-server/server/config' import { eventVersion } from '../telemetry/events' import { Telemetry } from '../telemetry/storage' +import { normalizePagePath } from '../next-server/server/normalize-page-path' const mkdirp = promisify(mkdirpModule) const copyFile = promisify(copyFileOrig) @@ -352,7 +353,7 @@ export default async function( if (!options.buildExport && prerenderManifest) { await Promise.all( Object.keys(prerenderManifest.routes).map(async route => { - route = route === '/' ? '/index' : route + route = normalizePagePath(route) const orig = join(distPagesDir, route) const htmlDest = join( outDir, diff --git a/packages/next/export/worker.js b/packages/next/export/worker.js index 61a2a88e2517d6e..2ca8fb688cb2337 100644 --- a/packages/next/export/worker.js +++ b/packages/next/export/worker.js @@ -9,6 +9,7 @@ import { loadComponents } from '../next-server/server/load-components' import { isDynamicRoute } from '../next-server/lib/router/utils/is-dynamic' import { getRouteMatcher } from '../next-server/lib/router/utils/route-matcher' import { getRouteRegex } from '../next-server/lib/router/utils/route-regex' +import { normalizePagePath } from '../next-server/server/normalize-page-path' const envConfig = require('../next-server/lib/runtime-config') const writeFileP = promisify(writeFile) @@ -39,7 +40,7 @@ export default async function({ try { const { query: originalQuery = {} } = pathMap const { page } = pathMap - const filePath = path === '/' ? '/index' : path + const filePath = normalizePagePath(path) const ampPath = `${filePath}.amp` let query = { ...originalQuery } let params diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index c817e6890e65ca3..a1b3a75bdce2e08 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -52,6 +52,7 @@ import { Header, getRedirectStatus, } from '../../lib/check-custom-routes' +import { normalizePagePath } from './normalize-page-path' const getCustomRouteMatcher = pathMatch(true) @@ -815,7 +816,7 @@ export default class Server { return await loadComponents( this.distDir, this.buildId, - (pathname === '/' ? '/index' : pathname) + '.amp', + normalizePagePath(pathname) + '.amp', serverless ) } catch (err) { diff --git a/packages/next/next-server/server/normalize-page-path.ts b/packages/next/next-server/server/normalize-page-path.ts index 1102a4ec91aa8a9..13728d1d326dce2 100644 --- a/packages/next/next-server/server/normalize-page-path.ts +++ b/packages/next/next-server/server/normalize-page-path.ts @@ -11,7 +11,9 @@ export function normalizePagePath(page: string): string { // Throw when using ../ etc in the pathname const resolvedPage = posix.normalize(page) if (page !== resolvedPage) { - throw new Error('Requested and resolved page mismatch') + throw new Error( + `Requested and resolved page mismatch: ${page} ${resolvedPage}` + ) } return page } diff --git a/packages/next/next-server/server/require.ts b/packages/next/next-server/server/require.ts index c846fedf5be52ec..bd2251cc4c0c7eb 100644 --- a/packages/next/next-server/server/require.ts +++ b/packages/next/next-server/server/require.ts @@ -30,7 +30,6 @@ export function getPagePath( try { page = normalizePagePath(page) - page = page === '/' ? '/index' : page } catch (err) { // tslint:disable-next-line console.error(err) diff --git a/packages/next/next-server/server/spr-cache.ts b/packages/next/next-server/server/spr-cache.ts index 4e7a9c1f9858c7d..0de1a419e6049b8 100644 --- a/packages/next/next-server/server/spr-cache.ts +++ b/packages/next/next-server/server/spr-cache.ts @@ -146,12 +146,12 @@ export async function setSprCache( ) { if (sprOptions.dev) return if (typeof revalidateSeconds !== 'undefined') { - // TODO: This is really bad. We shouldn't be mutating the manifest from the + // TODO: Update this to not mutate the manifest from the // build. prerenderManifest.routes[pathname] = { dataRoute: path.posix.join( '/_next/data', - `${pathname === '/' ? '/index' : pathname}.json` + `${normalizePagePath(pathname)}.json` ), srcRoute: null, // FIXME: provide actual source route, however, when dynamically appending it doesn't really matter initialRevalidateSeconds: revalidateSeconds, diff --git a/packages/next/server/on-demand-entry-handler.ts b/packages/next/server/on-demand-entry-handler.ts index fc10177df54e40f..550fd09adb3f26a 100644 --- a/packages/next/server/on-demand-entry-handler.ts +++ b/packages/next/server/on-demand-entry-handler.ts @@ -285,11 +285,15 @@ export default function onDemandEntryHandler( throw pageNotFoundError(normalizedPagePath) } - let pageUrl = `/${pagePath + let pageUrl = pagePath.replace(/\\/g, '/') + + pageUrl = `${pageUrl[0] !== '/' ? '/' : ''}${pageUrl .replace(new RegExp(`\\.+(?:${pageExtensions.join('|')})$`), '') - .replace(/\\/g, '/')}`.replace(/\/index$/, '') + .replace(/\/index$/, '')}` + pageUrl = pageUrl === '' ? '/' : pageUrl - const bundleFile = pageUrl === '/' ? '/index.js' : `${pageUrl}.js` + + const bundleFile = `${normalizePagePath(pageUrl)}.js` const name = join('static', buildId, 'pages', bundleFile) const absolutePagePath = pagePath.startsWith('next/dist/pages') ? require.resolve(pagePath)