From cf2ed6f49b25cf2ed939b4d3364c8c587cf99d2f Mon Sep 17 00:00:00 2001 From: Alex Kirszenberg Date: Mon, 6 Feb 2023 09:56:55 +0100 Subject: [PATCH] Support for getStaticPaths.fallback = false (vercel/turbo#3600) Adds support for `getStaticPaths` returning `{ fallback: false }` by building out all static paths and checking whether the resolved path is included in that list. `buildStaticPaths` requires the `next.config.js` path, as well as other config options such as locale. I created WEB-546 to track being able to pass them to the handlers. --- .../js/src/internal/page-server-handler.tsx | 63 ++++++++++++++----- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/crates/next-core/js/src/internal/page-server-handler.tsx b/crates/next-core/js/src/internal/page-server-handler.tsx index bb5dc2b92c5be..25cd0afb478c2 100644 --- a/crates/next-core/js/src/internal/page-server-handler.tsx +++ b/crates/next-core/js/src/internal/page-server-handler.tsx @@ -10,6 +10,7 @@ import type { IncomingMessage, ServerResponse } from "node:http"; import { renderToHTML, RenderOpts } from "next/dist/server/render"; import { getRedirectStatus } from "next/dist/lib/redirect-status"; import { PERMANENT_REDIRECT_STATUS } from "next/dist/shared/lib/constants"; +import { buildStaticPaths } from "next/dist/build/utils"; import type { BuildManifest } from "next/dist/server/get-page-files"; import type { ReactLoadableManifest } from "next/dist/server/load-components"; @@ -79,6 +80,30 @@ export default function startHandler({ async function runOperation( renderData: RenderData ): Promise { + if ("getStaticPaths" in otherExports) { + const { + paths: prerenderRoutes, + fallback: prerenderFallback, + encodedPaths: _encodedPrerenderRoutes, + } = await buildStaticPaths({ + page: renderData.path, + getStaticPaths: otherExports.getStaticPaths, + // TODO(alexkirsz) Provide the correct next.config.js path. + configFileName: "next.config.js", + }); + + // We provide a dummy base URL to the URL constructor so that it doesn't + // throw when we pass a relative URL. + const resolvedPath = new URL(renderData.url, "next://").pathname; + if ( + prerenderFallback === false && + // TODO(alexkirsz) Strip basePath. + !prerenderRoutes.includes(resolvedPath) + ) { + return createNotFoundResponse(isDataReq); + } + } + // TODO(alexkirsz) This is missing *a lot* of data, but it's enough to get a // basic render working. @@ -203,23 +228,7 @@ export default function startHandler({ const isNotFound = (renderOpts as any).isNotFound; if (isNotFound) { - if (isDataReq) { - return { - type: "response", - // Returning a 404 status code is required for the client-side router - // to redirect to the error page. - statusCode: 404, - body: '{"notFound":true}', - headers: [["Content-Type", MIME_APPLICATION_JAVASCRIPT]], - }; - } - - return { - type: "rewrite", - // _next/404 is a Turbopack-internal route that will always redirect to - // the 404 page. - path: "/_next/404", - }; + return createNotFoundResponse(isDataReq); } // Set when `getStaticProps` returns `redirect: { destination, permanent, statusCode }`. @@ -290,6 +299,26 @@ export default function startHandler({ } } +function createNotFoundResponse(isDataReq: boolean): IpcOutgoingMessage { + if (isDataReq) { + return { + type: "response", + // Returning a 404 status code is required for the client-side router + // to redirect to the error page. + statusCode: 404, + body: '{"notFound":true}', + headers: [["Content-Type", MIME_APPLICATION_JAVASCRIPT]], + }; + } + + return { + type: "rewrite", + // /_next/404 is a Turbopack-internal route that will always redirect to + // the 404 page. + path: "/_next/404", + }; +} + type ManifestItem = { id: string; chunks: string[];