Skip to content

Commit 7f89f68

Browse files
authored
Support for getStaticPaths.fallback = false (vercel/turborepo#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.
1 parent 8f5d41b commit 7f89f68

File tree

1 file changed

+46
-17
lines changed

1 file changed

+46
-17
lines changed

crates/next-core/js/src/internal/page-server-handler.tsx

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { IncomingMessage, ServerResponse } from "node:http";
1010
import { renderToHTML, RenderOpts } from "next/dist/server/render";
1111
import { getRedirectStatus } from "next/dist/lib/redirect-status";
1212
import { PERMANENT_REDIRECT_STATUS } from "next/dist/shared/lib/constants";
13+
import { buildStaticPaths } from "next/dist/build/utils";
1314
import type { BuildManifest } from "next/dist/server/get-page-files";
1415
import type { ReactLoadableManifest } from "next/dist/server/load-components";
1516

@@ -79,6 +80,30 @@ export default function startHandler({
7980
async function runOperation(
8081
renderData: RenderData
8182
): Promise<IpcOutgoingMessage> {
83+
if ("getStaticPaths" in otherExports) {
84+
const {
85+
paths: prerenderRoutes,
86+
fallback: prerenderFallback,
87+
encodedPaths: _encodedPrerenderRoutes,
88+
} = await buildStaticPaths({
89+
page: renderData.path,
90+
getStaticPaths: otherExports.getStaticPaths,
91+
// TODO(alexkirsz) Provide the correct next.config.js path.
92+
configFileName: "next.config.js",
93+
});
94+
95+
// We provide a dummy base URL to the URL constructor so that it doesn't
96+
// throw when we pass a relative URL.
97+
const resolvedPath = new URL(renderData.url, "next://").pathname;
98+
if (
99+
prerenderFallback === false &&
100+
// TODO(alexkirsz) Strip basePath.
101+
!prerenderRoutes.includes(resolvedPath)
102+
) {
103+
return createNotFoundResponse(isDataReq);
104+
}
105+
}
106+
82107
// TODO(alexkirsz) This is missing *a lot* of data, but it's enough to get a
83108
// basic render working.
84109

@@ -203,23 +228,7 @@ export default function startHandler({
203228
const isNotFound = (renderOpts as any).isNotFound;
204229

205230
if (isNotFound) {
206-
if (isDataReq) {
207-
return {
208-
type: "response",
209-
// Returning a 404 status code is required for the client-side router
210-
// to redirect to the error page.
211-
statusCode: 404,
212-
body: '{"notFound":true}',
213-
headers: [["Content-Type", MIME_APPLICATION_JAVASCRIPT]],
214-
};
215-
}
216-
217-
return {
218-
type: "rewrite",
219-
// _next/404 is a Turbopack-internal route that will always redirect to
220-
// the 404 page.
221-
path: "/_next/404",
222-
};
231+
return createNotFoundResponse(isDataReq);
223232
}
224233

225234
// Set when `getStaticProps` returns `redirect: { destination, permanent, statusCode }`.
@@ -290,6 +299,26 @@ export default function startHandler({
290299
}
291300
}
292301

302+
function createNotFoundResponse(isDataReq: boolean): IpcOutgoingMessage {
303+
if (isDataReq) {
304+
return {
305+
type: "response",
306+
// Returning a 404 status code is required for the client-side router
307+
// to redirect to the error page.
308+
statusCode: 404,
309+
body: '{"notFound":true}',
310+
headers: [["Content-Type", MIME_APPLICATION_JAVASCRIPT]],
311+
};
312+
}
313+
314+
return {
315+
type: "rewrite",
316+
// /_next/404 is a Turbopack-internal route that will always redirect to
317+
// the 404 page.
318+
path: "/_next/404",
319+
};
320+
}
321+
293322
type ManifestItem = {
294323
id: string;
295324
chunks: string[];

0 commit comments

Comments
 (0)