vinext 0.2.0 → 0.2.1
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/dist/build/css-url-assets.d.ts +3 -1
- package/dist/build/css-url-assets.js +18 -1
- package/dist/build/inject-pregenerated-paths.d.ts +3 -0
- package/dist/build/inject-pregenerated-paths.js +4 -1
- package/dist/build/prerender-server-entry.d.ts +1 -0
- package/dist/build/prerender-server-entry.js +49 -0
- package/dist/build/prerender-server-pool.d.ts +44 -0
- package/dist/build/prerender-server-pool.js +194 -0
- package/dist/build/prerender.js +86 -22
- package/dist/build/run-prerender.js +2 -1
- package/dist/check.d.ts +4 -6
- package/dist/check.js +8 -9
- package/dist/cli.js +1 -1
- package/dist/client/vinext-next-data.d.ts +4 -1
- package/dist/config/config-matchers.js +33 -11
- package/dist/config/next-config.d.ts +36 -6
- package/dist/config/next-config.js +16 -2
- package/dist/entries/app-browser-entry.js +5 -1
- package/dist/entries/app-rsc-entry.d.ts +3 -2
- package/dist/entries/app-rsc-entry.js +4 -0
- package/dist/entries/pages-client-entry.js +14 -3
- package/dist/entries/pages-server-entry.js +18 -4
- package/dist/index.js +320 -25
- package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +8 -1
- package/dist/packages/cloudflare/src/deploy.js +1 -5
- package/dist/packages/cloudflare/src/tpr.js +26 -5
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +1 -1
- package/dist/plugins/og-assets.js +2 -1
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
- package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
- package/dist/plugins/sass.d.ts +17 -1
- package/dist/plugins/sass.js +74 -1
- package/dist/plugins/styled-jsx.d.ts +16 -0
- package/dist/plugins/styled-jsx.js +149 -0
- package/dist/routing/app-route-graph.js +22 -16
- package/dist/routing/file-matcher.d.ts +8 -1
- package/dist/routing/file-matcher.js +15 -3
- package/dist/server/app-browser-entry.js +46 -14
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-server-action-client.js +5 -3
- package/dist/server/app-browser-state.d.ts +1 -0
- package/dist/server/app-browser-state.js +2 -2
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +3 -3
- package/dist/server/app-page-cache.js +23 -6
- package/dist/server/app-page-dispatch.d.ts +1 -0
- package/dist/server/app-page-dispatch.js +25 -8
- package/dist/server/app-page-element-builder.js +1 -0
- package/dist/server/app-page-execution.js +2 -1
- package/dist/server/app-page-render-identity.d.ts +1 -0
- package/dist/server/app-page-render-identity.js +2 -1
- package/dist/server/app-page-render.d.ts +2 -0
- package/dist/server/app-page-render.js +67 -16
- package/dist/server/app-page-response.d.ts +7 -0
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-stream.d.ts +2 -1
- package/dist/server/app-page-stream.js +1 -1
- package/dist/server/app-route-handler-execution.js +1 -1
- package/dist/server/app-route-tree-prefetch.d.ts +43 -0
- package/dist/server/app-route-tree-prefetch.js +187 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +2 -1
- package/dist/server/app-rsc-cache-busting.js +9 -4
- package/dist/server/app-rsc-handler.d.ts +6 -0
- package/dist/server/app-rsc-handler.js +89 -11
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.d.ts +3 -4
- package/dist/server/app-rsc-request-normalization.js +4 -5
- package/dist/server/app-server-action-execution.js +4 -3
- package/dist/server/app-ssr-entry.js +3 -3
- package/dist/server/cache-control.d.ts +3 -1
- package/dist/server/cache-control.js +13 -1
- package/dist/server/dev-server.d.ts +11 -1
- package/dist/server/dev-server.js +78 -20
- package/dist/server/headers.d.ts +6 -2
- package/dist/server/headers.js +11 -5
- package/dist/server/isr-cache.d.ts +2 -1
- package/dist/server/isr-cache.js +7 -3
- package/dist/server/pages-data-route.d.ts +4 -2
- package/dist/server/pages-data-route.js +18 -4
- package/dist/server/pages-dev-module-url.d.ts +2 -1
- package/dist/server/pages-dev-module-url.js +6 -3
- package/dist/server/pages-node-compat.d.ts +12 -1
- package/dist/server/pages-node-compat.js +50 -1
- package/dist/server/pages-page-data.d.ts +9 -0
- package/dist/server/pages-page-data.js +17 -9
- package/dist/server/pages-page-handler.js +19 -7
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +3 -2
- package/dist/server/pages-request-pipeline.d.ts +8 -6
- package/dist/server/pages-request-pipeline.js +30 -6
- package/dist/server/pages-router-entry.js +1 -1
- package/dist/server/prod-server.d.ts +4 -2
- package/dist/server/prod-server.js +38 -22
- package/dist/server/request-pipeline.js +1 -1
- package/dist/shims/cache-handler.js +8 -1
- package/dist/shims/cache.js +3 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +77 -52
- package/dist/shims/form.d.ts +1 -1
- package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
- package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
- package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
- package/dist/shims/internal/pages-data-target.d.ts +8 -3
- package/dist/shims/internal/pages-data-target.js +9 -4
- package/dist/shims/link.d.ts +1 -1
- package/dist/shims/link.js +179 -42
- package/dist/shims/navigation.d.ts +15 -3
- package/dist/shims/navigation.js +202 -39
- package/dist/shims/navigation.react-server.js +1 -1
- package/dist/shims/request-context.js +18 -0
- package/dist/shims/router.js +31 -15
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -1
- package/dist/utils/middleware-request-headers.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/dist/utils/vite-version.d.ts +2 -0
- package/dist/utils/vite-version.js +11 -1
- package/package.json +2 -2
|
@@ -264,6 +264,12 @@ async function resolvePagesPageData(options) {
|
|
|
264
264
|
}
|
|
265
265
|
let pageProps = {};
|
|
266
266
|
let gsspRes = null;
|
|
267
|
+
const previewData = options.isOnDemandRevalidate ? false : options.previewData ?? false;
|
|
268
|
+
const previewContext = previewData === false ? {} : {
|
|
269
|
+
draftMode: true,
|
|
270
|
+
preview: true,
|
|
271
|
+
previewData
|
|
272
|
+
};
|
|
267
273
|
let sharedReqRes = null;
|
|
268
274
|
function getSharedReqRes() {
|
|
269
275
|
sharedReqRes ??= options.createGsspReqRes();
|
|
@@ -317,7 +323,8 @@ async function resolvePagesPageData(options) {
|
|
|
317
323
|
resolvedUrl: options.resolvedUrl ?? options.routeUrl,
|
|
318
324
|
locale: options.i18n.locale,
|
|
319
325
|
locales: options.i18n.locales,
|
|
320
|
-
defaultLocale: options.i18n.defaultLocale
|
|
326
|
+
defaultLocale: options.i18n.defaultLocale,
|
|
327
|
+
...previewContext
|
|
321
328
|
});
|
|
322
329
|
if (isResponseSent(res)) return {
|
|
323
330
|
kind: "response",
|
|
@@ -338,7 +345,7 @@ async function resolvePagesPageData(options) {
|
|
|
338
345
|
response: buildPagesRedirectResponse(result.redirect, options, renderProps)
|
|
339
346
|
};
|
|
340
347
|
if (result?.notFound) return buildPagesNotFoundResult(options);
|
|
341
|
-
if (result?.props !== void 0) isSerializableProps(options.routePattern, "getServerSideProps", pageProps);
|
|
348
|
+
if (result?.props !== void 0 && options.validatePropsSerialization !== false) isSerializableProps(options.routePattern, "getServerSideProps", pageProps);
|
|
342
349
|
gsspRes = res;
|
|
343
350
|
}
|
|
344
351
|
let isrRevalidateSeconds = null;
|
|
@@ -347,7 +354,7 @@ async function resolvePagesPageData(options) {
|
|
|
347
354
|
const cacheKey = options.isrCacheKey("pages", pathname);
|
|
348
355
|
const cached = await options.isrGet(cacheKey);
|
|
349
356
|
const cachedValue = cached?.value.value;
|
|
350
|
-
if (!options.isOnDemandRevalidate && cached?.isStale === false && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq) {
|
|
357
|
+
if (!options.isOnDemandRevalidate && cached?.isStale === false && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq && previewData === false) {
|
|
351
358
|
const hitResponse = buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status);
|
|
352
359
|
const hitBotResult = applyBotETagAndCheck(hitResponse, cachedValue.html, options);
|
|
353
360
|
if (hitBotResult) return hitBotResult;
|
|
@@ -356,7 +363,7 @@ async function resolvePagesPageData(options) {
|
|
|
356
363
|
response: hitResponse
|
|
357
364
|
};
|
|
358
365
|
}
|
|
359
|
-
if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && cached.isStale && !options.scriptNonce && !options.isDataReq) {
|
|
366
|
+
if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && cached.isStale && !options.scriptNonce && !options.isDataReq && previewData === false) {
|
|
360
367
|
options.triggerBackgroundRegeneration(cacheKey, async function() {
|
|
361
368
|
return options.runInFreshUnifiedContext(async () => {
|
|
362
369
|
options.applyRequestContexts();
|
|
@@ -413,7 +420,7 @@ async function resolvePagesPageData(options) {
|
|
|
413
420
|
response: staleResponse
|
|
414
421
|
};
|
|
415
422
|
}
|
|
416
|
-
const generatedPageData = !options.isOnDemandRevalidate && cached?.isStale === false && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest && isUnknownRecord(cachedValue.pageData) ? cachedValue.pageData : null;
|
|
423
|
+
const generatedPageData = !options.isOnDemandRevalidate && previewData === false && cached?.isStale === false && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest && isUnknownRecord(cachedValue.pageData) ? cachedValue.pageData : null;
|
|
417
424
|
if (!generatedPageData) {
|
|
418
425
|
const shortCircuit = await loadForegroundAppInitialRenderProps();
|
|
419
426
|
if (shortCircuit) return shortCircuit;
|
|
@@ -423,6 +430,7 @@ async function resolvePagesPageData(options) {
|
|
|
423
430
|
locale: options.i18n.locale,
|
|
424
431
|
locales: options.i18n.locales,
|
|
425
432
|
defaultLocale: options.i18n.defaultLocale,
|
|
433
|
+
...previewContext,
|
|
426
434
|
revalidateReason: options.isOnDemandRevalidate ? "on-demand" : options.isBuildTimePrerendering ? "build" : "stale"
|
|
427
435
|
});
|
|
428
436
|
if (generatedPageData) {
|
|
@@ -444,10 +452,10 @@ async function resolvePagesPageData(options) {
|
|
|
444
452
|
response: buildPagesRedirectResponse(result.redirect, options, renderProps)
|
|
445
453
|
};
|
|
446
454
|
if (result?.notFound) return buildPagesNotFoundResult(options);
|
|
447
|
-
if (result?.props !== void 0) isSerializableProps(options.routePattern, "getStaticProps", pageProps);
|
|
448
|
-
if (typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
|
|
449
|
-
else if (cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest) isrRevalidateSeconds = cached?.value.cacheControl?.revalidate ?? 31536e3;
|
|
450
|
-
if (shouldPersistFallbackData) {
|
|
455
|
+
if (result?.props !== void 0 && options.validatePropsSerialization !== false) isSerializableProps(options.routePattern, "getStaticProps", pageProps);
|
|
456
|
+
if (previewData === false && typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
|
|
457
|
+
else if (previewData === false && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest) isrRevalidateSeconds = cached?.value.cacheControl?.revalidate ?? 31536e3;
|
|
458
|
+
if (shouldPersistFallbackData && previewData === false) {
|
|
451
459
|
const revalidateSeconds = isrRevalidateSeconds ?? 31536e3;
|
|
452
460
|
await options.isrSet(cacheKey, {
|
|
453
461
|
kind: "PAGES",
|
|
@@ -3,8 +3,8 @@ import { patternToNextFormat } from "../routing/route-validation.js";
|
|
|
3
3
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
4
4
|
import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
|
|
5
5
|
import { reportRequestError } from "./instrumentation.js";
|
|
6
|
-
import { NEVER_CACHE_CONTROL } from "./cache-control.js";
|
|
7
|
-
import "./isr-decision.js";
|
|
6
|
+
import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, applyCdnResponseHeaders, shouldUseNextDeployCacheControl } from "./cache-control.js";
|
|
7
|
+
import { buildMissIsrCacheControl } from "./isr-decision.js";
|
|
8
8
|
import { PRERENDER_REVALIDATE_HEADER, isOnDemandRevalidateRequest, isrCacheKey, isrGet, isrSet, triggerBackgroundRegeneration } from "./isr-cache.js";
|
|
9
9
|
import { ensureFetchPatch } from "../shims/fetch-cache.js";
|
|
10
10
|
import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
|
|
@@ -18,8 +18,8 @@ import { renderPagesPageResponse } from "./pages-page-response.js";
|
|
|
18
18
|
import { hasPagesGetInitialProps } from "./pages-get-initial-props.js";
|
|
19
19
|
import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
|
|
20
20
|
import { resolvePagesPageData } from "./pages-page-data.js";
|
|
21
|
-
import { createPagesReqRes } from "./pages-node-compat.js";
|
|
22
21
|
import { collectAssetTags, resolveClientModuleUrl } from "./pages-asset-tags.js";
|
|
22
|
+
import { createPagesReqRes, getPagesPreviewData } from "./pages-node-compat.js";
|
|
23
23
|
//#region src/server/pages-page-handler.ts
|
|
24
24
|
function shouldEmitPagesClientTraceMetadata(pageModule, appComponent) {
|
|
25
25
|
if (typeof pageModule.getServerSideProps === "function") return true;
|
|
@@ -61,7 +61,7 @@ function createPagesPageHandler(opts) {
|
|
|
61
61
|
const originalRequestPathAndSearch = originalRequestUrl.pathname + originalRequestUrl.search;
|
|
62
62
|
let dataRequestPathname = null;
|
|
63
63
|
let dataRequestSearch = "";
|
|
64
|
-
const initialDataNorm = normalizePagesDataRequest(request, buildId);
|
|
64
|
+
const initialDataNorm = normalizePagesDataRequest(request, buildId, vinextConfig.basePath, hasMiddleware && vinextConfig.trailingSlash);
|
|
65
65
|
if (!isDataReq) {
|
|
66
66
|
if (initialDataNorm.notFoundResponse) return initialDataNorm.notFoundResponse;
|
|
67
67
|
if (initialDataNorm.isDataReq) {
|
|
@@ -133,6 +133,7 @@ function createPagesPageHandler(opts) {
|
|
|
133
133
|
const renderStatusCode = renderStatusCodeOverride ?? (routePattern === "/404" ? 404 : void 0);
|
|
134
134
|
const query = mergeRouteParamsIntoQuery(parseQueryString(routeUrl), params);
|
|
135
135
|
const pageModule = route.module;
|
|
136
|
+
const isStaticPropsRoute = typeof pageModule.getStaticProps === "function";
|
|
136
137
|
const pagesNextData = buildPagesReadinessNextData({
|
|
137
138
|
pageModule,
|
|
138
139
|
appComponent: AppComponent,
|
|
@@ -177,7 +178,8 @@ function createPagesPageHandler(opts) {
|
|
|
177
178
|
...pagesNextData.__vinext,
|
|
178
179
|
pageModuleUrl,
|
|
179
180
|
appModuleUrl,
|
|
180
|
-
hasMiddleware
|
|
181
|
+
hasMiddleware,
|
|
182
|
+
routeUrl
|
|
181
183
|
}
|
|
182
184
|
};
|
|
183
185
|
const scriptNonce = getScriptNonceFromHeaderSources(request.headers, middlewareHeaders);
|
|
@@ -194,6 +196,7 @@ function createPagesPageHandler(opts) {
|
|
|
194
196
|
request,
|
|
195
197
|
url: originalRequestPathAndSearch
|
|
196
198
|
});
|
|
199
|
+
const isOnDemandRevalidate = isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER));
|
|
197
200
|
const pageDataResult = await resolvePagesPageData({
|
|
198
201
|
isDataReq,
|
|
199
202
|
err: err instanceof Error ? err : void 0,
|
|
@@ -217,7 +220,9 @@ function createPagesPageHandler(opts) {
|
|
|
217
220
|
isrSet,
|
|
218
221
|
expireSeconds: vinextConfig.expireTime,
|
|
219
222
|
isBuildTimePrerendering: typeof process !== "undefined" && process.env && process.env.VINEXT_PRERENDER === "1",
|
|
220
|
-
|
|
223
|
+
validatePropsSerialization: process.env.NODE_ENV !== "production" || process.env.VINEXT_PRERENDER === "1",
|
|
224
|
+
isOnDemandRevalidate,
|
|
225
|
+
previewData: getPagesPreviewData(request, { isOnDemandRevalidate }),
|
|
221
226
|
pageModule,
|
|
222
227
|
AppComponent,
|
|
223
228
|
params,
|
|
@@ -300,6 +305,12 @@ function createPagesPageHandler(opts) {
|
|
|
300
305
|
break;
|
|
301
306
|
}
|
|
302
307
|
if (!hasUserCacheControl) init.headers["Cache-Control"] = NEVER_CACHE_CONTROL;
|
|
308
|
+
} else if (isStaticPropsRoute) {
|
|
309
|
+
if (isrRevalidateSeconds) {
|
|
310
|
+
const headers = new Headers(init.headers);
|
|
311
|
+
applyCdnResponseHeaders(headers, { cacheControl: buildMissIsrCacheControl(isrRevalidateSeconds, vinextConfig.expireTime) });
|
|
312
|
+
for (const [key, value] of headers) init.headers[key] = value;
|
|
313
|
+
} else if (shouldUseNextDeployCacheControl()) init.headers["Cache-Control"] = BROWSER_REVALIDATE_CACHE_CONTROL;
|
|
303
314
|
}
|
|
304
315
|
if (routePattern !== "/_error" && routePattern !== "/500") {
|
|
305
316
|
const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
|
|
@@ -308,8 +319,8 @@ function createPagesPageHandler(opts) {
|
|
|
308
319
|
return buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, init);
|
|
309
320
|
}
|
|
310
321
|
const pageModuleIds = [];
|
|
311
|
-
if (route.filePath) pageModuleIds.push(route.filePath);
|
|
312
322
|
if (appAssetPath) pageModuleIds.push(appAssetPath);
|
|
323
|
+
if (route.filePath) pageModuleIds.push(route.filePath);
|
|
313
324
|
return await renderPagesPageResponse({
|
|
314
325
|
assetTags: collectAssetTags({
|
|
315
326
|
manifest,
|
|
@@ -346,6 +357,7 @@ function createPagesPageHandler(opts) {
|
|
|
346
357
|
isrCacheKey: pageIsrCacheKey,
|
|
347
358
|
expireSeconds: vinextConfig.expireTime,
|
|
348
359
|
isrRevalidateSeconds,
|
|
360
|
+
isStaticPropsRoute,
|
|
349
361
|
isrSet,
|
|
350
362
|
i18n: buildI18nRenderContext(i18nConfig, locale, currentDefaultLocale, domainLocales),
|
|
351
363
|
isFallback: isFallbackRender,
|
|
@@ -91,6 +91,7 @@ type RenderPagesPageResponseOptions = {
|
|
|
91
91
|
isrCacheKey: (router: string, pathname: string) => string;
|
|
92
92
|
expireSeconds?: number;
|
|
93
93
|
isrRevalidateSeconds: number | null;
|
|
94
|
+
isStaticPropsRoute?: boolean;
|
|
94
95
|
isrSet: (key: string, data: CachedPagesValue, revalidateSeconds: number, tags?: string[], expireSeconds?: number) => Promise<void>;
|
|
95
96
|
i18n: PagesI18nRenderContext;
|
|
96
97
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getRequestExecutionContext } from "../shims/request-context.js";
|
|
2
2
|
import { reportRequestError } from "./instrumentation.js";
|
|
3
3
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
4
|
-
import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
|
|
4
|
+
import { BROWSER_REVALIDATE_CACHE_CONTROL, NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders, shouldUseNextDeployCacheControl } from "./cache-control.js";
|
|
5
5
|
import { buildMissIsrCacheControl } from "./isr-decision.js";
|
|
6
6
|
import { fnv1a52 } from "../utils/hash.js";
|
|
7
7
|
import { encodeCacheTag } from "../utils/encode-cache-tag.js";
|
|
@@ -264,7 +264,8 @@ async function renderPagesPageResponse(options) {
|
|
|
264
264
|
tags: [encodeCacheTag(`_N_T_${stem || "/"}`)]
|
|
265
265
|
});
|
|
266
266
|
setCacheStateHeaders(responseHeaders, "MISS");
|
|
267
|
-
} else if (options.
|
|
267
|
+
} else if (options.isStaticPropsRoute && shouldUseNextDeployCacheControl()) responseHeaders.set("Cache-Control", BROWSER_REVALIDATE_CACHE_CONTROL);
|
|
268
|
+
else if (options.gsspRes && !userSetCacheControl) responseHeaders.set("Cache-Control", NEVER_CACHE_CONTROL);
|
|
268
269
|
if (options.fontLinkHeader) responseHeaders.set("Link", options.fontLinkHeader);
|
|
269
270
|
if (options.userAgent && isPagesStreamingBot(options.userAgent)) {
|
|
270
271
|
const fullHtml = await readStreamAsText(compositeStream);
|
|
@@ -8,6 +8,13 @@ type PagesRenderOptions = {
|
|
|
8
8
|
originalUrl?: string;
|
|
9
9
|
};
|
|
10
10
|
type FilesystemRoutePhase = "direct" | "beforeFiles" | "afterFiles" | "fallback";
|
|
11
|
+
type PageRouteMatch = {
|
|
12
|
+
route: {
|
|
13
|
+
isDynamic: boolean;
|
|
14
|
+
pattern?: string;
|
|
15
|
+
dataKind?: "static" | "server" | "none";
|
|
16
|
+
};
|
|
17
|
+
};
|
|
11
18
|
declare function fetchWorkerFilesystemRoute(request: Request, requestPathname: string, phase: FilesystemRoutePhase, fetchAsset: (request: Request) => Promise<Response>): Promise<Response | false>;
|
|
12
19
|
type MiddlewareResult = {
|
|
13
20
|
continue: boolean;
|
|
@@ -37,12 +44,7 @@ type PagesPipelineDeps = {
|
|
|
37
44
|
hasMiddleware: boolean;
|
|
38
45
|
ctx?: unknown;
|
|
39
46
|
rawSearch?: string;
|
|
40
|
-
matchPageRoute?: ((pathname: string, request: Request) =>
|
|
41
|
-
route: {
|
|
42
|
-
isDynamic: boolean;
|
|
43
|
-
pattern?: string;
|
|
44
|
-
};
|
|
45
|
-
} | null) | null;
|
|
47
|
+
matchPageRoute?: ((pathname: string, request: Request) => PageRouteMatch | null) | null;
|
|
46
48
|
runMiddleware?: ((request: Request, ctx: unknown, opts: {
|
|
47
49
|
isDataRequest: boolean;
|
|
48
50
|
}) => Promise<MiddlewareResult>) | null;
|
|
@@ -4,6 +4,7 @@ import { applyMiddlewareRequestHeaders, isExternalUrl, matchRedirect, matchRewri
|
|
|
4
4
|
import { applyConfigHeadersToHeaderRecord, cloneRequestWithUrl, normalizeTrailingSlash } from "./request-pipeline.js";
|
|
5
5
|
import { mergeRewriteQuery } from "../utils/query.js";
|
|
6
6
|
import { normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./pages-i18n.js";
|
|
7
|
+
import { buildMiddlewarePrefetchSkipResponse } from "./pages-data-route.js";
|
|
7
8
|
import { mergeHeaders } from "./worker-utils.js";
|
|
8
9
|
//#region src/server/pages-request-pipeline.ts
|
|
9
10
|
async function fetchWorkerFilesystemRoute(request, requestPathname, phase, fetchAsset) {
|
|
@@ -149,6 +150,15 @@ async function runPagesRequest(request, deps) {
|
|
|
149
150
|
if (resolvedLocale && i18nConfig.locales.includes(resolvedLocale)) return matchedPathname === "/" ? `/${resolvedLocale}` : `/${resolvedLocale}${matchedPathname}`;
|
|
150
151
|
return matchResolvedPathname(matchedPathname);
|
|
151
152
|
};
|
|
153
|
+
const buildMiddlewarePrefetchSkipResult = (match) => {
|
|
154
|
+
if (!match) return null;
|
|
155
|
+
if (match.route.dataKind !== "server" || !isDataRequest || !deps.hasMiddleware || request.headers.get("x-middleware-prefetch") !== "1") return null;
|
|
156
|
+
return {
|
|
157
|
+
type: "response",
|
|
158
|
+
response: mergeHeaders(buildMiddlewarePrefetchSkipResponse(matchedPathnameForRoute(match.route.pattern)), middlewareHeaders, void 0),
|
|
159
|
+
defaultContentType: "application/json"
|
|
160
|
+
};
|
|
161
|
+
};
|
|
152
162
|
if (configHeaders.length) applyConfigHeadersToHeaderRecord(middlewareHeaders, {
|
|
153
163
|
configHeaders,
|
|
154
164
|
pathname: matchPathname,
|
|
@@ -178,14 +188,16 @@ async function runPagesRequest(request, deps) {
|
|
|
178
188
|
const beforeFilesResult = await serveFilesystemRoute(resolvedPathname, "beforeFiles");
|
|
179
189
|
if (beforeFilesResult) return beforeFilesResult;
|
|
180
190
|
}
|
|
181
|
-
|
|
191
|
+
const isOutsideBasePathUnclaimed = () => basePath && !hadBasePath && !configRewriteFired;
|
|
192
|
+
const outOfBasePathNotFound = () => ({
|
|
182
193
|
type: "response",
|
|
183
194
|
response: new Response("This page could not be found", {
|
|
184
195
|
status: 404,
|
|
185
196
|
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
186
197
|
})
|
|
187
|
-
};
|
|
198
|
+
});
|
|
188
199
|
const handleResolvedApiRoute = async () => {
|
|
200
|
+
if (isOutsideBasePathUnclaimed()) return null;
|
|
189
201
|
const apiLookupUrl = stripI18nLocaleForApiRoute(resolvedUrl, i18nConfig);
|
|
190
202
|
const apiLookupPathname = apiLookupUrl.split("?")[0];
|
|
191
203
|
if (!apiLookupPathname.startsWith("/api/") && apiLookupPathname !== "/api") return null;
|
|
@@ -212,7 +224,7 @@ async function runPagesRequest(request, deps) {
|
|
|
212
224
|
};
|
|
213
225
|
const apiResult = await handleResolvedApiRoute();
|
|
214
226
|
if (apiResult) return apiResult;
|
|
215
|
-
let pageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
|
|
227
|
+
let pageMatch = !isOutsideBasePathUnclaimed() && deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
|
|
216
228
|
let resolvedPathnameChanged = false;
|
|
217
229
|
if (!pageMatch || pageMatch.route.isDynamic) for (const rewrite of configRewrites.afterFiles ?? []) {
|
|
218
230
|
const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
@@ -223,6 +235,7 @@ async function runPagesRequest(request, deps) {
|
|
|
223
235
|
};
|
|
224
236
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
225
237
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
238
|
+
configRewriteFired = true;
|
|
226
239
|
resolvedPathnameChanged = true;
|
|
227
240
|
const afterFilesFilesystemResult = await serveFilesystemRoute(resolvedPathname, "afterFiles");
|
|
228
241
|
if (afterFilesFilesystemResult) return afterFilesFilesystemResult;
|
|
@@ -239,7 +252,7 @@ async function runPagesRequest(request, deps) {
|
|
|
239
252
|
refreshDataRewriteHeader();
|
|
240
253
|
if (typeof deps.renderPage === "function") {
|
|
241
254
|
let renderPageMatch = pageMatch;
|
|
242
|
-
if ((isDataReq || isDataRequest) && !renderPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
255
|
+
if ((isOutsideBasePathUnclaimed() || isDataReq || isDataRequest) && !renderPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
243
256
|
const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
244
257
|
if (!fallbackRewrite) continue;
|
|
245
258
|
if (isExternalUrl(fallbackRewrite)) return {
|
|
@@ -248,6 +261,7 @@ async function runPagesRequest(request, deps) {
|
|
|
248
261
|
};
|
|
249
262
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
250
263
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
264
|
+
configRewriteFired = true;
|
|
251
265
|
const fallbackFilesystemResult = await serveFilesystemRoute(resolvedPathname, "fallback");
|
|
252
266
|
if (fallbackFilesystemResult) return fallbackFilesystemResult;
|
|
253
267
|
const fallbackApiResult = await handleResolvedApiRoute();
|
|
@@ -256,6 +270,9 @@ async function runPagesRequest(request, deps) {
|
|
|
256
270
|
refreshDataRewriteHeader();
|
|
257
271
|
if (renderPageMatch) break;
|
|
258
272
|
}
|
|
273
|
+
const prefetchSkipResult = buildMiddlewarePrefetchSkipResult(renderPageMatch);
|
|
274
|
+
if (prefetchSkipResult) return prefetchSkipResult;
|
|
275
|
+
if (isOutsideBasePathUnclaimed()) return outOfBasePathNotFound();
|
|
259
276
|
const shouldDeferErrorPageOnMiss = !isDataReq && !isDataRequest && !!deps.matchPageRoute && !renderPageMatch;
|
|
260
277
|
const initialRenderOptions = shouldDeferErrorPageOnMiss ? { renderErrorPageOnMiss: false } : isDataReq ? { isDataReq: true } : void 0;
|
|
261
278
|
const stagedHeaders = new Headers();
|
|
@@ -272,6 +289,7 @@ async function runPagesRequest(request, deps) {
|
|
|
272
289
|
};
|
|
273
290
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
274
291
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
292
|
+
configRewriteFired = true;
|
|
275
293
|
const fallbackFilesystemResult = await serveFilesystemRoute(resolvedPathname, "fallback");
|
|
276
294
|
if (fallbackFilesystemResult) return fallbackFilesystemResult;
|
|
277
295
|
const fallbackApiResult = await handleResolvedApiRoute();
|
|
@@ -305,7 +323,8 @@ async function runPagesRequest(request, deps) {
|
|
|
305
323
|
defaultContentType: "text/html"
|
|
306
324
|
};
|
|
307
325
|
}
|
|
308
|
-
|
|
326
|
+
let devPageMatch = isOutsideBasePathUnclaimed() ? null : resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch;
|
|
327
|
+
if (!devPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
309
328
|
const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
310
329
|
if (!fallbackRewrite) continue;
|
|
311
330
|
if (isExternalUrl(fallbackRewrite)) return {
|
|
@@ -314,12 +333,17 @@ async function runPagesRequest(request, deps) {
|
|
|
314
333
|
};
|
|
315
334
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
316
335
|
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
336
|
+
configRewriteFired = true;
|
|
317
337
|
const fallbackFilesystemResult = await serveFilesystemRoute(resolvedPathname, "fallback");
|
|
318
338
|
if (fallbackFilesystemResult) return fallbackFilesystemResult;
|
|
319
339
|
const fallbackApiResult = await handleResolvedApiRoute();
|
|
320
340
|
if (fallbackApiResult) return fallbackApiResult;
|
|
321
|
-
|
|
341
|
+
devPageMatch = deps.matchPageRoute?.(resolvedPathname, request) ?? null;
|
|
342
|
+
if (devPageMatch) break;
|
|
322
343
|
}
|
|
344
|
+
const prefetchSkipResult = buildMiddlewarePrefetchSkipResult(devPageMatch);
|
|
345
|
+
if (prefetchSkipResult) return prefetchSkipResult;
|
|
346
|
+
if (isOutsideBasePathUnclaimed()) return outOfBasePathNotFound();
|
|
323
347
|
refreshDataRewriteHeader();
|
|
324
348
|
return {
|
|
325
349
|
type: "render",
|
|
@@ -2,8 +2,8 @@ import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
|
2
2
|
import { notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
3
3
|
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
4
4
|
import { cloneRequestWithHeaders, cloneRequestWithUrl, filterInternalHeaders } from "./request-pipeline.js";
|
|
5
|
-
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
|
|
6
5
|
import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
|
|
6
|
+
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
|
|
7
7
|
import { finalizeMissingStaticAssetResponse } from "./worker-utils.js";
|
|
8
8
|
import { fetchWorkerFilesystemRoute, runPagesRequest, wrapMiddlewareWithBasePath } from "./pages-request-pipeline.js";
|
|
9
9
|
import { registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
|
|
@@ -41,6 +41,7 @@ import { IncomingMessage, ServerResponse } from "node:http";
|
|
|
41
41
|
* Exported for direct unit testing of the URL choice.
|
|
42
42
|
*/
|
|
43
43
|
declare function resolveServerEntryImportUrl(entryPath: string): string;
|
|
44
|
+
declare function rememberCurrentServerEntryImportMtime(entryPath: string): void;
|
|
44
45
|
declare function importServerEntryModule(entryPath: string): Promise<any>;
|
|
45
46
|
/** Convert a Node.js IncomingMessage into a ReadableStream for Web Request body. */
|
|
46
47
|
declare function readNodeStream(req: IncomingMessage): ReadableStream<Uint8Array>;
|
|
@@ -54,7 +55,8 @@ type ProdServerOptions = {
|
|
|
54
55
|
* Omitted for normal `vinext start` so the existing production-server output
|
|
55
56
|
* remains stable.
|
|
56
57
|
*/
|
|
57
|
-
purpose?: "prerender";
|
|
58
|
+
purpose?: "prerender"; /** Suppress the startup log for internal child-process servers. */
|
|
59
|
+
silent?: boolean;
|
|
58
60
|
};
|
|
59
61
|
/** Content types that benefit from compression. */
|
|
60
62
|
declare const COMPRESSIBLE_TYPES: Set<string>;
|
|
@@ -145,4 +147,4 @@ declare function resolveAppRouterPrerenderSeeder(entryModule: unknown): AppRoute
|
|
|
145
147
|
*/
|
|
146
148
|
declare function resolveAppRouterAssetPath(pathname: string, assetPathPrefix: string, assetPrefix: string): string | null;
|
|
147
149
|
//#endregion
|
|
148
|
-
export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, ProdServerOptions, importServerEntryModule, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, readNodeStream, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };
|
|
150
|
+
export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, ProdServerOptions, importServerEntryModule, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, readNodeStream, rememberCurrentServerEntryImportMtime, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { normalizePathnameForRouteMatchStrict } from "../routing/utils.js";
|
|
2
2
|
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
3
|
-
import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER } from "../utils/protocol-headers.js";
|
|
3
|
+
import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
|
|
4
4
|
import { VINEXT_STATIC_FILE_HEADER } from "./headers.js";
|
|
5
5
|
import { normalizePath } from "./normalize-path.js";
|
|
6
6
|
import { notFoundResponse } from "./http-error-responses.js";
|
|
7
7
|
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
8
8
|
import { filterInternalHeaders } from "./request-pipeline.js";
|
|
9
9
|
import { isUnknownRecord } from "../utils/record.js";
|
|
10
|
-
import { buildNextDataNotFoundResponse, isNextDataPathname, parseNextDataPathname } from "./pages-data-route.js";
|
|
10
|
+
import { buildNextDataNotFoundResponse, isNextDataPathname, normalizeNextDataPagePathname, parseNextDataPathname } from "./pages-data-route.js";
|
|
11
|
+
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
|
|
12
|
+
import { setPagesClientAssets } from "./pages-client-assets.js";
|
|
11
13
|
import { resolveRequestHost, resolveRequestProtocol, trustProxy, trustedHosts } from "./proxy-trust.js";
|
|
12
14
|
import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath, isSafeImageContentType, parseImageParams } from "./image-optimization.js";
|
|
13
15
|
import { installSocketErrorBackstop } from "./socket-error-backstop.js";
|
|
14
|
-
import { ASSET_PREFIX_URL_DIR, assetPrefixPathname, isAbsoluteAssetPrefix } from "../utils/asset-prefix.js";
|
|
15
16
|
import { CONTENT_TYPES, StaticFileCache, etagFromFilenameHash } from "./static-file-cache.js";
|
|
16
17
|
import { collectInlineCssManifest } from "../build/inline-css.js";
|
|
17
18
|
import { mergeHeaders } from "./worker-utils.js";
|
|
18
19
|
import { runPagesRequest, wrapMiddlewareWithBasePath } from "./pages-request-pipeline.js";
|
|
19
20
|
import { computeClientRuntimeMetadata } from "../utils/client-runtime-metadata.js";
|
|
20
21
|
import { readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
21
|
-
import { setPagesClientAssets } from "./pages-client-assets.js";
|
|
22
22
|
import { readPrerenderSecret } from "../build/server-manifest.js";
|
|
23
23
|
import { seedMemoryCacheFromPrerender } from "./seed-cache.js";
|
|
24
24
|
import { negotiateEncoding, parseAcceptedEncodings, selectContentEncoding } from "./accept-encoding.js";
|
|
@@ -56,6 +56,18 @@ import { createServer } from "node:http";
|
|
|
56
56
|
* through a cache-busted URL instead.
|
|
57
57
|
*/
|
|
58
58
|
const bareServerEntryMtimes = /* @__PURE__ */ new Map();
|
|
59
|
+
function resolveCanonicalServerEntry(entryPath) {
|
|
60
|
+
let canonicalEntryPath;
|
|
61
|
+
try {
|
|
62
|
+
canonicalEntryPath = fs.realpathSync.native(entryPath);
|
|
63
|
+
} catch {
|
|
64
|
+
canonicalEntryPath = entryPath;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
href: pathToFileURL(canonicalEntryPath).href,
|
|
68
|
+
mtime: fs.statSync(canonicalEntryPath).mtimeMs
|
|
69
|
+
};
|
|
70
|
+
}
|
|
59
71
|
/**
|
|
60
72
|
* Import a built server entry module (App Router RSC entry or Pages Router
|
|
61
73
|
* server entry) by absolute file path.
|
|
@@ -93,14 +105,7 @@ const bareServerEntryMtimes = /* @__PURE__ */ new Map();
|
|
|
93
105
|
* Exported for direct unit testing of the URL choice.
|
|
94
106
|
*/
|
|
95
107
|
function resolveServerEntryImportUrl(entryPath) {
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
canonicalEntryPath = fs.realpathSync.native(entryPath);
|
|
99
|
-
} catch {
|
|
100
|
-
canonicalEntryPath = entryPath;
|
|
101
|
-
}
|
|
102
|
-
const href = pathToFileURL(canonicalEntryPath).href;
|
|
103
|
-
const mtime = fs.statSync(canonicalEntryPath).mtimeMs;
|
|
108
|
+
const { href, mtime } = resolveCanonicalServerEntry(entryPath);
|
|
104
109
|
const bareMtime = bareServerEntryMtimes.get(href);
|
|
105
110
|
if (bareMtime === void 0 || bareMtime === mtime) {
|
|
106
111
|
bareServerEntryMtimes.set(href, mtime);
|
|
@@ -108,6 +113,10 @@ function resolveServerEntryImportUrl(entryPath) {
|
|
|
108
113
|
}
|
|
109
114
|
return `${href}?t=${mtime}`;
|
|
110
115
|
}
|
|
116
|
+
function rememberCurrentServerEntryImportMtime(entryPath) {
|
|
117
|
+
const { href, mtime } = resolveCanonicalServerEntry(entryPath);
|
|
118
|
+
bareServerEntryMtimes.set(href, mtime);
|
|
119
|
+
}
|
|
111
120
|
async function importServerEntryModule(entryPath) {
|
|
112
121
|
return import(resolveServerEntryImportUrl(entryPath));
|
|
113
122
|
}
|
|
@@ -557,9 +566,11 @@ function nodeToWebRequest(req, urlOverride, prerenderSecret) {
|
|
|
557
566
|
const url = new URL(urlOverride ?? req.url ?? "/", origin);
|
|
558
567
|
const rawHeaders = nodeHeadersToWebHeaders(req.headers);
|
|
559
568
|
const prerenderRouteParamsPayload = readTrustedPrerenderRouteParamsFromHeaders(rawHeaders, prerenderSecret);
|
|
569
|
+
const isTrustedSpeculativePrerender = process.env.VINEXT_PRERENDER === "1" && prerenderSecret !== void 0 && rawHeaders.get("x-vinext-prerender-secret") === prerenderSecret && rawHeaders.get("x-vinext-prerender-speculative") === "1";
|
|
560
570
|
const headers = filterInternalHeaders(rawHeaders);
|
|
561
571
|
const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParamsPayload);
|
|
562
572
|
if (prerenderRouteParamsHeader !== null) headers.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
|
|
573
|
+
if (isTrustedSpeculativePrerender) headers.set(VINEXT_PRERENDER_SPECULATIVE_HEADER, "1");
|
|
563
574
|
const method = req.method ?? "GET";
|
|
564
575
|
const hasBody = method !== "GET" && method !== "HEAD";
|
|
565
576
|
const init = {
|
|
@@ -622,7 +633,7 @@ async function sendWebResponse(webResponse, req, res, compress) {
|
|
|
622
633
|
*/
|
|
623
634
|
async function startProdServer(options = {}) {
|
|
624
635
|
installSocketErrorBackstop();
|
|
625
|
-
const { port = process.env.PORT ? parseInt(process.env.PORT) : 3e3, host = "0.0.0.0", outDir = path.resolve("dist"), noCompression = false, purpose } = options;
|
|
636
|
+
const { port = process.env.PORT ? parseInt(process.env.PORT) : 3e3, host = "0.0.0.0", outDir = path.resolve("dist"), noCompression = false, purpose, silent = false } = options;
|
|
626
637
|
const compress = !noCompression;
|
|
627
638
|
const resolvedOutDir = path.resolve(outDir);
|
|
628
639
|
const clientDir = path.join(resolvedOutDir, "client");
|
|
@@ -640,7 +651,8 @@ async function startProdServer(options = {}) {
|
|
|
640
651
|
clientDir,
|
|
641
652
|
rscEntryPath,
|
|
642
653
|
compress,
|
|
643
|
-
purpose
|
|
654
|
+
purpose,
|
|
655
|
+
silent
|
|
644
656
|
});
|
|
645
657
|
return startPagesRouterServer({
|
|
646
658
|
port,
|
|
@@ -648,7 +660,8 @@ async function startProdServer(options = {}) {
|
|
|
648
660
|
clientDir,
|
|
649
661
|
serverEntryPath,
|
|
650
662
|
compress,
|
|
651
|
-
purpose
|
|
663
|
+
purpose,
|
|
664
|
+
silent
|
|
652
665
|
});
|
|
653
666
|
}
|
|
654
667
|
function createNodeExecutionContext() {
|
|
@@ -776,7 +789,7 @@ function installPagesClientAssets(options) {
|
|
|
776
789
|
* 4. Stream the Web Response back (with optional compression)
|
|
777
790
|
*/
|
|
778
791
|
async function startAppRouterServer(options) {
|
|
779
|
-
const { port, host, clientDir, rscEntryPath, compress, purpose } = options;
|
|
792
|
+
const { port, host, clientDir, rscEntryPath, compress, purpose, silent } = options;
|
|
780
793
|
const prerenderSecret = readPrerenderSecret(path.dirname(rscEntryPath));
|
|
781
794
|
const rscModule = await importServerEntryModule(rscEntryPath);
|
|
782
795
|
const rscHandler = resolveAppRouterHandler(rscModule.default);
|
|
@@ -899,7 +912,8 @@ async function startAppRouterServer(options) {
|
|
|
899
912
|
await new Promise((resolve) => {
|
|
900
913
|
server.listen(port, host, () => {
|
|
901
914
|
const addr = server.address();
|
|
902
|
-
|
|
915
|
+
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
916
|
+
if (!silent) logProdServerStarted(host, actualPort, purpose);
|
|
903
917
|
resolve();
|
|
904
918
|
});
|
|
905
919
|
});
|
|
@@ -930,7 +944,7 @@ function readPagesServerEntryPageRoutes(value) {
|
|
|
930
944
|
* - vinextConfig — embedded next.config.js settings
|
|
931
945
|
*/
|
|
932
946
|
async function startPagesRouterServer(options) {
|
|
933
|
-
const { port, host, clientDir, serverEntryPath, compress, purpose } = options;
|
|
947
|
+
const { port, host, clientDir, serverEntryPath, compress, purpose, silent } = options;
|
|
934
948
|
const serverEntry = await importServerEntryModule(serverEntryPath);
|
|
935
949
|
const { renderPage, handleApiRoute: handleApi, runMiddleware, vinextConfig, buildId: pagesBuildId } = serverEntry;
|
|
936
950
|
const matchPageRoute = typeof serverEntry.matchPageRoute === "function" ? serverEntry.matchPageRoute : void 0;
|
|
@@ -1062,8 +1076,9 @@ async function startPagesRouterServer(options) {
|
|
|
1062
1076
|
}
|
|
1063
1077
|
isDataReq = true;
|
|
1064
1078
|
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
1065
|
-
|
|
1066
|
-
|
|
1079
|
+
const pagePathname = normalizeNextDataPagePathname(dataMatch.pagePathname, hasMiddleware && trailingSlash);
|
|
1080
|
+
url = pagePathname + qs;
|
|
1081
|
+
pathname = pagePathname;
|
|
1067
1082
|
}
|
|
1068
1083
|
const protocol = resolveRequestProtocol(req);
|
|
1069
1084
|
const hostHeader = resolveRequestHost(req, `${host}:${port}`);
|
|
@@ -1144,7 +1159,8 @@ async function startPagesRouterServer(options) {
|
|
|
1144
1159
|
await new Promise((resolve) => {
|
|
1145
1160
|
server.listen(port, host, () => {
|
|
1146
1161
|
const addr = server.address();
|
|
1147
|
-
|
|
1162
|
+
const actualPort = typeof addr === "object" && addr ? addr.port : port;
|
|
1163
|
+
if (!silent) logProdServerStarted(host, actualPort, purpose);
|
|
1148
1164
|
resolve();
|
|
1149
1165
|
});
|
|
1150
1166
|
});
|
|
@@ -1155,4 +1171,4 @@ async function startPagesRouterServer(options) {
|
|
|
1155
1171
|
};
|
|
1156
1172
|
}
|
|
1157
1173
|
//#endregion
|
|
1158
|
-
export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, importServerEntryModule, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, readNodeStream, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };
|
|
1174
|
+
export { COMPRESSIBLE_TYPES, COMPRESS_THRESHOLD, importServerEntryModule, mergeResponseHeaders, mergeWebResponse, negotiateEncoding, nodeToWebRequest, readNodeStream, rememberCurrentServerEntryImportMtime, resolveAppRouterAssetPath, resolveAppRouterPrerenderSeeder, resolveRequestHost as resolveHost, resolveServerEntryImportUrl, sendCompressed, sendWebResponse, startProdServer, trustProxy, trustedHosts, tryServeStatic };
|
|
@@ -338,7 +338,7 @@ function isOriginAllowed(origin, allowed) {
|
|
|
338
338
|
*/
|
|
339
339
|
function processMiddlewareHeaders(headers) {
|
|
340
340
|
const keysToDelete = [];
|
|
341
|
-
for (const key of headers.keys()) if (key.startsWith("x-middleware-")) keysToDelete.push(key);
|
|
341
|
+
for (const key of headers.keys()) if (key.startsWith("x-middleware-") && key !== "x-middleware-cache") keysToDelete.push(key);
|
|
342
342
|
for (const key of keysToDelete) headers.delete(key);
|
|
343
343
|
}
|
|
344
344
|
const STRIPPED_INTERNAL_HEADERS = new Set([...INTERNAL_HEADERS, ...VINEXT_INTERNAL_HEADERS]);
|
|
@@ -42,6 +42,10 @@ function readStringArrayField(ctx, field) {
|
|
|
42
42
|
if (!Array.isArray(value)) return [];
|
|
43
43
|
return value.filter((item) => typeof item === "string");
|
|
44
44
|
}
|
|
45
|
+
function readPositiveNumberField(ctx, field) {
|
|
46
|
+
const value = ctx?.[field];
|
|
47
|
+
return typeof value === "number" && value > 0 ? value : void 0;
|
|
48
|
+
}
|
|
45
49
|
var MemoryCacheHandler = class {
|
|
46
50
|
store = /* @__PURE__ */ new Map();
|
|
47
51
|
tagRevalidatedAt = /* @__PURE__ */ new Map();
|
|
@@ -89,7 +93,10 @@ var MemoryCacheHandler = class {
|
|
|
89
93
|
return null;
|
|
90
94
|
}
|
|
91
95
|
this.touchEntry(key, entry);
|
|
92
|
-
|
|
96
|
+
const now = Date.now();
|
|
97
|
+
const requestedRevalidate = readPositiveNumberField(ctx, "revalidate");
|
|
98
|
+
const requestedRevalidateAt = requestedRevalidate === void 0 ? null : entry.lastModified + requestedRevalidate * 1e3;
|
|
99
|
+
if (entry.revalidateAt !== null && now > entry.revalidateAt || requestedRevalidateAt !== null && now > requestedRevalidateAt) return {
|
|
93
100
|
lastModified: entry.lastModified,
|
|
94
101
|
value: entry.value,
|
|
95
102
|
cacheState: "stale",
|
package/dist/shims/cache.js
CHANGED
|
@@ -8,6 +8,7 @@ import { makeHangingPromise } from "./internal/make-hanging-promise.js";
|
|
|
8
8
|
import { getHeadersAccessPhase, isDraftModeEnabled, markDynamicUsage } from "./headers.js";
|
|
9
9
|
import { ACTION_DID_REVALIDATE_DYNAMIC_ONLY, ACTION_DID_REVALIDATE_STATIC_AND_DYNAMIC, _consumeRequestScopedCacheLife, _initRequestScopedCacheState, _peekRequestScopedCacheLife, _peekUnstableCacheObservations, _registerCacheContextAccessor, _runWithCacheState, _setRequestScopedCacheLife, cacheLifeProfiles, getAndClearActionRevalidationKind, getRegisteredCacheContext, markActionRevalidation, recordUnstableCacheObservation, shouldServeStaleUnstableCacheEntry } from "./cache-request-state.js";
|
|
10
10
|
import { encodeCacheTag, encodeCacheTags } from "../utils/encode-cache-tag.js";
|
|
11
|
+
import { addCollectedRequestTags } from "./fetch-cache.js";
|
|
11
12
|
import { workUnitAsyncStorage } from "./internal/work-unit-async-storage.js";
|
|
12
13
|
//#region src/shims/cache.ts
|
|
13
14
|
/**
|
|
@@ -124,6 +125,7 @@ function updateTag(tag) {
|
|
|
124
125
|
* It's provided for API compatibility so apps importing it don't break.
|
|
125
126
|
*/
|
|
126
127
|
function unstable_noStore() {
|
|
128
|
+
if (isInsideUnstableCacheScope()) return;
|
|
127
129
|
markDynamicUsage();
|
|
128
130
|
}
|
|
129
131
|
/**
|
|
@@ -373,6 +375,7 @@ function unstable_cache(fn, keyParts, options) {
|
|
|
373
375
|
const revalidateSeconds = options?.revalidate;
|
|
374
376
|
const cachedFn = async (...args) => {
|
|
375
377
|
const cacheKey = `unstable_cache:${baseKey}:${JSON.stringify(args)}`;
|
|
378
|
+
addCollectedRequestTags(tags);
|
|
376
379
|
recordUnstableCacheObservation({
|
|
377
380
|
kind: "unstable_cache",
|
|
378
381
|
keyHash: fnv1a64(cacheKey),
|
|
@@ -42,6 +42,7 @@ type FetchCacheState = {
|
|
|
42
42
|
currentFetchCacheMode: FetchCacheMode | null;
|
|
43
43
|
currentForceDynamicFetchDefault: boolean;
|
|
44
44
|
dynamicFetchUrls: Set<string>;
|
|
45
|
+
refreshStaleFetchesInForeground: boolean;
|
|
45
46
|
isFetchDedupeActive: boolean;
|
|
46
47
|
currentFetchDedupeEntries: Map<string, FetchDedupeEntry[]>;
|
|
47
48
|
};
|
|
@@ -86,6 +87,7 @@ declare function setCurrentFetchSoftTags(tags: string[]): void;
|
|
|
86
87
|
declare function getCurrentFetchSoftTags(): string[];
|
|
87
88
|
declare function setCurrentFetchCacheMode(mode: FetchCacheMode | null): void;
|
|
88
89
|
declare function setCurrentForceDynamicFetchDefault(enabled: boolean): void;
|
|
90
|
+
declare function setRefreshStaleFetchesInForeground(enabled: boolean): void;
|
|
89
91
|
/**
|
|
90
92
|
* Install the patched fetch and reset per-request tag state.
|
|
91
93
|
* Returns a cleanup function that clears tags.
|
|
@@ -133,4 +135,4 @@ declare function ensureFetchPatch(): void;
|
|
|
133
135
|
*/
|
|
134
136
|
declare function getOriginalFetch(): typeof globalThis.fetch;
|
|
135
137
|
//#endregion
|
|
136
|
-
export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, withFetchCache };
|
|
138
|
+
export { FetchCacheMode, FetchCacheState, _resetPendingRefetches, addCollectedRequestTags, consumeDynamicFetchObservations, ensureFetchPatch, getCollectedFetchTags, getCurrentFetchSoftTags, getOriginalFetch, peekCacheableFetchObservations, peekDynamicFetchObservations, runWithFetchCache, runWithFetchDedupe, setCurrentFetchCacheMode, setCurrentFetchSoftTags, setCurrentForceDynamicFetchDefault, setRefreshStaleFetchesInForeground, withFetchCache };
|