vinext 1.0.0-beta.2 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -9
- package/dist/build/client-build-config.js +7 -1
- package/dist/check.js +4 -0
- package/dist/config/config-matchers.js +4 -1
- package/dist/config/next-config.d.ts +12 -3
- package/dist/config/next-config.js +4 -0
- package/dist/entries/app-browser-entry.d.ts +4 -10
- package/dist/entries/app-browser-entry.js +20 -4
- package/dist/entries/app-rsc-entry.js +3 -0
- package/dist/entries/app-rsc-manifest.js +19 -0
- package/dist/entries/pages-client-entry.js +0 -1
- package/dist/entries/pages-server-entry.js +10 -3
- package/dist/index.js +112 -43
- package/dist/init-cloudflare.d.ts +3 -1
- package/dist/init-cloudflare.js +59 -5
- package/dist/plugins/extensionless-dynamic-import.js +23 -18
- package/dist/plugins/ignore-dynamic-requests.js +3 -1
- package/dist/plugins/import-meta-url.js +17 -6
- package/dist/plugins/require-context.js +20 -15
- package/dist/plugins/transform-cache.d.ts +19 -0
- package/dist/plugins/transform-cache.js +36 -0
- package/dist/routing/app-route-graph.d.ts +14 -6
- package/dist/routing/app-route-graph.js +106 -16
- package/dist/server/api-handler.d.ts +2 -0
- package/dist/server/api-handler.js +3 -3
- package/dist/server/app-browser-entry.js +103 -31
- package/dist/server/app-browser-navigation-controller.d.ts +23 -21
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-page-cache-finalizer.js +1 -1
- package/dist/server/app-page-cache.d.ts +1 -1
- package/dist/server/app-page-cache.js +16 -2
- package/dist/server/app-page-dispatch.d.ts +8 -0
- package/dist/server/app-page-dispatch.js +31 -6
- package/dist/server/app-page-element-builder.d.ts +2 -0
- package/dist/server/app-page-element-builder.js +33 -7
- package/dist/server/app-page-head.d.ts +3 -3
- package/dist/server/app-page-head.js +58 -13
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +2 -2
- package/dist/server/app-page-http-access-fallback-metadata.js +9 -1
- package/dist/server/app-page-probe.d.ts +4 -0
- package/dist/server/app-page-probe.js +6 -2
- package/dist/server/app-page-request.d.ts +3 -0
- package/dist/server/app-page-request.js +1 -1
- package/dist/server/app-page-response.js +1 -1
- package/dist/server/app-page-route-wiring.d.ts +7 -0
- package/dist/server/app-page-route-wiring.js +211 -49
- package/dist/server/app-pages-bridge.d.ts +1 -1
- package/dist/server/app-pages-bridge.js +2 -1
- package/dist/server/app-route-handler-cache.js +4 -0
- package/dist/server/app-route-handler-dispatch.js +9 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-module-loader.d.ts +6 -0
- package/dist/server/app-route-module-loader.js +3 -0
- package/dist/server/app-router-entry.js +6 -3
- package/dist/server/app-rsc-errors.js +10 -0
- package/dist/server/app-rsc-handler.js +21 -9
- package/dist/server/app-rsc-route-matching.d.ts +9 -0
- package/dist/server/app-rsc-route-matching.js +6 -0
- package/dist/server/app-ssr-entry.js +4 -4
- package/dist/server/cache-control.d.ts +2 -2
- package/dist/server/cache-control.js +2 -1
- package/dist/server/dev-server.d.ts +3 -1
- package/dist/server/dev-server.js +145 -312
- package/dist/server/headers.d.ts +2 -2
- package/dist/server/headers.js +4 -3
- package/dist/server/isr-cache.d.ts +10 -33
- package/dist/server/isr-cache.js +33 -43
- package/dist/server/isr-decision.d.ts +2 -2
- package/dist/server/pages-api-route.d.ts +2 -0
- package/dist/server/pages-api-route.js +4 -1
- package/dist/server/pages-dev-hydration.js +0 -1
- package/dist/server/pages-get-initial-props.d.ts +1 -1
- package/dist/server/pages-get-initial-props.js +1 -4
- package/dist/server/pages-i18n.js +64 -16
- package/dist/server/pages-node-compat.d.ts +2 -0
- package/dist/server/pages-node-compat.js +7 -3
- package/dist/server/pages-page-data.d.ts +61 -9
- package/dist/server/pages-page-data.js +334 -74
- package/dist/server/pages-page-handler.d.ts +5 -1
- package/dist/server/pages-page-handler.js +115 -19
- package/dist/server/pages-page-response.d.ts +5 -3
- package/dist/server/pages-page-response.js +23 -26
- package/dist/server/pages-request-pipeline.d.ts +7 -0
- package/dist/server/pages-request-pipeline.js +5 -1
- package/dist/server/pages-revalidate.d.ts +1 -1
- package/dist/server/pages-revalidate.js +54 -8
- package/dist/server/pages-router-entry.d.ts +1 -0
- package/dist/server/pages-router-entry.js +10 -4
- package/dist/server/prod-server.d.ts +2 -1
- package/dist/server/prod-server.js +37 -13
- package/dist/server/revalidation-host.d.ts +11 -0
- package/dist/server/revalidation-host.js +19 -0
- package/dist/server/worker-revalidation-context.d.ts +13 -0
- package/dist/server/worker-revalidation-context.js +29 -0
- package/dist/shims/cache-handler.d.ts +1 -1
- package/dist/shims/cache-handler.js +10 -7
- package/dist/shims/cache-runtime.d.ts +6 -0
- package/dist/shims/cache-runtime.js +4 -1
- package/dist/shims/cache.js +1 -1
- package/dist/shims/error.js +1 -1
- package/dist/shims/fetch-cache.js +1 -1
- package/dist/shims/font-google-base.js +17 -8
- package/dist/shims/font-local.js +41 -10
- package/dist/shims/headers.d.ts +10 -13
- package/dist/shims/headers.js +85 -36
- package/dist/shims/internal/cookie-serialize.d.ts +10 -9
- package/dist/shims/internal/cookie-serialize.js +9 -8
- package/dist/shims/internal/interpolate-as.d.ts +15 -1
- package/dist/shims/internal/interpolate-as.js +27 -2
- package/dist/shims/link.js +18 -6
- package/dist/shims/metadata.d.ts +7 -17
- package/dist/shims/metadata.js +74 -24
- package/dist/shims/navigation.js +1 -1
- package/dist/shims/request-context.d.ts +4 -1
- package/dist/shims/router.js +18 -7
- package/dist/shims/script.js +1 -1
- package/dist/shims/server.d.ts +7 -6
- package/dist/shims/server.js +156 -57
- package/dist/shims/unified-request-context.d.ts +21 -2
- package/dist/shims/unified-request-context.js +82 -1
- package/dist/utils/cache-control-metadata.d.ts +2 -1
- package/dist/utils/cache-control-metadata.js +5 -1
- package/dist/utils/html-limited-bots.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/package.json +1 -1
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
import { createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
1
|
+
import { closeAfterResponse, createRequestContext, runWithRequestContext } from "../shims/unified-request-context.js";
|
|
2
2
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
3
3
|
import { createValidFileMatcher, findFileWithExtensions, findFileWithExts } from "../routing/file-matcher.js";
|
|
4
4
|
import { patternToNextFormat } from "../routing/route-validation.js";
|
|
5
5
|
import { matchRoute } from "../routing/pages-router.js";
|
|
6
|
-
import {
|
|
6
|
+
import { PRERENDER_REVALIDATE_HEADER } from "../utils/protocol-headers.js";
|
|
7
|
+
import { NEXTJS_CACHE_HEADER, NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
|
|
7
8
|
import { isDangerousScheme } from "../shims/url-safety.js";
|
|
9
|
+
import { sanitizeDestination } from "../config/config-matchers.js";
|
|
8
10
|
import { importModule, reportRequestError } from "./instrumentation.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { PRERENDER_REVALIDATE_HEADER, buildPagesCacheValue, getRevalidateDuration, isOnDemandRevalidateRequest, isrCacheKey, isrGet, isrSet, setRevalidateDuration, triggerBackgroundRegeneration } from "./isr-cache.js";
|
|
14
|
-
import { _runWithCacheState } from "../shims/cache-request-state.js";
|
|
15
|
-
import { ensureFetchPatch, runWithFetchCache } from "../shims/fetch-cache.js";
|
|
16
|
-
import { runWithPrivateCache } from "../shims/cache-runtime.js";
|
|
11
|
+
import { NEVER_CACHE_CONTROL } from "./cache-control.js";
|
|
12
|
+
import { buildMissIsrCacheControl } from "./isr-decision.js";
|
|
13
|
+
import { isOnDemandRevalidateRequest } from "./isr-cache.js";
|
|
14
|
+
import { ensureFetchPatch } from "../shims/fetch-cache.js";
|
|
17
15
|
import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
|
|
18
16
|
import "../shims/router-state.js";
|
|
19
|
-
import { runWithHeadState } from "../shims/head-state.js";
|
|
20
|
-
import { runWithServerInsertedHTMLState } from "../shims/navigation-state.js";
|
|
21
17
|
import { withScriptNonce } from "../shims/script-nonce-context.js";
|
|
22
18
|
import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr, safeJsonStringify } from "./html.js";
|
|
23
19
|
import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
|
|
@@ -29,10 +25,10 @@ import { buildPagesReadinessNextData } from "./pages-readiness.js";
|
|
|
29
25
|
import { resolvePagesPageMethodResponse } from "./pages-page-method.js";
|
|
30
26
|
import { loadUserDocumentInitialProps, runDocumentRenderPage } from "./pages-document-initial-props.js";
|
|
31
27
|
import { callDocumentGetInitialProps } from "./document-initial-head.js";
|
|
28
|
+
import { isBotUserAgent } from "../utils/html-limited-bots.js";
|
|
32
29
|
import { hasPagesGetInitialProps, loadDevAppInitialProps, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
|
|
33
30
|
import { isSerializableProps } from "./pages-serializable-props.js";
|
|
34
|
-
import {
|
|
35
|
-
import { getPagesRouteParams, matchesPagesStaticPath } from "./pages-page-data.js";
|
|
31
|
+
import { assertPages404DoesNotReturnNotFound, buildPagesRedirectProps, getPagesRouteParams, matchesPagesStaticPath, mergePagesDataProps, resolvePagesRedirect, resolvePagesRedirectLocation, resolvePagesRevalidateSeconds } from "./pages-page-data.js";
|
|
36
32
|
import { createPagesDevAssetUrl, createPagesDevModuleUrl } from "./pages-dev-module-url.js";
|
|
37
33
|
import { createPagesDevHydrationScript } from "./pages-dev-hydration.js";
|
|
38
34
|
import { getManifestFilesForModule } from "./pages-asset-tags.js";
|
|
@@ -78,8 +74,15 @@ function applyDevPagesPreviewResponse(res, preview) {
|
|
|
78
74
|
applyDevPagesPreviewHeaders(headers, preview);
|
|
79
75
|
for (const [name, value] of Object.entries(headers)) res.setHeader(name, value);
|
|
80
76
|
}
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
const DEV_PAGES_CACHE_CONTROL = "no-cache, must-revalidate";
|
|
78
|
+
const PAGES_CACHE_ONE_YEAR_SECONDS = 31536e3;
|
|
79
|
+
function applyDevPagesCacheHeaders(res, state, cacheControl = DEV_PAGES_CACHE_CONTROL) {
|
|
80
|
+
res.setHeader(NEXTJS_CACHE_HEADER, state);
|
|
81
|
+
res.setHeader("Cache-Control", cacheControl);
|
|
82
|
+
}
|
|
83
|
+
function buildDevPagesTerminalCacheControl(revalidateSeconds, expireSeconds) {
|
|
84
|
+
if (revalidateSeconds === false) return `s-maxage=${PAGES_CACHE_ONE_YEAR_SECONDS}`;
|
|
85
|
+
return buildMissIsrCacheControl(revalidateSeconds, expireSeconds);
|
|
83
86
|
}
|
|
84
87
|
const DEV_STYLESHEET_ASSET_RE = /\.(?:css|scss|sass)$/i;
|
|
85
88
|
const transformedStylesheetAssetsCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -172,11 +175,17 @@ async function collectDevInitialStylesheetHeadHTML(server, runner, moduleIds, no
|
|
|
172
175
|
* (`buildPagesRedirectResponse`) and Next.js's `render.tsx` `__N_REDIRECT`
|
|
173
176
|
* handling. See AGENTS.md "dev and prod server parity".
|
|
174
177
|
*/
|
|
175
|
-
function writeGsspRedirect(res, redirect, isDataReq, props) {
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
function writeGsspRedirect(res, redirect, isDataReq, props, options) {
|
|
179
|
+
const resolved = resolvePagesRedirect(redirect, {
|
|
180
|
+
method: options.method,
|
|
181
|
+
routeUrl: options.routeUrl,
|
|
182
|
+
sanitizeDestination
|
|
183
|
+
});
|
|
184
|
+
const redirectProps = buildPagesRedirectProps(resolved, {
|
|
185
|
+
...props,
|
|
186
|
+
pageProps: props.pageProps
|
|
187
|
+
});
|
|
188
|
+
if (isDangerousScheme(resolved.destination)) {
|
|
180
189
|
const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
|
|
181
190
|
const headers = {
|
|
182
191
|
"Cache-Control": "private, no-cache, no-store, max-age=0, must-revalidate",
|
|
@@ -192,18 +201,15 @@ function writeGsspRedirect(res, redirect, isDataReq, props) {
|
|
|
192
201
|
const dataHeaders = { "Content-Type": "application/json" };
|
|
193
202
|
if (deploymentId) dataHeaders[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
194
203
|
res.writeHead(200, dataHeaders);
|
|
195
|
-
res.end(JSON.stringify({
|
|
196
|
-
...props,
|
|
197
|
-
pageProps: {
|
|
198
|
-
...isUnknownRecord(props.pageProps) ? props.pageProps : {},
|
|
199
|
-
__N_REDIRECT: dest,
|
|
200
|
-
__N_REDIRECT_STATUS: status
|
|
201
|
-
}
|
|
202
|
-
}));
|
|
204
|
+
res.end(JSON.stringify({ ...redirectProps }));
|
|
203
205
|
return;
|
|
204
206
|
}
|
|
205
|
-
|
|
206
|
-
res.
|
|
207
|
+
const location = resolvePagesRedirectLocation(resolved, options.basePath);
|
|
208
|
+
res.writeHead(resolved.statusCode, {
|
|
209
|
+
Location: location,
|
|
210
|
+
...resolved.statusCode === 308 ? { Refresh: `0;url=${location}` } : {}
|
|
211
|
+
});
|
|
212
|
+
res.end(location);
|
|
207
213
|
}
|
|
208
214
|
/** Body placeholder used to split the document shell for streaming. */
|
|
209
215
|
const STREAM_BODY_MARKER = "<!--VINEXT_STREAM_BODY-->";
|
|
@@ -324,7 +330,7 @@ function parseCookieLocale(req, i18nConfig) {
|
|
|
324
330
|
* 4. Render the component to HTML
|
|
325
331
|
* 5. Wrap in _document shell and send response
|
|
326
332
|
*/
|
|
327
|
-
function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatcher, basePath = "", trailingSlash = false, hasMiddleware = false, hasRewrites = false, clientTraceMetadata, htmlLimitedBots, reactStrictMode = false) {
|
|
333
|
+
function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatcher, basePath = "", trailingSlash = false, hasMiddleware = false, hasRewrites = false, clientTraceMetadata, htmlLimitedBots, reactStrictMode = false, expireTime = PAGES_CACHE_ONE_YEAR_SECONDS) {
|
|
328
334
|
const matcher = fileMatcher ?? createValidFileMatcher();
|
|
329
335
|
const pagePatterns = routes.map((r) => patternToNextFormat(r.pattern));
|
|
330
336
|
const _alsRegistration = Promise.all([runner.import("vinext/head-state"), runner.import("vinext/router-state")]);
|
|
@@ -350,22 +356,24 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
350
356
|
let locale;
|
|
351
357
|
let localeStrippedUrl = url;
|
|
352
358
|
let currentDefaultLocale;
|
|
353
|
-
let currentDomainLocaleDomain;
|
|
354
359
|
const domainLocales = i18nConfig?.domains;
|
|
355
360
|
if (i18nConfig) {
|
|
356
361
|
const resolved = resolvePagesI18nRequest(url, i18nConfig, req.headers, req.headers.host, basePath, trailingSlash);
|
|
357
362
|
locale = resolved.locale;
|
|
358
363
|
localeStrippedUrl = resolved.url;
|
|
359
364
|
currentDefaultLocale = resolved.domainLocale?.defaultLocale ?? i18nConfig.defaultLocale;
|
|
360
|
-
currentDomainLocaleDomain = resolved.domainLocale?.domain;
|
|
361
365
|
if (resolved.redirectUrl) {
|
|
362
366
|
res.writeHead(307, { Location: resolved.redirectUrl });
|
|
363
367
|
res.end();
|
|
364
368
|
return;
|
|
365
369
|
}
|
|
366
370
|
}
|
|
367
|
-
const
|
|
368
|
-
|
|
371
|
+
const errorPageContext = {
|
|
372
|
+
basePath,
|
|
373
|
+
locale: locale ?? currentDefaultLocale,
|
|
374
|
+
locales: i18nConfig?.locales,
|
|
375
|
+
defaultLocale: currentDefaultLocale
|
|
376
|
+
};
|
|
369
377
|
const match = matchRoute(localeStrippedUrl, routes);
|
|
370
378
|
if (!match) {
|
|
371
379
|
if (isDataReq) {
|
|
@@ -377,9 +385,13 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
377
385
|
res.end("{}");
|
|
378
386
|
return;
|
|
379
387
|
}
|
|
380
|
-
|
|
388
|
+
const requestContext = createRequestContext();
|
|
389
|
+
const closeRequest = () => void closeAfterResponse(requestContext);
|
|
390
|
+
res.on("finish", closeRequest);
|
|
391
|
+
res.on("close", closeRequest);
|
|
392
|
+
await runWithRequestContext(requestContext, async () => {
|
|
381
393
|
await _alsRegistration;
|
|
382
|
-
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, void 0, matcher, void 0, reactStrictMode);
|
|
394
|
+
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, void 0, matcher, void 0, reactStrictMode, errorPageContext);
|
|
383
395
|
});
|
|
384
396
|
return;
|
|
385
397
|
}
|
|
@@ -391,7 +403,11 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
391
403
|
let requestAsPath = isDataReq ? gsspResolvedUrl : i18nConfig ? extractLocaleFromUrl$1(originalUrl, i18nConfig, locale).url : originalUrl;
|
|
392
404
|
const userFacingParams = route.isDynamic ? params : null;
|
|
393
405
|
let query = mergeRouteParamsIntoQuery(parseQueryString(url), params);
|
|
394
|
-
|
|
406
|
+
const requestContext = createRequestContext();
|
|
407
|
+
const closeRequest = () => void closeAfterResponse(requestContext);
|
|
408
|
+
res.on("finish", closeRequest);
|
|
409
|
+
res.on("close", closeRequest);
|
|
410
|
+
return runWithRequestContext(requestContext, async () => {
|
|
395
411
|
ensureFetchPatch();
|
|
396
412
|
try {
|
|
397
413
|
await _alsRegistration;
|
|
@@ -472,10 +488,9 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
472
488
|
let pageProps = {};
|
|
473
489
|
let renderProps = { pageProps };
|
|
474
490
|
if (requestPreviewData !== false) renderProps.__N_PREVIEW = true;
|
|
475
|
-
let
|
|
491
|
+
let isOnDemandRevalidate = false;
|
|
492
|
+
let staticPropsRevalidateSeconds = false;
|
|
476
493
|
let isFallbackRender = false;
|
|
477
|
-
let shouldPersistFallbackData = false;
|
|
478
|
-
let staticPropsPreviewData = requestPreviewData;
|
|
479
494
|
if (typeof pageModule.getStaticPaths === "function" && route.isDynamic) {
|
|
480
495
|
const pathsResult = await pageModule.getStaticPaths({
|
|
481
496
|
locales: i18nConfig?.locales ?? [],
|
|
@@ -491,17 +506,17 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
491
506
|
const notFoundHeaders = { "Content-Type": "application/json" };
|
|
492
507
|
if (deploymentId) notFoundHeaders[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
493
508
|
res.writeHead(404, notFoundHeaders);
|
|
494
|
-
res.end("{}");
|
|
509
|
+
res.end("{\"notFound\":true}");
|
|
495
510
|
return;
|
|
496
511
|
}
|
|
497
|
-
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, matcher, void 0, reactStrictMode);
|
|
512
|
+
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, matcher, void 0, reactStrictMode, errorPageContext);
|
|
498
513
|
return;
|
|
499
514
|
}
|
|
500
515
|
const userAgentHeader = req.headers["user-agent"];
|
|
501
516
|
const userAgent = Array.isArray(userAgentHeader) ? userAgentHeader[0] : userAgentHeader;
|
|
502
517
|
const isBotRequest = !!userAgent && isBotUserAgent(userAgent, htmlLimitedBots);
|
|
503
518
|
if (fallback === true && !isValidPath && !isDataReq && !isBotRequest && requestPreviewData === false) {
|
|
504
|
-
isFallbackRender =
|
|
519
|
+
isFallbackRender = true;
|
|
505
520
|
if (isFallbackRender && typeof routerShim.setSSRContext === "function") routerShim.setSSRContext({
|
|
506
521
|
pathname: patternToNextFormat(route.pattern),
|
|
507
522
|
query: {},
|
|
@@ -514,7 +529,6 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
514
529
|
isFallback: true
|
|
515
530
|
});
|
|
516
531
|
}
|
|
517
|
-
shouldPersistFallbackData = fallback === true && !isValidPath && isDataReq;
|
|
518
532
|
}
|
|
519
533
|
const gsspExtraHeaders = {};
|
|
520
534
|
const hasAppGetInitialProps = hasPagesGetInitialProps(AppComponent);
|
|
@@ -526,7 +540,6 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
526
540
|
const appTree = React.createElement(AppComponent, {
|
|
527
541
|
...appTreeProps,
|
|
528
542
|
Component: PageComponent,
|
|
529
|
-
pageProps: appTreeProps.pageProps,
|
|
530
543
|
router: routerShim.default
|
|
531
544
|
});
|
|
532
545
|
return typeof routerShim.wrapWithRouterContext === "function" ? routerShim.wrapWithRouterContext(appTree) : appTree;
|
|
@@ -577,17 +590,18 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
577
590
|
const result = await pageModule.getServerSideProps(context);
|
|
578
591
|
if (res.writableEnded) return;
|
|
579
592
|
if (result && "props" in result) {
|
|
580
|
-
pageProps =
|
|
581
|
-
...pageProps,
|
|
582
|
-
...await Promise.resolve(result.props)
|
|
583
|
-
};
|
|
593
|
+
pageProps = mergePagesDataProps(renderProps.pageProps, await Promise.resolve(result.props));
|
|
584
594
|
renderProps = {
|
|
585
595
|
...renderProps,
|
|
586
596
|
pageProps
|
|
587
597
|
};
|
|
588
598
|
}
|
|
589
599
|
if (result && "redirect" in result) {
|
|
590
|
-
writeGsspRedirect(res, result.redirect, isDataReq, renderProps
|
|
600
|
+
writeGsspRedirect(res, result.redirect, isDataReq, renderProps, {
|
|
601
|
+
basePath,
|
|
602
|
+
method: "getServerSideProps",
|
|
603
|
+
routeUrl: url
|
|
604
|
+
});
|
|
591
605
|
return;
|
|
592
606
|
}
|
|
593
607
|
if (result && "notFound" in result && result.notFound) {
|
|
@@ -597,10 +611,10 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
597
611
|
const notFoundHeaders = { "Content-Type": "application/json" };
|
|
598
612
|
if (deploymentId) notFoundHeaders[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
599
613
|
res.writeHead(404, notFoundHeaders);
|
|
600
|
-
res.end("{}");
|
|
614
|
+
res.end("{\"notFound\":true}");
|
|
601
615
|
return;
|
|
602
616
|
}
|
|
603
|
-
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, void 0, void 0, reactStrictMode);
|
|
617
|
+
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, void 0, void 0, reactStrictMode, errorPageContext);
|
|
604
618
|
return;
|
|
605
619
|
}
|
|
606
620
|
if (result && "props" in result) isSerializableProps(patternToNextFormat(route.pattern), "getServerSideProps", pageProps);
|
|
@@ -616,216 +630,19 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
616
630
|
}
|
|
617
631
|
const responseHeaders = typeof res.getHeaders === "function" ? res.getHeaders() : void 0;
|
|
618
632
|
const scriptNonce = getScriptNonceFromNodeHeaderSources(req.headers, responseHeaders);
|
|
619
|
-
let earlyFontLinkHeader = "";
|
|
620
|
-
try {
|
|
621
|
-
const earlyPreloads = [];
|
|
622
|
-
const fontGoogleEarly = await importModule(runner, "next/font/google");
|
|
623
|
-
if (typeof fontGoogleEarly.getSSRFontPreloads === "function") earlyPreloads.push(...fontGoogleEarly.getSSRFontPreloads());
|
|
624
|
-
const fontLocalEarly = await importModule(runner, "next/font/local");
|
|
625
|
-
if (typeof fontLocalEarly.getSSRFontPreloads === "function") earlyPreloads.push(...fontLocalEarly.getSSRFontPreloads());
|
|
626
|
-
if (earlyPreloads.length > 0) earlyFontLinkHeader = earlyPreloads.map((p) => `<${p.href}>; rel=preload; as=font; type=${p.type}; crossorigin`).join(", ");
|
|
627
|
-
} catch {}
|
|
628
633
|
if (typeof pageModule.getStaticProps === "function" && !isFallbackRender) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
634
|
+
isOnDemandRevalidate = isOnDemandRevalidateRequest(req.headers[PRERENDER_REVALIDATE_HEADER]);
|
|
635
|
+
if (isOnDemandRevalidate && req.headers["x-prerender-revalidate-if-generated"] !== void 0) {
|
|
636
|
+
res.writeHead(404, { [NEXTJS_CACHE_HEADER]: "REVALIDATED" });
|
|
637
|
+
res.end("This page could not be found");
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
632
640
|
const previewData = requestPreviewData;
|
|
633
|
-
staticPropsPreviewData = previewData;
|
|
634
641
|
const previewContext = previewData === false ? {} : {
|
|
635
642
|
draftMode: true,
|
|
636
643
|
preview: true,
|
|
637
644
|
previewData
|
|
638
645
|
};
|
|
639
|
-
if (!isOnDemandRevalidate && cached && !cached.isStale && cached.value.value?.kind === "PAGES" && !cached.value.value.generatedFromDataRequest && !scriptNonce && !isDataReq && previewData === false) {
|
|
640
|
-
const cachedHtml = cached.value.value.html;
|
|
641
|
-
const transformedHtml = await server.transformIndexHtml(url, cachedHtml);
|
|
642
|
-
const { cacheControl: hitCacheControl } = decideIsr({
|
|
643
|
-
cacheState: "HIT",
|
|
644
|
-
kind: "dev",
|
|
645
|
-
revalidateSeconds: getRevalidateDuration(cacheKey) ?? 60
|
|
646
|
-
});
|
|
647
|
-
const hitHeaders = {
|
|
648
|
-
"Content-Type": "text/html; charset=utf-8",
|
|
649
|
-
...buildCacheStateHeaders("HIT"),
|
|
650
|
-
"Cache-Control": hitCacheControl
|
|
651
|
-
};
|
|
652
|
-
if (earlyFontLinkHeader) hitHeaders["Link"] = earlyFontLinkHeader;
|
|
653
|
-
res.writeHead(200, hitHeaders);
|
|
654
|
-
res.end(transformedHtml);
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
if (!isOnDemandRevalidate && cached && cached.isStale && cached.value.value?.kind === "PAGES" && !cached.value.value.generatedFromDataRequest && !scriptNonce && !isDataReq && previewData === false) {
|
|
658
|
-
const cachedHtml = cached.value.value.html;
|
|
659
|
-
const transformedHtml = await server.transformIndexHtml(url, cachedHtml);
|
|
660
|
-
triggerBackgroundRegeneration(cacheKey, async () => {
|
|
661
|
-
return runWithRequestContext(createRequestContext({
|
|
662
|
-
executionContext: null,
|
|
663
|
-
ssrContext: {
|
|
664
|
-
pathname: patternToNextFormat(route.pattern),
|
|
665
|
-
query,
|
|
666
|
-
asPath: requestAsPath,
|
|
667
|
-
navigationIsReady,
|
|
668
|
-
locale: locale ?? currentDefaultLocale,
|
|
669
|
-
locales: i18nConfig?.locales,
|
|
670
|
-
defaultLocale: currentDefaultLocale
|
|
671
|
-
},
|
|
672
|
-
i18nContext: i18nConfig ? {
|
|
673
|
-
locale: locale ?? currentDefaultLocale,
|
|
674
|
-
locales: i18nConfig.locales,
|
|
675
|
-
defaultLocale: currentDefaultLocale,
|
|
676
|
-
domainLocales,
|
|
677
|
-
hostname: req.headers.host?.split(":", 1)[0]
|
|
678
|
-
} : null
|
|
679
|
-
}), async () => {
|
|
680
|
-
ensureFetchPatch();
|
|
681
|
-
let freshPageProps = {};
|
|
682
|
-
let freshRenderProps = { pageProps: freshPageProps };
|
|
683
|
-
let RegenApp = null;
|
|
684
|
-
const appPath = path.join(pagesDir, "_app");
|
|
685
|
-
if (findFileWithExtensions(appPath, matcher)) try {
|
|
686
|
-
RegenApp = (await runner.import(appPath)).default ?? null;
|
|
687
|
-
} catch {}
|
|
688
|
-
if (RegenApp && hasPagesGetInitialProps(RegenApp)) {
|
|
689
|
-
const regenReq = {
|
|
690
|
-
url: req.url,
|
|
691
|
-
headers: req.headers,
|
|
692
|
-
method: req.method
|
|
693
|
-
};
|
|
694
|
-
const regenRes = {
|
|
695
|
-
headersSent: false,
|
|
696
|
-
writableEnded: false,
|
|
697
|
-
statusCode: 200,
|
|
698
|
-
getHeaders() {
|
|
699
|
-
return {};
|
|
700
|
-
}
|
|
701
|
-
};
|
|
702
|
-
const initialProps = await loadPagesGetInitialProps(RegenApp, {
|
|
703
|
-
AppTree: (appTreeProps) => {
|
|
704
|
-
const appTree = React.createElement(RegenApp, {
|
|
705
|
-
...appTreeProps,
|
|
706
|
-
Component: pageModule.default,
|
|
707
|
-
pageProps: appTreeProps.pageProps,
|
|
708
|
-
router: routerShim.default
|
|
709
|
-
});
|
|
710
|
-
return typeof routerShim.wrapWithRouterContext === "function" ? routerShim.wrapWithRouterContext(appTree) : appTree;
|
|
711
|
-
},
|
|
712
|
-
Component: pageModule.default,
|
|
713
|
-
router: routerShim.default,
|
|
714
|
-
ctx: {
|
|
715
|
-
req: regenReq,
|
|
716
|
-
res: regenRes,
|
|
717
|
-
pathname: patternToNextFormat(route.pattern),
|
|
718
|
-
query,
|
|
719
|
-
asPath: requestAsPath,
|
|
720
|
-
locale: locale ?? currentDefaultLocale,
|
|
721
|
-
locales: i18nConfig?.locales,
|
|
722
|
-
defaultLocale: currentDefaultLocale
|
|
723
|
-
}
|
|
724
|
-
});
|
|
725
|
-
if (regenRes.headersSent || regenRes.writableEnded) return;
|
|
726
|
-
if (initialProps) {
|
|
727
|
-
freshRenderProps = initialProps;
|
|
728
|
-
freshPageProps = isUnknownRecord(initialProps.pageProps) ? initialProps.pageProps : {};
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
const freshResult = await pageModule.getStaticProps({
|
|
732
|
-
params: userFacingParams,
|
|
733
|
-
locale: locale ?? currentDefaultLocale,
|
|
734
|
-
locales: i18nConfig?.locales,
|
|
735
|
-
defaultLocale: currentDefaultLocale,
|
|
736
|
-
revalidateReason: "stale"
|
|
737
|
-
});
|
|
738
|
-
if (freshResult && "props" in freshResult) {
|
|
739
|
-
const revalidate = typeof freshResult.revalidate === "number" ? freshResult.revalidate : cached.value.cacheControl?.revalidate ?? 0;
|
|
740
|
-
if (revalidate > 0) {
|
|
741
|
-
freshPageProps = {
|
|
742
|
-
...freshPageProps,
|
|
743
|
-
...freshResult.props
|
|
744
|
-
};
|
|
745
|
-
freshRenderProps = {
|
|
746
|
-
...freshRenderProps,
|
|
747
|
-
pageProps: freshPageProps
|
|
748
|
-
};
|
|
749
|
-
if (typeof routerShim.setSSRContext === "function") routerShim.setSSRContext({
|
|
750
|
-
pathname: patternToNextFormat(route.pattern),
|
|
751
|
-
query,
|
|
752
|
-
asPath: requestAsPath,
|
|
753
|
-
navigationIsReady,
|
|
754
|
-
locale: locale ?? currentDefaultLocale,
|
|
755
|
-
locales: i18nConfig?.locales,
|
|
756
|
-
defaultLocale: currentDefaultLocale,
|
|
757
|
-
domainLocales
|
|
758
|
-
});
|
|
759
|
-
if (i18nConfig) {
|
|
760
|
-
await runner.import("vinext/i18n-state");
|
|
761
|
-
const i18nCtx = await importModule(runner, "vinext/i18n-context");
|
|
762
|
-
if (typeof i18nCtx.setI18nContext === "function") i18nCtx.setI18nContext({
|
|
763
|
-
locale: locale ?? currentDefaultLocale,
|
|
764
|
-
locales: i18nConfig.locales,
|
|
765
|
-
defaultLocale: currentDefaultLocale,
|
|
766
|
-
domainLocales,
|
|
767
|
-
hostname: req.headers.host?.split(":", 1)[0]
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
let el = RegenApp ? React.createElement(RegenApp, {
|
|
771
|
-
...freshRenderProps,
|
|
772
|
-
Component: pageModule.default,
|
|
773
|
-
pageProps: freshRenderProps.pageProps,
|
|
774
|
-
router: routerShim.default
|
|
775
|
-
}) : React.createElement(pageModule.default, freshPageProps);
|
|
776
|
-
if (routerShim.wrapWithRouterContext) el = routerShim.wrapWithRouterContext(el);
|
|
777
|
-
const freshBody = await renderIsrPassToStringAsync(withScriptNonce(el, scriptNonce));
|
|
778
|
-
const viteRoot = server.config.root;
|
|
779
|
-
const viteBase = server.config.base;
|
|
780
|
-
const regenPageUrl = createPagesDevModuleUrl(viteRoot, route.filePath, viteBase);
|
|
781
|
-
const regenAppUrl = RegenApp ? createPagesDevModuleUrl(viteRoot, path.join(pagesDir, "_app"), viteBase) : null;
|
|
782
|
-
const freshPagesNextData = {
|
|
783
|
-
...pagesNextData,
|
|
784
|
-
__vinext: {
|
|
785
|
-
...pagesNextData.__vinext,
|
|
786
|
-
pageModuleUrl: regenPageUrl,
|
|
787
|
-
appModuleUrl: regenAppUrl,
|
|
788
|
-
hasMiddleware,
|
|
789
|
-
routeUrl: requestAsPath
|
|
790
|
-
}
|
|
791
|
-
};
|
|
792
|
-
const freshHtml = `<!DOCTYPE html><html><head></head><body><div id="__next">${freshBody}</div>${`<script id="__NEXT_DATA__" type="application/json">${safeJsonStringify({
|
|
793
|
-
props: freshRenderProps,
|
|
794
|
-
page: patternToNextFormat(route.pattern),
|
|
795
|
-
query: params,
|
|
796
|
-
buildId: process.env.__VINEXT_BUILD_ID,
|
|
797
|
-
isFallback: false,
|
|
798
|
-
locale: locale ?? currentDefaultLocale,
|
|
799
|
-
locales: i18nConfig?.locales,
|
|
800
|
-
defaultLocale: currentDefaultLocale,
|
|
801
|
-
domainLocales,
|
|
802
|
-
...freshPagesNextData
|
|
803
|
-
})}<\/script>`}\n ${cachedHtml.match(/<script type="module">[\s\S]*?<\/script>/)?.[0] ?? ""}</body></html>`;
|
|
804
|
-
await isrSet(cacheKey, buildPagesCacheValue(freshHtml, freshRenderProps), revalidate);
|
|
805
|
-
setRevalidateDuration(cacheKey, revalidate);
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
});
|
|
809
|
-
}, {
|
|
810
|
-
routerKind: "Pages Router",
|
|
811
|
-
routePath: route.pattern,
|
|
812
|
-
routeType: "render"
|
|
813
|
-
});
|
|
814
|
-
const { cacheControl: staleCacheControl } = decideIsr({
|
|
815
|
-
cacheState: "STALE",
|
|
816
|
-
kind: "dev",
|
|
817
|
-
revalidateSeconds: getRevalidateDuration(cacheKey) ?? 60
|
|
818
|
-
});
|
|
819
|
-
const staleHeaders = {
|
|
820
|
-
"Content-Type": "text/html; charset=utf-8",
|
|
821
|
-
...buildCacheStateHeaders("STALE"),
|
|
822
|
-
"Cache-Control": staleCacheControl
|
|
823
|
-
};
|
|
824
|
-
if (earlyFontLinkHeader) staleHeaders["Link"] = earlyFontLinkHeader;
|
|
825
|
-
res.writeHead(200, staleHeaders);
|
|
826
|
-
res.end(transformedHtml);
|
|
827
|
-
return;
|
|
828
|
-
}
|
|
829
646
|
const context = {
|
|
830
647
|
params: userFacingParams,
|
|
831
648
|
locale: locale ?? currentDefaultLocale,
|
|
@@ -834,43 +651,47 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
834
651
|
revalidateReason: isOnDemandRevalidate ? "on-demand" : "stale",
|
|
835
652
|
...previewContext
|
|
836
653
|
};
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
pageProps = isUnknownRecord(renderProps.pageProps) ? renderProps.pageProps : {};
|
|
843
|
-
}
|
|
654
|
+
if (await loadAppInitialProps()) return;
|
|
655
|
+
const result = await pageModule.getStaticProps(context);
|
|
656
|
+
const routePattern = patternToNextFormat(route.pattern);
|
|
657
|
+
assertPages404DoesNotReturnNotFound(routePattern, result);
|
|
658
|
+
if (result) staticPropsRevalidateSeconds = resolvePagesRevalidateSeconds(result, routePattern);
|
|
844
659
|
if (result && "props" in result) {
|
|
845
|
-
pageProps =
|
|
846
|
-
...pageProps,
|
|
847
|
-
...await Promise.resolve(result.props)
|
|
848
|
-
};
|
|
660
|
+
pageProps = mergePagesDataProps(renderProps.pageProps, await Promise.resolve(result.props));
|
|
849
661
|
renderProps = {
|
|
850
662
|
...renderProps,
|
|
851
663
|
pageProps
|
|
852
664
|
};
|
|
853
665
|
}
|
|
854
666
|
if (result && "redirect" in result) {
|
|
855
|
-
|
|
667
|
+
if (previewData === false) resolvePagesRedirect(result.redirect, {
|
|
668
|
+
method: "getStaticProps",
|
|
669
|
+
routeUrl: url,
|
|
670
|
+
sanitizeDestination
|
|
671
|
+
});
|
|
672
|
+
applyDevPagesCacheHeaders(res, isOnDemandRevalidate ? "REVALIDATED" : "HIT", buildDevPagesTerminalCacheControl(staticPropsRevalidateSeconds, expireTime));
|
|
673
|
+
writeGsspRedirect(res, result.redirect, isDataReq, renderProps, {
|
|
674
|
+
basePath,
|
|
675
|
+
method: "getStaticProps",
|
|
676
|
+
routeUrl: url
|
|
677
|
+
});
|
|
856
678
|
return;
|
|
857
679
|
}
|
|
858
680
|
if (result && "notFound" in result && result.notFound) {
|
|
681
|
+
applyDevPagesCacheHeaders(res, isOnDemandRevalidate ? "REVALIDATED" : "HIT", isDataReq ? buildDevPagesTerminalCacheControl(staticPropsRevalidateSeconds, expireTime) : DEV_PAGES_CACHE_CONTROL);
|
|
859
682
|
applyDevPagesPreviewResponse(res, requestPreview);
|
|
860
683
|
if (isDataReq) {
|
|
861
684
|
const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
|
|
862
685
|
const notFoundHeaders = { "Content-Type": "application/json" };
|
|
863
686
|
if (deploymentId) notFoundHeaders[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
864
687
|
res.writeHead(404, notFoundHeaders);
|
|
865
|
-
res.end("{}");
|
|
688
|
+
res.end("{\"notFound\":true}");
|
|
866
689
|
return;
|
|
867
690
|
}
|
|
868
|
-
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, void 0, void 0, reactStrictMode);
|
|
691
|
+
await renderErrorPage(server, runner, req, res, url, pagesDir, 404, routerShim.wrapWithRouterContext, void 0, void 0, reactStrictMode, errorPageContext);
|
|
869
692
|
return;
|
|
870
693
|
}
|
|
871
|
-
if (result && "props" in result) isSerializableProps(
|
|
872
|
-
if (previewData === false && typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
|
|
873
|
-
else if (previewData === false && cached?.value.value?.kind === "PAGES" && cached.value.value.generatedFromDataRequest) isrRevalidateSeconds = cached.value.cacheControl?.revalidate ?? 31536e3;
|
|
694
|
+
if (result && "props" in result) isSerializableProps(routePattern, "getStaticProps", pageProps);
|
|
874
695
|
}
|
|
875
696
|
if (typeof pageModule.getServerSideProps !== "function" && typeof pageModule.getStaticProps !== "function" && hasAppGetInitialProps) {
|
|
876
697
|
if (await loadAppInitialProps()) return;
|
|
@@ -899,20 +720,11 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
899
720
|
}
|
|
900
721
|
}
|
|
901
722
|
if (isDataReq) {
|
|
902
|
-
if (shouldPersistFallbackData && staticPropsPreviewData === false) {
|
|
903
|
-
const cacheKey = pagesIsrCacheKey(url.split("?")[0]);
|
|
904
|
-
const revalidateSeconds = isrRevalidateSeconds ?? 31536e3;
|
|
905
|
-
await isrSet(cacheKey, {
|
|
906
|
-
kind: "PAGES",
|
|
907
|
-
html: "",
|
|
908
|
-
pageData: renderProps,
|
|
909
|
-
generatedFromDataRequest: true,
|
|
910
|
-
headers: void 0,
|
|
911
|
-
status: void 0
|
|
912
|
-
}, revalidateSeconds);
|
|
913
|
-
setRevalidateDuration(cacheKey, revalidateSeconds);
|
|
914
|
-
}
|
|
915
723
|
const dataHeaders = { "Content-Type": "application/json" };
|
|
724
|
+
if (typeof pageModule.getStaticProps === "function") {
|
|
725
|
+
dataHeaders["Cache-Control"] = DEV_PAGES_CACHE_CONTROL;
|
|
726
|
+
dataHeaders[NEXTJS_CACHE_HEADER] = isOnDemandRevalidate ? "REVALIDATED" : "HIT";
|
|
727
|
+
}
|
|
916
728
|
if ((statusCode ?? 200) === 200) dataHeaders["x-nextjs-matched-path"] = `${locale ? `/${locale}` : ""}${patternToNextFormat(route.pattern)}`;
|
|
917
729
|
if (gsspExtraHeaders) for (const [k, v] of Object.entries(gsspExtraHeaders)) dataHeaders[k] = v;
|
|
918
730
|
applyDevPagesPreviewHeaders(dataHeaders, requestPreview);
|
|
@@ -932,7 +744,6 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
932
744
|
if (AppComponent) element = createElement(AppComponent, {
|
|
933
745
|
...renderProps,
|
|
934
746
|
Component: PageComponent,
|
|
935
|
-
pageProps: renderProps.pageProps,
|
|
936
747
|
router: routerShim.default
|
|
937
748
|
});
|
|
938
749
|
else element = createElement(PageComponent, pageProps);
|
|
@@ -1011,10 +822,9 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
1011
822
|
} catch {}
|
|
1012
823
|
const allScripts = `${nextDataScript}\n ${createInlineScriptTag(`window.__VINEXT_PAGE_PATTERNS__=${safeJsonStringify(pagePatterns)}`, scriptNonce)}\n ${hydrationScript}`;
|
|
1013
824
|
const extraHeaders = { ...gsspExtraHeaders };
|
|
1014
|
-
if (
|
|
1015
|
-
|
|
1016
|
-
extraHeaders[
|
|
1017
|
-
Object.assign(extraHeaders, buildCacheStateHeaders("MISS"));
|
|
825
|
+
if (typeof pageModule.getStaticProps === "function") {
|
|
826
|
+
extraHeaders["Cache-Control"] = DEV_PAGES_CACHE_CONTROL;
|
|
827
|
+
extraHeaders[NEXTJS_CACHE_HEADER] = isFallbackRender ? "MISS" : isOnDemandRevalidate ? "REVALIDATED" : "HIT";
|
|
1018
828
|
}
|
|
1019
829
|
applyDevPagesPreviewHeaders(extraHeaders, requestPreview);
|
|
1020
830
|
if (allFontPreloads.length > 0) extraHeaders["Link"] = allFontPreloads.map((p) => `<${p.href}>; rel=preload; as=font; type=${p.type}; crossorigin`).join(", ");
|
|
@@ -1046,7 +856,7 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
1046
856
|
if (FinalApp) enhancedElement = createElement(FinalApp, {
|
|
1047
857
|
...renderProps,
|
|
1048
858
|
Component: FinalComp,
|
|
1049
|
-
|
|
859
|
+
router: routerShim.default
|
|
1050
860
|
});
|
|
1051
861
|
else enhancedElement = createElement(FinalComp, pageProps);
|
|
1052
862
|
if (wrapWithRouterContext) enhancedElement = wrapWithRouterContext(enhancedElement);
|
|
@@ -1062,18 +872,6 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
1062
872
|
});
|
|
1063
873
|
_renderEnd = now();
|
|
1064
874
|
if (typeof routerShim.setSSRContext === "function") routerShim.setSSRContext(null);
|
|
1065
|
-
if (!scriptNonce && isrRevalidateSeconds !== null && isrRevalidateSeconds > 0) {
|
|
1066
|
-
let isrElement = AppComponent ? createElement(AppComponent, {
|
|
1067
|
-
...renderProps,
|
|
1068
|
-
Component: pageModule.default,
|
|
1069
|
-
pageProps
|
|
1070
|
-
}) : createElement(pageModule.default, pageProps);
|
|
1071
|
-
if (wrapWithRouterContext) isrElement = wrapWithRouterContext(isrElement);
|
|
1072
|
-
const isrHtml = `<!DOCTYPE html><html><head>${assetHeadHTML}</head><body><div id="__next">${await renderIsrPassToStringAsync(withScriptNonce(isrElement, scriptNonce))}</div>${allScripts}</body></html>`;
|
|
1073
|
-
const cacheKey = pagesIsrCacheKey(url.split("?")[0]);
|
|
1074
|
-
await isrSet(cacheKey, buildPagesCacheValue(isrHtml, pageProps), isrRevalidateSeconds);
|
|
1075
|
-
setRevalidateDuration(cacheKey, isrRevalidateSeconds);
|
|
1076
|
-
}
|
|
1077
875
|
} catch (e) {
|
|
1078
876
|
console.error(e);
|
|
1079
877
|
reportRequestError(e instanceof Error ? e : new Error(String(e)), {
|
|
@@ -1086,7 +884,7 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
1086
884
|
routeType: "render"
|
|
1087
885
|
}).catch(() => {});
|
|
1088
886
|
try {
|
|
1089
|
-
await renderErrorPage(server, runner, req, res, url, pagesDir, 500, void 0, matcher, e instanceof Error ? e : new Error(String(e)), reactStrictMode);
|
|
887
|
+
await renderErrorPage(server, runner, req, res, url, pagesDir, 500, void 0, matcher, e instanceof Error ? e : new Error(String(e)), reactStrictMode, errorPageContext);
|
|
1090
888
|
} catch (fallbackErr) {
|
|
1091
889
|
res.statusCode = 500;
|
|
1092
890
|
res.end(`Internal Server Error: ${fallbackErr.message}`);
|
|
@@ -1103,16 +901,20 @@ function createSSRHandler(server, runner, routes, pagesDir, i18nConfig, fileMatc
|
|
|
1103
901
|
* - 500: pages/500.tsx -> pages/_error.tsx -> default
|
|
1104
902
|
* - other: pages/_error.tsx -> default
|
|
1105
903
|
*/
|
|
1106
|
-
async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCode, wrapWithRouterContext, fileMatcher, err, reactStrictMode = false) {
|
|
904
|
+
async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCode, wrapWithRouterContext, fileMatcher, err, reactStrictMode = false, context = { basePath: "" }) {
|
|
1107
905
|
attachPagesRequestCookies(req);
|
|
1108
906
|
const matcher = fileMatcher ?? createValidFileMatcher();
|
|
1109
907
|
const candidates = statusCode === 404 ? ["404", "_error"] : statusCode === 500 ? ["500", "_error"] : ["_error"];
|
|
1110
908
|
for (const candidate of candidates) {
|
|
1111
909
|
let errorRouterShim = null;
|
|
910
|
+
let candidateLoaded = false;
|
|
911
|
+
let errorAssetPath = null;
|
|
1112
912
|
try {
|
|
1113
|
-
|
|
913
|
+
errorAssetPath = findFileWithExts(pagesDir, candidate, matcher);
|
|
1114
914
|
if (!errorAssetPath && candidate !== "_error") continue;
|
|
1115
|
-
const
|
|
915
|
+
const errorModule = await importModule(runner, errorAssetPath ?? "next/error");
|
|
916
|
+
candidateLoaded = true;
|
|
917
|
+
const ErrorComponent = errorModule.default;
|
|
1116
918
|
if (!ErrorComponent) continue;
|
|
1117
919
|
let AppComponent = null;
|
|
1118
920
|
const appPathErr = path.join(pagesDir, "_app");
|
|
@@ -1146,10 +948,36 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1146
948
|
asPath: url
|
|
1147
949
|
});
|
|
1148
950
|
if (res.headersSent || res.writableEnded) return;
|
|
1149
|
-
|
|
951
|
+
let errorProps = {
|
|
1150
952
|
...initialErrorProps,
|
|
1151
953
|
statusCode
|
|
1152
954
|
};
|
|
955
|
+
if (typeof errorModule.getStaticProps === "function") {
|
|
956
|
+
const isOnDemandRevalidate = isOnDemandRevalidateRequest(req.headers[PRERENDER_REVALIDATE_HEADER]);
|
|
957
|
+
const staticResult = await errorModule.getStaticProps({
|
|
958
|
+
locale: context.locale,
|
|
959
|
+
locales: context.locales,
|
|
960
|
+
defaultLocale: context.defaultLocale,
|
|
961
|
+
revalidateReason: isOnDemandRevalidate ? "on-demand" : "stale"
|
|
962
|
+
});
|
|
963
|
+
assertPages404DoesNotReturnNotFound(errorPage, staticResult);
|
|
964
|
+
if (staticResult?.redirect) {
|
|
965
|
+
applyDevPagesCacheHeaders(res, isOnDemandRevalidate ? "REVALIDATED" : "HIT", NEVER_CACHE_CONTROL);
|
|
966
|
+
writeGsspRedirect(res, staticResult.redirect, false, { pageProps: errorProps }, {
|
|
967
|
+
basePath: context.basePath,
|
|
968
|
+
method: "getStaticProps",
|
|
969
|
+
routeUrl: url
|
|
970
|
+
});
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
if (staticResult?.props !== void 0) {
|
|
974
|
+
const staticProps = await Promise.resolve(staticResult.props);
|
|
975
|
+
isSerializableProps(errorPage, "getStaticProps", staticProps);
|
|
976
|
+
errorProps = mergePagesDataProps(errorProps, staticProps);
|
|
977
|
+
}
|
|
978
|
+
if (staticResult) resolvePagesRevalidateSeconds(staticResult, errorPage);
|
|
979
|
+
applyDevPagesCacheHeaders(res, isOnDemandRevalidate ? "REVALIDATED" : "HIT");
|
|
980
|
+
}
|
|
1153
981
|
let renderProps;
|
|
1154
982
|
if (AppComponent && hasPagesGetInitialProps(AppComponent)) {
|
|
1155
983
|
const appInitialProps = await loadPagesGetInitialProps(AppComponent, {
|
|
@@ -1173,7 +1001,11 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1173
1001
|
}
|
|
1174
1002
|
});
|
|
1175
1003
|
if (res.headersSent || res.writableEnded) return;
|
|
1176
|
-
|
|
1004
|
+
const appRenderProps = appInitialProps ?? {};
|
|
1005
|
+
renderProps = Object.hasOwn(appRenderProps, "pageProps") ? {
|
|
1006
|
+
...appRenderProps,
|
|
1007
|
+
pageProps: mergePagesDataProps(appRenderProps.pageProps, errorProps)
|
|
1008
|
+
} : appRenderProps;
|
|
1177
1009
|
} else renderProps = { pageProps: errorProps };
|
|
1178
1010
|
let DocumentComponent = null;
|
|
1179
1011
|
const docPathErr = path.join(pagesDir, "_document");
|
|
@@ -1257,8 +1089,9 @@ async function renderErrorPage(server, runner, req, res, url, pagesDir, statusCo
|
|
|
1257
1089
|
res.end(transformedHtml);
|
|
1258
1090
|
}
|
|
1259
1091
|
return;
|
|
1260
|
-
} catch {
|
|
1092
|
+
} catch (error) {
|
|
1261
1093
|
if (res.headersSent || res.writableEnded) return;
|
|
1094
|
+
if (errorAssetPath || candidateLoaded) throw error;
|
|
1262
1095
|
continue;
|
|
1263
1096
|
} finally {
|
|
1264
1097
|
if (typeof errorRouterShim?.setSSRContext === "function") errorRouterShim.setSSRContext(null);
|