diff --git a/src/index.ts b/src/index.ts index fbd9ff5b..c4cae924 100644 --- a/src/index.ts +++ b/src/index.ts @@ -432,7 +432,8 @@ export const build = async ({ if (routesManifest) { switch (routesManifest.version) { case 1: - case 2: { + case 2: + case 3: { redirects.push(...convertRedirects(routesManifest.redirects)); rewrites.push(...convertRewrites(routesManifest.rewrites)); @@ -468,7 +469,14 @@ export const build = async ({ // make sure to route SSG data route to the data prerender // output, we don't do this for SSP routes since they don't // have a separate data output - (ssgDataRoute && ssgDataRoute.dataRoute) || dataRoute.page + (ssgDataRoute && ssgDataRoute.dataRoute) || dataRoute.page, + `${ + dataRoute.routeKeys + ? `?${Object.keys(dataRoute.routeKeys) + .map(key => `${dataRoute.routeKeys![key]}=$${key}`) + .join('&')}` + : '' + }` ), check: true, }); diff --git a/src/utils.ts b/src/utils.ts index f852ac28..8c2357f6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -312,9 +312,16 @@ export type RoutesManifest = { dynamicRoutes: { page: string; regex: string; + namedRegex?: string; + routeKeys?: { [named: string]: string }; }[]; version: number; - dataRoutes?: Array<{ page: string; dataRouteRegex: string }>; + dataRoutes?: Array<{ + page: string; + dataRouteRegex: string; + namedDataRouteRegex?: string; + routeKeys?: { [named: string]: string }; + }>; }; export async function getRoutesManifest( @@ -352,6 +359,20 @@ export async function getRoutesManifest( // eslint-disable-next-line @typescript-eslint/no-var-requires const routesManifest: RoutesManifest = require(pathRoutesManifest); + // massage temporary array based routeKeys from v1/v2 of routes + // manifest into new object based + for (const route of [ + ...(routesManifest.dataRoutes || []), + ...(routesManifest.dynamicRoutes || []), + ]) { + if (Array.isArray(route.routeKeys)) { + route.routeKeys = route.routeKeys.reduce((prev, cur) => { + prev[cur] = cur; + return prev; + }, {}); + } + } + return routesManifest; } @@ -383,6 +404,25 @@ export async function getDynamicRoutes( }; }); } + case 3: { + return routesManifest.dynamicRoutes + .filter(({ page }) => + omittedRoutes ? !omittedRoutes.has(page) : true + ) + .map(({ page, namedRegex, regex, routeKeys }) => { + return { + src: namedRegex || regex, + dest: `${!isDev ? path.join('/', entryDirectory, page) : page}${ + routeKeys + ? `?${Object.keys(routeKeys) + .map(key => `${routeKeys[key]}=$${key}`) + .join('&')}` + : '' + }`, + check: true, + }; + }); + } default: { // update MIN_ROUTES_MANIFEST_VERSION throw new NowBuildError({ diff --git a/test/fixtures/10-export-cache-headers/now.json b/test/fixtures/10-export-cache-headers/now.json index e538d411..147ddc07 100644 --- a/test/fixtures/10-export-cache-headers/now.json +++ b/test/fixtures/10-export-cache-headers/now.json @@ -3,7 +3,7 @@ "builds": [{ "src": "package.json", "use": "@vercel/next" }], "probes": [ { - "path": "/_next/static/testing-build-id/pages/index.js", + "path": "/_next/static/9dc4d2c93491d81eead3/pages/index.js", "responseHeaders": { "cache-control": "public,max-age=31536000,immutable" } diff --git a/test/fixtures/16-base-path/now.json b/test/fixtures/16-base-path/now.json index cc17ba7b..2dd0c284 100644 --- a/test/fixtures/16-base-path/now.json +++ b/test/fixtures/16-base-path/now.json @@ -3,7 +3,7 @@ "builds": [{ "src": "package.json", "use": "@vercel/next" }], "probes": [ { - "path": "/docs/_next/static/testing-build-id/pages/index.js", + "path": "/docs/_next/static/a7184ed7301386fd6825/pages/index.js", "responseHeaders": { "cache-control": "public,max-age=31536000,immutable" } diff --git a/test/fixtures/23-custom-routes-verbose/now.json b/test/fixtures/23-custom-routes-verbose/now.json index db142f4a..a0199f06 100644 --- a/test/fixtures/23-custom-routes-verbose/now.json +++ b/test/fixtures/23-custom-routes-verbose/now.json @@ -182,7 +182,7 @@ // should match /_next file after rewrite { - "path": "/hidden/_next/static/testing-build-id/pages/hello.js", + "path": "/hidden/_next/static/b09092d6eebe375caba5/pages/hello.js", "mustContain": "createElement" }, @@ -245,6 +245,13 @@ "path": "/hello/post-123.html", "status": 200, "mustContain": "123" + }, + + // should rewrite to catch-all with dash in segment name + { + "path": "/catchall-dash/hello/world", + "status": 200, + "mustContain": "hello/world" } ] } diff --git a/test/fixtures/23-custom-routes-verbose/pages/catchall-dash/[...hello-world].js b/test/fixtures/23-custom-routes-verbose/pages/catchall-dash/[...hello-world].js new file mode 100644 index 00000000..4eabb143 --- /dev/null +++ b/test/fixtures/23-custom-routes-verbose/pages/catchall-dash/[...hello-world].js @@ -0,0 +1,17 @@ +import { useRouter } from 'next/router' + +const Page = () => { + return ( +

path: {useRouter().query['hello-world']?.join('/')}

+ ) +} + +export default Page + +export const getServerSideProps = () => { + return { + props: { + hello: 'world' + } + } +} diff --git a/test/fixtures/23-custom-routes-verbose/pages/dash/[hello-world].js b/test/fixtures/23-custom-routes-verbose/pages/dash/[hello-world].js new file mode 100644 index 00000000..0957a987 --- /dev/null +++ b/test/fixtures/23-custom-routes-verbose/pages/dash/[hello-world].js @@ -0,0 +1 @@ +export default () => 'hi'