vinext 0.1.2 → 0.1.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/dist/build/prerender.d.ts +9 -1
- package/dist/build/prerender.js +41 -12
- package/dist/build/run-prerender.d.ts +10 -2
- package/dist/build/run-prerender.js +15 -1
- package/dist/client/app-nav-failure-handler.d.ts +8 -0
- package/dist/client/app-nav-failure-handler.js +44 -0
- package/dist/client/vinext-next-data.d.ts +18 -1
- package/dist/client/window-next.d.ts +2 -1
- package/dist/client/window-next.js +12 -1
- package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
- package/dist/config/config-matchers.js +73 -14
- package/dist/config/next-config.d.ts +46 -4
- package/dist/config/next-config.js +147 -48
- package/dist/deploy.d.ts +30 -11
- package/dist/deploy.js +180 -99
- package/dist/entries/app-browser-entry.d.ts +9 -3
- package/dist/entries/app-browser-entry.js +21 -3
- package/dist/entries/app-rsc-entry.d.ts +2 -0
- package/dist/entries/app-rsc-entry.js +64 -5
- package/dist/entries/app-rsc-manifest.js +2 -0
- package/dist/entries/app-ssr-entry.js +1 -1
- package/dist/entries/pages-client-entry.js +53 -8
- package/dist/entries/pages-server-entry.js +41 -5
- package/dist/index.js +200 -62
- package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
- package/dist/plugins/extensionless-dynamic-import.js +152 -0
- package/dist/plugins/optimize-imports.d.ts +2 -1
- package/dist/plugins/optimize-imports.js +11 -9
- package/dist/plugins/postcss.js +7 -7
- package/dist/plugins/typeof-window.d.ts +14 -0
- package/dist/plugins/typeof-window.js +150 -0
- package/dist/routing/app-route-graph.d.ts +2 -1
- package/dist/routing/app-route-graph.js +44 -14
- package/dist/routing/file-matcher.d.ts +10 -1
- package/dist/routing/file-matcher.js +22 -1
- package/dist/routing/pages-router.js +3 -3
- package/dist/routing/utils.d.ts +35 -6
- package/dist/routing/utils.js +59 -7
- package/dist/server/api-handler.d.ts +6 -1
- package/dist/server/api-handler.js +21 -15
- package/dist/server/app-browser-action-result.d.ts +19 -6
- package/dist/server/app-browser-action-result.js +19 -10
- package/dist/server/app-browser-entry.js +167 -90
- package/dist/server/app-browser-error.d.ts +10 -6
- package/dist/server/app-browser-error.js +43 -8
- package/dist/server/app-browser-hydration.d.ts +2 -0
- package/dist/server/app-browser-hydration.js +1 -0
- package/dist/server/app-browser-navigation-controller.d.ts +4 -2
- package/dist/server/app-browser-navigation-controller.js +23 -2
- package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
- package/dist/server/app-browser-server-action-navigation.js +9 -0
- package/dist/server/app-browser-stream.js +86 -43
- package/dist/server/app-elements-wire.d.ts +6 -1
- package/dist/server/app-elements-wire.js +14 -4
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-fallback-renderer.d.ts +1 -0
- package/dist/server/app-fallback-renderer.js +3 -1
- package/dist/server/app-optimistic-routing.js +2 -2
- package/dist/server/app-page-boundary-render.d.ts +1 -0
- package/dist/server/app-page-boundary-render.js +27 -14
- package/dist/server/app-page-cache-render.d.ts +53 -0
- package/dist/server/app-page-cache-render.js +91 -0
- package/dist/server/app-page-cache.d.ts +16 -2
- package/dist/server/app-page-cache.js +62 -1
- package/dist/server/app-page-dispatch.d.ts +26 -0
- package/dist/server/app-page-dispatch.js +149 -92
- package/dist/server/app-page-element-builder.d.ts +1 -0
- package/dist/server/app-page-element-builder.js +5 -2
- package/dist/server/app-page-execution.d.ts +6 -1
- package/dist/server/app-page-execution.js +21 -1
- package/dist/server/app-page-probe.d.ts +1 -0
- package/dist/server/app-page-probe.js +4 -0
- package/dist/server/app-page-render-observation.d.ts +3 -1
- package/dist/server/app-page-render-observation.js +17 -1
- package/dist/server/app-page-render.d.ts +12 -1
- package/dist/server/app-page-render.js +42 -4
- package/dist/server/app-page-request.d.ts +2 -0
- package/dist/server/app-page-request.js +2 -1
- package/dist/server/app-page-route-wiring.d.ts +3 -1
- package/dist/server/app-page-route-wiring.js +14 -5
- package/dist/server/app-page-stream.d.ts +15 -3
- package/dist/server/app-page-stream.js +11 -5
- package/dist/server/app-pages-bridge.d.ts +18 -0
- package/dist/server/app-pages-bridge.js +22 -5
- package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
- package/dist/server/app-ppr-fallback-shell-render.js +26 -0
- package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
- package/dist/server/app-ppr-fallback-shell.js +8 -1
- package/dist/server/app-route-handler-dispatch.js +9 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-router-entry.js +5 -0
- package/dist/server/app-rsc-cache-busting.js +2 -0
- package/dist/server/app-rsc-handler.d.ts +25 -0
- package/dist/server/app-rsc-handler.js +154 -54
- package/dist/server/app-rsc-route-matching.d.ts +3 -0
- package/dist/server/app-rsc-route-matching.js +2 -0
- package/dist/server/app-segment-config.d.ts +9 -1
- package/dist/server/app-segment-config.js +12 -3
- package/dist/server/app-server-action-execution.d.ts +1 -0
- package/dist/server/app-server-action-execution.js +42 -13
- package/dist/server/app-ssr-entry.d.ts +2 -0
- package/dist/server/app-ssr-entry.js +83 -10
- package/dist/server/cache-control.js +4 -0
- package/dist/server/dev-server.d.ts +2 -2
- package/dist/server/dev-server.js +244 -51
- package/dist/server/hybrid-route-priority.d.ts +22 -0
- package/dist/server/hybrid-route-priority.js +33 -0
- package/dist/server/image-optimization.d.ts +18 -9
- package/dist/server/image-optimization.js +37 -23
- package/dist/server/implicit-tags.d.ts +2 -1
- package/dist/server/implicit-tags.js +4 -1
- package/dist/server/navigation-planner.d.ts +133 -30
- package/dist/server/navigation-planner.js +114 -0
- package/dist/server/navigation-trace.d.ts +8 -1
- package/dist/server/navigation-trace.js +8 -1
- package/dist/server/pages-api-route.d.ts +6 -0
- package/dist/server/pages-api-route.js +13 -2
- package/dist/server/pages-asset-tags.d.ts +2 -1
- package/dist/server/pages-asset-tags.js +6 -2
- package/dist/server/pages-data-route.d.ts +8 -1
- package/dist/server/pages-data-route.js +11 -2
- package/dist/server/pages-get-initial-props.d.ts +54 -4
- package/dist/server/pages-get-initial-props.js +43 -1
- package/dist/server/pages-node-compat.js +2 -2
- package/dist/server/pages-page-data.d.ts +11 -2
- package/dist/server/pages-page-data.js +204 -33
- package/dist/server/pages-page-handler.d.ts +4 -2
- package/dist/server/pages-page-handler.js +59 -22
- package/dist/server/pages-page-response.d.ts +2 -1
- package/dist/server/pages-page-response.js +7 -4
- package/dist/server/pages-request-pipeline.d.ts +1 -0
- package/dist/server/pages-request-pipeline.js +73 -36
- package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
- package/dist/server/pregenerated-concrete-paths.js +2 -19
- package/dist/server/prerender-manifest.d.ts +33 -0
- package/dist/server/prerender-manifest.js +54 -0
- package/dist/server/prerender-route-params.d.ts +1 -2
- package/dist/server/prod-server.js +9 -3
- package/dist/server/request-pipeline.d.ts +3 -15
- package/dist/server/request-pipeline.js +58 -47
- package/dist/server/rsc-stream-hints.d.ts +5 -1
- package/dist/server/rsc-stream-hints.js +6 -1
- package/dist/server/seed-cache.js +10 -18
- package/dist/shims/app-router-scroll-state.d.ts +3 -1
- package/dist/shims/app-router-scroll-state.js +14 -2
- package/dist/shims/app-router-scroll.d.ts +3 -0
- package/dist/shims/app-router-scroll.js +28 -18
- package/dist/shims/cache-runtime.js +3 -2
- package/dist/shims/cache.d.ts +1 -0
- package/dist/shims/cache.js +1 -1
- package/dist/shims/cdn-cache.d.ts +5 -5
- package/dist/shims/dynamic-preload-chunks.js +6 -4
- package/dist/shims/error-boundary.d.ts +2 -0
- package/dist/shims/error-boundary.js +7 -0
- package/dist/shims/error.js +3 -2
- package/dist/shims/error.react-server.d.ts +9 -0
- package/dist/shims/error.react-server.js +6 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +45 -20
- package/dist/shims/hash-scroll.js +6 -1
- package/dist/shims/headers.js +29 -4
- package/dist/shims/internal/als-registry.js +28 -1
- package/dist/shims/internal/app-route-detection.js +8 -17
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
- package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
- package/dist/shims/internal/navigation-untracked.d.ts +35 -0
- package/dist/shims/internal/navigation-untracked.js +55 -0
- package/dist/shims/internal/pages-data-target.d.ts +7 -2
- package/dist/shims/internal/pages-data-target.js +17 -8
- package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
- package/dist/shims/internal/pages-router-accessor.js +13 -0
- package/dist/shims/internal/router-context.d.ts +2 -1
- package/dist/shims/internal/router-context.js +3 -1
- package/dist/shims/link.js +12 -5
- package/dist/shims/navigation.d.ts +8 -2
- package/dist/shims/navigation.js +61 -31
- package/dist/shims/ppr-fallback-shell.d.ts +5 -1
- package/dist/shims/ppr-fallback-shell.js +28 -7
- package/dist/shims/router.d.ts +13 -2
- package/dist/shims/router.js +419 -128
- package/dist/shims/server.d.ts +16 -1
- package/dist/shims/server.js +44 -12
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/utils/built-asset-url.d.ts +4 -0
- package/dist/utils/built-asset-url.js +11 -0
- package/dist/utils/commonjs-loader.d.ts +16 -0
- package/dist/utils/commonjs-loader.js +100 -0
- package/dist/utils/deployment-id.d.ts +8 -0
- package/dist/utils/deployment-id.js +22 -0
- package/dist/utils/html-limited-bots.d.ts +18 -1
- package/dist/utils/html-limited-bots.js +23 -1
- package/dist/utils/parse-cookie.d.ts +13 -0
- package/dist/utils/parse-cookie.js +52 -0
- package/dist/utils/path.d.ts +7 -1
- package/dist/utils/path.js +9 -1
- package/package.json +2 -2
- package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
- package/dist/shims/internal/parse-cookie-header.js +0 -30
|
@@ -31,6 +31,7 @@ type VinextConfigSubset = {
|
|
|
31
31
|
assetPrefix: string;
|
|
32
32
|
trailingSlash: boolean;
|
|
33
33
|
expireTime?: number;
|
|
34
|
+
htmlLimitedBots?: string;
|
|
34
35
|
clientTraceMetadata?: readonly string[];
|
|
35
36
|
disableOptimizedLoading: boolean;
|
|
36
37
|
};
|
|
@@ -73,8 +74,8 @@ type CreatePagesPageHandlerOptions = {
|
|
|
73
74
|
renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>; /** `safeJsonStringify` from `vinext/html`. */
|
|
74
75
|
safeJsonStringify: (value: unknown) => string; /** `sanitizeDestination` from the config-matchers module. */
|
|
75
76
|
sanitizeDestination: (dest: string) => string; /** Build the React page element for a given set of page props. */
|
|
76
|
-
createPageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null,
|
|
77
|
-
enhancePageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null,
|
|
77
|
+
createPageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null, props: Record<string, unknown>) => ReactNode; /** Build the element with optional App/Component enhancers (for _document). */
|
|
78
|
+
enhancePageElement: (PageComponent: ComponentType, AppComponent: ComponentType | null, props: Record<string, unknown>, opts: RenderPageEnhancers) => ReactNode; /** The `_app` page component (or null). */
|
|
78
79
|
AppComponent: ComponentType | null; /** The `_document` page component (or null). */
|
|
79
80
|
DocumentComponent: ComponentType | null;
|
|
80
81
|
};
|
|
@@ -82,6 +83,7 @@ type RenderPageOptions = {
|
|
|
82
83
|
isDataReq?: boolean;
|
|
83
84
|
statusCode?: number;
|
|
84
85
|
asPath?: string;
|
|
86
|
+
originalUrl?: string;
|
|
85
87
|
renderErrorPageOnMiss?: boolean;
|
|
86
88
|
__isInternalErrorRender?: boolean;
|
|
87
89
|
__forcedRoute?: PageRoute;
|
|
@@ -7,13 +7,14 @@ import { NEVER_CACHE_CONTROL } from "./cache-control.js";
|
|
|
7
7
|
import "./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
|
+
import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
|
|
10
11
|
import { mergeRouteParamsIntoQuery, parseQueryString } from "../utils/query.js";
|
|
11
12
|
import { getScriptNonceFromHeaderSources } from "./csp.js";
|
|
12
13
|
import { resolvePagesI18nRequest } from "./pages-i18n.js";
|
|
13
14
|
import { buildDefaultPagesNotFoundResponse } from "./pages-default-404.js";
|
|
14
15
|
import { buildPagesReadinessNextData } from "./pages-readiness.js";
|
|
15
16
|
import { resolvePagesPageMethodResponse } from "./pages-page-method.js";
|
|
16
|
-
import {
|
|
17
|
+
import { buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, normalizePagesDataRequest, parseNextDataPathname } from "./pages-data-route.js";
|
|
17
18
|
import { createPagesReqRes } from "./pages-node-compat.js";
|
|
18
19
|
import { collectAssetTags, resolveClientModuleUrl } from "./pages-asset-tags.js";
|
|
19
20
|
import { renderPagesPageResponse } from "./pages-page-response.js";
|
|
@@ -48,19 +49,38 @@ function createPagesPageHandler(opts) {
|
|
|
48
49
|
}
|
|
49
50
|
async function renderPage(request, url, manifest, middlewareHeaders, options) {
|
|
50
51
|
let isDataReq = !!(options && options.isDataReq);
|
|
52
|
+
const requestUrl = new URL(request.url);
|
|
53
|
+
const rawOriginalUrl = options && typeof options.originalUrl === "string" ? options.originalUrl : requestUrl.pathname + requestUrl.search;
|
|
54
|
+
const originalRequestUrl = new URL(rawOriginalUrl, requestUrl);
|
|
55
|
+
const originalRequestPathAndSearch = originalRequestUrl.pathname + originalRequestUrl.search;
|
|
56
|
+
let dataRequestPathname = null;
|
|
57
|
+
let dataRequestSearch = "";
|
|
58
|
+
const initialDataNorm = normalizePagesDataRequest(request, buildId);
|
|
51
59
|
if (!isDataReq) {
|
|
52
|
-
|
|
53
|
-
if (
|
|
54
|
-
if (dataNorm.isDataReq) {
|
|
60
|
+
if (initialDataNorm.notFoundResponse) return initialDataNorm.notFoundResponse;
|
|
61
|
+
if (initialDataNorm.isDataReq) {
|
|
55
62
|
isDataReq = true;
|
|
63
|
+
dataRequestPathname = initialDataNorm.normalizedPathname;
|
|
64
|
+
dataRequestSearch = initialDataNorm.search;
|
|
56
65
|
if (url && url.startsWith("/_next/data/")) {
|
|
57
66
|
const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
|
|
58
|
-
url =
|
|
67
|
+
url = initialDataNorm.normalizedPathname + qs;
|
|
59
68
|
}
|
|
60
69
|
}
|
|
70
|
+
} else if (initialDataNorm.isDataReq) {
|
|
71
|
+
dataRequestPathname = initialDataNorm.normalizedPathname;
|
|
72
|
+
dataRequestSearch = initialDataNorm.search;
|
|
73
|
+
}
|
|
74
|
+
if (isDataReq && dataRequestPathname === null && buildId) {
|
|
75
|
+
const originalDataMatch = parseNextDataPathname(originalRequestUrl.pathname, buildId);
|
|
76
|
+
if (originalDataMatch) {
|
|
77
|
+
dataRequestPathname = originalDataMatch.pagePathname;
|
|
78
|
+
dataRequestSearch = originalRequestUrl.search;
|
|
79
|
+
}
|
|
61
80
|
}
|
|
62
81
|
const statusCode = options && typeof options.statusCode === "number" ? options.statusCode : void 0;
|
|
63
|
-
const
|
|
82
|
+
const defaultAsPath = isDataReq && dataRequestPathname ? dataRequestPathname + dataRequestSearch : originalRequestPathAndSearch;
|
|
83
|
+
const asPath = options && typeof options.asPath === "string" ? options.asPath : defaultAsPath;
|
|
64
84
|
const renderErrorPageOnMiss = !(options && options.renderErrorPageOnMiss === false);
|
|
65
85
|
const isInternalErrorRender = !!(options && options.__isInternalErrorRender);
|
|
66
86
|
const err = options && options.err;
|
|
@@ -143,8 +163,8 @@ function createPagesPageHandler(opts) {
|
|
|
143
163
|
});
|
|
144
164
|
if (methodResponse) return methodResponse;
|
|
145
165
|
}
|
|
146
|
-
const pageModuleUrl = resolveClientModuleUrl(manifest, route.filePath, vinextConfig.basePath, vinextConfig.assetPrefix);
|
|
147
|
-
const appModuleUrl = resolveClientModuleUrl(manifest, appAssetPath, vinextConfig.basePath, vinextConfig.assetPrefix);
|
|
166
|
+
const pageModuleUrl = resolveClientModuleUrl(manifest, route.filePath, vinextConfig.basePath, vinextConfig.assetPrefix, process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID);
|
|
167
|
+
const appModuleUrl = resolveClientModuleUrl(manifest, appAssetPath, vinextConfig.basePath, vinextConfig.assetPrefix, process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID);
|
|
148
168
|
const serializedPagesNextData = {
|
|
149
169
|
...pagesNextData,
|
|
150
170
|
__vinext: {
|
|
@@ -159,24 +179,30 @@ function createPagesPageHandler(opts) {
|
|
|
159
179
|
let allFontPreloads = [];
|
|
160
180
|
try {
|
|
161
181
|
allFontPreloads = getFontPreloads();
|
|
162
|
-
if (allFontPreloads.length > 0) fontLinkHeader = allFontPreloads.map((p) => "<" + p.href + ">; rel=preload; as=font; type=" + p.type + "; crossorigin").join(", ");
|
|
182
|
+
if (allFontPreloads.length > 0) fontLinkHeader = allFontPreloads.map((p) => "<" + appendAssetDeploymentIdQuery(p.href) + ">; rel=preload; as=font; type=" + p.type + "; crossorigin").join(", ");
|
|
163
183
|
} catch {}
|
|
184
|
+
const pagesResolvedUrl = (new URL(routeUrl, originalRequestUrl).pathname || "/") + originalRequestUrl.search;
|
|
164
185
|
const pageDataResult = await resolvePagesPageData({
|
|
165
186
|
isDataReq,
|
|
166
187
|
err,
|
|
167
188
|
applyRequestContexts: applySSRContext,
|
|
168
189
|
buildId,
|
|
169
190
|
deploymentId: process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID,
|
|
191
|
+
htmlLimitedBots: vinextConfig.htmlLimitedBots,
|
|
170
192
|
createGsspReqRes() {
|
|
171
193
|
return createPagesReqRes({
|
|
172
194
|
body: void 0,
|
|
173
195
|
query,
|
|
174
196
|
request,
|
|
175
|
-
url:
|
|
197
|
+
url: originalRequestPathAndSearch
|
|
176
198
|
});
|
|
177
199
|
},
|
|
178
|
-
|
|
179
|
-
const el = createPageElement(PageComponent, AppComponent,
|
|
200
|
+
createAppTree(appTreeProps) {
|
|
201
|
+
const el = createPageElement(PageComponent, AppComponent, appTreeProps);
|
|
202
|
+
return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
|
|
203
|
+
},
|
|
204
|
+
createPageElement(currentProps) {
|
|
205
|
+
const el = createPageElement(PageComponent, AppComponent, currentProps);
|
|
180
206
|
return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
|
|
181
207
|
},
|
|
182
208
|
fontLinkHeader,
|
|
@@ -188,15 +214,17 @@ function createPagesPageHandler(opts) {
|
|
|
188
214
|
isBuildTimePrerendering: typeof process !== "undefined" && process.env && process.env.VINEXT_PRERENDER === "1",
|
|
189
215
|
isOnDemandRevalidate: isOnDemandRevalidateRequest(request.headers.get(PRERENDER_REVALIDATE_HEADER)),
|
|
190
216
|
pageModule,
|
|
217
|
+
AppComponent,
|
|
191
218
|
params,
|
|
192
219
|
query,
|
|
193
220
|
asPath: renderAsPath ?? routeUrl,
|
|
221
|
+
resolvedUrl: pagesResolvedUrl,
|
|
194
222
|
renderIsrPassToStringAsync,
|
|
195
223
|
route: { isDynamic: route.isDynamic },
|
|
196
224
|
routePattern,
|
|
197
225
|
routeUrl,
|
|
198
226
|
runInFreshUnifiedContext(callback) {
|
|
199
|
-
return runWithRequestContext(createRequestContext({ executionContext:
|
|
227
|
+
return runWithRequestContext(createRequestContext({ executionContext: null }), async () => {
|
|
200
228
|
ensureFetchPatch();
|
|
201
229
|
return callback();
|
|
202
230
|
});
|
|
@@ -224,10 +252,17 @@ function createPagesPageHandler(opts) {
|
|
|
224
252
|
}
|
|
225
253
|
if (pageDataResult.kind === "response") return pageDataResult.response;
|
|
226
254
|
let pageProps = pageDataResult.pageProps;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
255
|
+
let renderProps = pageDataResult.props;
|
|
256
|
+
if (routePattern === "/_error" && typeof renderStatusCode === "number") {
|
|
257
|
+
pageProps = {
|
|
258
|
+
...pageProps,
|
|
259
|
+
statusCode: renderStatusCode
|
|
260
|
+
};
|
|
261
|
+
renderProps = {
|
|
262
|
+
...renderProps,
|
|
263
|
+
pageProps
|
|
264
|
+
};
|
|
265
|
+
}
|
|
231
266
|
const gsspRes = pageDataResult.gsspRes;
|
|
232
267
|
const isrRevalidateSeconds = pageDataResult.isrRevalidateSeconds;
|
|
233
268
|
const isFallbackRender = pageDataResult.isFallback === true;
|
|
@@ -264,7 +299,7 @@ function createPagesPageHandler(opts) {
|
|
|
264
299
|
const deploymentId = process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID;
|
|
265
300
|
if (deploymentId) init.headers[NEXTJS_DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
266
301
|
}
|
|
267
|
-
return
|
|
302
|
+
return buildNextDataPropsJsonResponse(renderProps, safeJsonStringify, init);
|
|
268
303
|
}
|
|
269
304
|
const pageModuleIds = [];
|
|
270
305
|
if (route.filePath) pageModuleIds.push(route.filePath);
|
|
@@ -276,18 +311,19 @@ function createPagesPageHandler(opts) {
|
|
|
276
311
|
scriptNonce,
|
|
277
312
|
disableOptimizedLoading: vinextConfig.disableOptimizedLoading,
|
|
278
313
|
basePath: vinextConfig.basePath,
|
|
279
|
-
assetPrefix: vinextConfig.assetPrefix
|
|
314
|
+
assetPrefix: vinextConfig.assetPrefix,
|
|
315
|
+
deploymentId: process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID
|
|
280
316
|
}),
|
|
281
317
|
buildId,
|
|
282
318
|
clearSsrContext() {
|
|
283
319
|
if (typeof setSSRContext === "function") setSSRContext(null);
|
|
284
320
|
},
|
|
285
|
-
createPageElement(
|
|
286
|
-
const el = createPageElement(PageComponent, AppComponent,
|
|
321
|
+
createPageElement(currentProps) {
|
|
322
|
+
const el = createPageElement(PageComponent, AppComponent, currentProps);
|
|
287
323
|
return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
|
|
288
324
|
},
|
|
289
325
|
enhancePageElement(renderPageOpts) {
|
|
290
|
-
const el = enhancePageElement(PageComponent, AppComponent,
|
|
326
|
+
const el = enhancePageElement(PageComponent, AppComponent, renderProps, renderPageOpts);
|
|
291
327
|
return typeof wrapWithRouterContext === "function" ? wrapWithRouterContext(el) : el;
|
|
292
328
|
},
|
|
293
329
|
DocumentComponent,
|
|
@@ -306,6 +342,7 @@ function createPagesPageHandler(opts) {
|
|
|
306
342
|
i18n: buildI18nRenderContext(i18nConfig, locale, currentDefaultLocale, domainLocales),
|
|
307
343
|
isFallback: isFallbackRender,
|
|
308
344
|
pageProps,
|
|
345
|
+
props: renderProps,
|
|
309
346
|
params,
|
|
310
347
|
renderDocumentToString(element) {
|
|
311
348
|
return renderToStringAsync(element);
|
|
@@ -93,6 +93,7 @@ type RenderPagesPageResponseOptions = {
|
|
|
93
93
|
*/
|
|
94
94
|
isFallback?: boolean;
|
|
95
95
|
pageProps: Record<string, unknown>;
|
|
96
|
+
props?: Record<string, unknown>;
|
|
96
97
|
params: Record<string, unknown>;
|
|
97
98
|
renderDocumentToString: (element: ReactNode) => Promise<string>;
|
|
98
99
|
renderToReadableStream: (element: ReactNode) => Promise<ReadableStream<Uint8Array>>;
|
|
@@ -127,7 +128,7 @@ type RenderPagesPageResponseOptions = {
|
|
|
127
128
|
*/
|
|
128
129
|
requestCacheControl?: string;
|
|
129
130
|
};
|
|
130
|
-
declare function buildPagesNextDataScript(options: Pick<RenderPagesPageResponseOptions, "buildId" | "i18n" | "isFallback" | "pageProps" | "params" | "routePattern" | "safeJsonStringify" | "scriptNonce" | "nextData"> & {
|
|
131
|
+
declare function buildPagesNextDataScript(options: Pick<RenderPagesPageResponseOptions, "buildId" | "i18n" | "isFallback" | "pageProps" | "props" | "params" | "routePattern" | "safeJsonStringify" | "scriptNonce" | "nextData"> & {
|
|
131
132
|
vinext?: VinextNextData["__vinext"];
|
|
132
133
|
}): string;
|
|
133
134
|
declare function renderPagesPageResponse(options: RenderPagesPageResponseOptions): Promise<Response>;
|
|
@@ -5,6 +5,7 @@ import { fnv1a52 } from "../utils/hash.js";
|
|
|
5
5
|
import { encodeCacheTag } from "../utils/encode-cache-tag.js";
|
|
6
6
|
import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, applyCdnResponseHeaders } from "./cache-control.js";
|
|
7
7
|
import { buildMissIsrCacheControl } from "./isr-decision.js";
|
|
8
|
+
import { appendAssetDeploymentIdQuery } from "../utils/deployment-id.js";
|
|
8
9
|
import { withScriptNonce } from "../shims/script-nonce-context.js";
|
|
9
10
|
import { createInlineScriptTag, createNonceAttribute, escapeHtmlAttr } from "./html.js";
|
|
10
11
|
import { getClientTraceMetadataHTML } from "./client-trace-metadata.js";
|
|
@@ -62,14 +63,14 @@ function requestsNoCache(cacheControl) {
|
|
|
62
63
|
function buildPagesFontHeadHtml(fontLinks, fontPreloads, fontStyles, scriptNonce) {
|
|
63
64
|
let html = "";
|
|
64
65
|
const nonceAttr = createNonceAttribute(scriptNonce);
|
|
65
|
-
for (const link of fontLinks) html += `<link rel="stylesheet"${nonceAttr} href="${escapeHtmlAttr(link)}" />\n `;
|
|
66
|
-
for (const preload of fontPreloads) html += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(preload.href)}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n `;
|
|
66
|
+
for (const link of fontLinks) html += `<link rel="stylesheet"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(link))}" />\n `;
|
|
67
|
+
for (const preload of fontPreloads) html += `<link rel="preload"${nonceAttr} href="${escapeHtmlAttr(appendAssetDeploymentIdQuery(preload.href))}" as="font" type="${escapeHtmlAttr(preload.type)}" crossorigin />\n `;
|
|
67
68
|
if (fontStyles.length > 0) html += `<style data-vinext-fonts${nonceAttr}>${fontStyles.join("\n")}</style>\n `;
|
|
68
69
|
return html;
|
|
69
70
|
}
|
|
70
71
|
function buildPagesNextDataScript(options) {
|
|
71
72
|
const nextDataPayload = {
|
|
72
|
-
props: { pageProps: options.pageProps },
|
|
73
|
+
props: options.props ?? { pageProps: options.pageProps },
|
|
73
74
|
page: options.routePattern,
|
|
74
75
|
query: options.params,
|
|
75
76
|
buildId: options.buildId,
|
|
@@ -171,6 +172,7 @@ function applyGsspHeaders(headers, gsspRes, statusCode) {
|
|
|
171
172
|
return statusCode ?? gsspRes.statusCode;
|
|
172
173
|
}
|
|
173
174
|
async function renderPagesPageResponse(options) {
|
|
175
|
+
const renderProps = options.props ?? { pageProps: options.pageProps };
|
|
174
176
|
options.resetSSRHead?.();
|
|
175
177
|
await options.flushPreloads?.();
|
|
176
178
|
const fontHeadHTML = buildPagesFontHeadHtml(options.getFontLinks(), options.fontPreloads, options.getFontStyles(), options.scriptNonce);
|
|
@@ -179,6 +181,7 @@ async function renderPagesPageResponse(options) {
|
|
|
179
181
|
i18n: options.i18n,
|
|
180
182
|
isFallback: options.isFallback,
|
|
181
183
|
pageProps: options.pageProps,
|
|
184
|
+
props: renderProps,
|
|
182
185
|
params: options.params,
|
|
183
186
|
routePattern: options.routePattern,
|
|
184
187
|
safeJsonStringify: options.safeJsonStringify,
|
|
@@ -205,7 +208,7 @@ async function renderPagesPageResponse(options) {
|
|
|
205
208
|
controller.close();
|
|
206
209
|
} });
|
|
207
210
|
else {
|
|
208
|
-
const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(
|
|
211
|
+
const pageElement = withScriptNonce(React.createElement(React.Fragment, null, options.createPageElement(renderProps)), options.scriptNonce);
|
|
209
212
|
bodyStream = await options.renderToReadableStream(pageElement);
|
|
210
213
|
}
|
|
211
214
|
if (documentRenderPage.status === "skipped") await callDocumentGetInitialProps(options.DocumentComponent, options.setDocumentInitialHead);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { addBasePathToPathname, hasBasePath } from "../utils/base-path.js";
|
|
2
2
|
import { applyMiddlewareRequestHeaders, isExternalUrl, matchRedirect, matchRewrite, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "../config/config-matchers.js";
|
|
3
|
-
import { applyConfigHeadersToHeaderRecord, normalizeTrailingSlash } from "./request-pipeline.js";
|
|
3
|
+
import { applyConfigHeadersToHeaderRecord, cloneRequestWithUrl, normalizeTrailingSlash } from "./request-pipeline.js";
|
|
4
4
|
import { mergeRewriteQuery } from "../utils/query.js";
|
|
5
5
|
import { normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./pages-i18n.js";
|
|
6
6
|
import { mergeHeaders } from "./worker-utils.js";
|
|
@@ -68,7 +68,8 @@ async function runPagesRequest(request, deps) {
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
const originalResolvedUrl = pathname + search;
|
|
72
|
+
let resolvedUrl = originalResolvedUrl;
|
|
72
73
|
const middlewareHeaders = {};
|
|
73
74
|
let middlewareStatus;
|
|
74
75
|
if (typeof deps.runMiddleware === "function") {
|
|
@@ -114,7 +115,12 @@ async function runPagesRequest(request, deps) {
|
|
|
114
115
|
}
|
|
115
116
|
const { postMwReqCtx, request: postMwReq } = applyMiddlewareRequestHeaders(middlewareHeaders, request, { preserveCredentialHeaders: isExternalUrl(resolvedUrl) });
|
|
116
117
|
request = postMwReq;
|
|
117
|
-
|
|
118
|
+
const pathnameForResolvedUrl = (value) => value.split("#", 1)[0].split("?", 1)[0];
|
|
119
|
+
const rewriteRequestContext = () => ({
|
|
120
|
+
...postMwReqCtx,
|
|
121
|
+
query: new URL(resolvedUrl, url).searchParams
|
|
122
|
+
});
|
|
123
|
+
let resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
118
124
|
const matchResolvedPathname = (p) => i18nConfig ? normalizeDefaultLocalePathname(p, i18nConfig, { hostname: requestHostname }) : p;
|
|
119
125
|
if (configHeaders.length) applyConfigHeadersToHeaderRecord(middlewareHeaders, {
|
|
120
126
|
configHeaders,
|
|
@@ -130,15 +136,15 @@ async function runPagesRequest(request, deps) {
|
|
|
130
136
|
if (await deps.serveStaticFile(pathname, middlewareHeaders)) return { type: "handled" };
|
|
131
137
|
}
|
|
132
138
|
let configRewriteFired = false;
|
|
133
|
-
|
|
134
|
-
const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname),
|
|
139
|
+
for (const rewrite of configRewrites.beforeFiles ?? []) {
|
|
140
|
+
const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
135
141
|
if (rewritten) {
|
|
136
142
|
if (isExternalUrl(rewritten)) return {
|
|
137
143
|
type: "response",
|
|
138
144
|
response: await proxyExternal(request, rewritten)
|
|
139
145
|
};
|
|
140
146
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
141
|
-
resolvedPathname = resolvedUrl
|
|
147
|
+
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
142
148
|
configRewriteFired = true;
|
|
143
149
|
}
|
|
144
150
|
}
|
|
@@ -151,34 +157,61 @@ async function runPagesRequest(request, deps) {
|
|
|
151
157
|
};
|
|
152
158
|
const apiLookupUrl = stripI18nLocaleForApiRoute(resolvedUrl, i18nConfig);
|
|
153
159
|
const apiLookupPathname = apiLookupUrl.split("?")[0];
|
|
154
|
-
if (apiLookupPathname.startsWith("/api/") || apiLookupPathname === "/api") if (typeof deps.handleApi === "function")
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
if (apiLookupPathname.startsWith("/api/") || apiLookupPathname === "/api") if (typeof deps.handleApi === "function") {
|
|
161
|
+
let apiRequest = request;
|
|
162
|
+
if (basePath && hadBasePath) {
|
|
163
|
+
const apiRequestUrl = new URL(request.url);
|
|
164
|
+
apiRequestUrl.pathname = addBasePathToPathname(apiRequestUrl.pathname, basePath);
|
|
165
|
+
apiRequest = cloneRequestWithUrl(request, apiRequestUrl.toString());
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
type: "response",
|
|
169
|
+
defaultContentType: "application/octet-stream",
|
|
170
|
+
response: mergeHeaders(await deps.handleApi(apiRequest, apiLookupUrl, deps.ctx ?? null), middlewareHeaders, middlewareStatus)
|
|
171
|
+
};
|
|
172
|
+
} else return {
|
|
160
173
|
type: "api",
|
|
161
174
|
apiUrl: apiLookupUrl,
|
|
162
175
|
stagedHeaders: middlewareHeaders,
|
|
163
176
|
requestHeaders: request.headers,
|
|
164
177
|
middlewareStatus
|
|
165
178
|
};
|
|
166
|
-
|
|
179
|
+
let pageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
|
|
167
180
|
let resolvedPathnameChanged = false;
|
|
168
|
-
if (
|
|
169
|
-
const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname),
|
|
181
|
+
if (!pageMatch || pageMatch.route.isDynamic) for (const rewrite of configRewrites.afterFiles ?? []) {
|
|
182
|
+
const rewritten = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
170
183
|
if (rewritten) {
|
|
171
184
|
if (isExternalUrl(rewritten)) return {
|
|
172
185
|
type: "response",
|
|
173
186
|
response: await proxyExternal(request, rewritten)
|
|
174
187
|
};
|
|
175
188
|
resolvedUrl = mergeRewriteQuery(resolvedUrl, rewritten);
|
|
176
|
-
resolvedPathname = resolvedUrl
|
|
189
|
+
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
177
190
|
resolvedPathnameChanged = true;
|
|
191
|
+
pageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
|
|
192
|
+
if (pageMatch) break;
|
|
178
193
|
}
|
|
179
194
|
}
|
|
195
|
+
const refreshDataRewriteHeader = () => {
|
|
196
|
+
if ((isDataReq || isDataRequest) && resolvedUrl !== originalResolvedUrl && !isExternalUrl(resolvedUrl)) middlewareHeaders["x-nextjs-rewrite"] = resolvedUrl;
|
|
197
|
+
else delete middlewareHeaders["x-nextjs-rewrite"];
|
|
198
|
+
};
|
|
199
|
+
refreshDataRewriteHeader();
|
|
180
200
|
if (typeof deps.renderPage === "function") {
|
|
181
|
-
|
|
201
|
+
let renderPageMatch = pageMatch;
|
|
202
|
+
if ((isDataReq || isDataRequest) && !renderPageMatch && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
203
|
+
const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
204
|
+
if (!fallbackRewrite) continue;
|
|
205
|
+
if (isExternalUrl(fallbackRewrite)) return {
|
|
206
|
+
type: "response",
|
|
207
|
+
response: await proxyExternal(request, fallbackRewrite)
|
|
208
|
+
};
|
|
209
|
+
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
210
|
+
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
211
|
+
renderPageMatch = deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null;
|
|
212
|
+
refreshDataRewriteHeader();
|
|
213
|
+
if (renderPageMatch) break;
|
|
214
|
+
}
|
|
182
215
|
const shouldDeferErrorPageOnMiss = !isDataReq && !isDataRequest && !!deps.matchPageRoute && !renderPageMatch;
|
|
183
216
|
const initialRenderOptions = shouldDeferErrorPageOnMiss ? { renderErrorPageOnMiss: false } : isDataReq ? { isDataReq: true } : void 0;
|
|
184
217
|
const stagedHeaders = new Headers();
|
|
@@ -186,16 +219,18 @@ async function runPagesRequest(request, deps) {
|
|
|
186
219
|
else stagedHeaders.set(k, v);
|
|
187
220
|
let response = await deps.renderPage(request, resolvedUrl, initialRenderOptions, stagedHeaders);
|
|
188
221
|
let matchedFallbackRewrite = false;
|
|
189
|
-
if (response.status === 404 && shouldDeferErrorPageOnMiss && configRewrites.fallback?.length) {
|
|
190
|
-
const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname),
|
|
191
|
-
if (fallbackRewrite)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
222
|
+
if (response.status === 404 && shouldDeferErrorPageOnMiss && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
223
|
+
const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
224
|
+
if (!fallbackRewrite) continue;
|
|
225
|
+
if (isExternalUrl(fallbackRewrite)) return {
|
|
226
|
+
type: "response",
|
|
227
|
+
response: await proxyExternal(request, fallbackRewrite)
|
|
228
|
+
};
|
|
229
|
+
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
230
|
+
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
231
|
+
response = await deps.renderPage(request, resolvedUrl, void 0, stagedHeaders);
|
|
232
|
+
matchedFallbackRewrite = true;
|
|
233
|
+
if (response.status !== 404) break;
|
|
199
234
|
}
|
|
200
235
|
if (response.status === 404 && shouldDeferErrorPageOnMiss && !matchedFallbackRewrite) response = await deps.renderPage(request, resolvedUrl, void 0, stagedHeaders);
|
|
201
236
|
const merged = mergeHeaders(response, middlewareHeaders, middlewareStatus);
|
|
@@ -206,16 +241,18 @@ async function runPagesRequest(request, deps) {
|
|
|
206
241
|
defaultContentType: "text/html"
|
|
207
242
|
};
|
|
208
243
|
}
|
|
209
|
-
if (!(resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch) && configRewrites.fallback?.length) {
|
|
210
|
-
const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname),
|
|
211
|
-
if (fallbackRewrite)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
244
|
+
if (!(resolvedPathnameChanged ? deps.matchPageRoute ? deps.matchPageRoute(resolvedPathname, request) : null : pageMatch) && configRewrites.fallback?.length) for (const rewrite of configRewrites.fallback) {
|
|
245
|
+
const fallbackRewrite = matchRewrite(matchResolvedPathname(resolvedPathname), [rewrite], rewriteRequestContext(), basePathState);
|
|
246
|
+
if (!fallbackRewrite) continue;
|
|
247
|
+
if (isExternalUrl(fallbackRewrite)) return {
|
|
248
|
+
type: "response",
|
|
249
|
+
response: await proxyExternal(request, fallbackRewrite)
|
|
250
|
+
};
|
|
251
|
+
resolvedUrl = mergeRewriteQuery(resolvedUrl, fallbackRewrite);
|
|
252
|
+
resolvedPathname = pathnameForResolvedUrl(resolvedUrl);
|
|
253
|
+
if (deps.matchPageRoute?.(resolvedPathname, request)) break;
|
|
218
254
|
}
|
|
255
|
+
refreshDataRewriteHeader();
|
|
219
256
|
return {
|
|
220
257
|
type: "render",
|
|
221
258
|
resolvedUrl,
|
|
@@ -4,28 +4,12 @@ declare global {
|
|
|
4
4
|
}
|
|
5
5
|
declare function normalizePregeneratedPathname(pathname: string): string;
|
|
6
6
|
declare function clearPregeneratedConcretePaths(): void;
|
|
7
|
-
/**
|
|
8
|
-
* Records a concrete URL path for a route pattern. The pathname is normalized
|
|
9
|
-
* here so this is the single source of truth: every caller — the Worker global
|
|
10
|
-
* table and the Node `seed-cache.ts` path — stores the canonical form that
|
|
11
|
-
* matches the runtime `cleanPathname` lookup without having to pre-normalize.
|
|
12
|
-
*/
|
|
13
7
|
declare function addPregeneratedConcretePath(routePattern: string, pathname: string): void;
|
|
14
|
-
/**
|
|
15
|
-
* Returns the live backing `Set` for a route pattern (not a copy) to keep
|
|
16
|
-
* lookups allocation-free on the serving hot path. The `ReadonlySet` type
|
|
17
|
-
* forbids mutation at compile time. Callers must treat the result as
|
|
18
|
-
* point-in-time and must NOT retain it across a re-seed: each
|
|
19
|
-
* `initPregeneratedPathsFromGlobals` call runs `clearPregeneratedConcretePaths`,
|
|
20
|
-
* which empties the map, leaving any previously-returned reference stale. Read
|
|
21
|
-
* it, use it, drop it — never cache the reference.
|
|
22
|
-
*/
|
|
23
8
|
declare function getRenderedConcreteUrlPathsForRoute(routePattern: string): ReadonlySet<string> | undefined;
|
|
24
9
|
/**
|
|
25
10
|
* Populate the registry from `globalThis.__VINEXT_PREGENERATED_CONCRETE_PATHS`.
|
|
26
11
|
* No-op when the global is not set (Node path — seed-cache handles it later).
|
|
27
|
-
*
|
|
28
|
-
* runtime `cleanPathname`.
|
|
12
|
+
* Pathnames are normalised so they match the runtime `cleanPathname`.
|
|
29
13
|
*/
|
|
30
14
|
declare function initPregeneratedPathsFromGlobals(): void;
|
|
31
15
|
//#endregion
|
|
@@ -16,38 +16,21 @@ const concreteUrlPathsByRoute = /* @__PURE__ */ new Map();
|
|
|
16
16
|
function clearPregeneratedConcretePaths() {
|
|
17
17
|
concreteUrlPathsByRoute.clear();
|
|
18
18
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Records a concrete URL path for a route pattern. The pathname is normalized
|
|
21
|
-
* here so this is the single source of truth: every caller — the Worker global
|
|
22
|
-
* table and the Node `seed-cache.ts` path — stores the canonical form that
|
|
23
|
-
* matches the runtime `cleanPathname` lookup without having to pre-normalize.
|
|
24
|
-
*/
|
|
25
19
|
function addPregeneratedConcretePath(routePattern, pathname) {
|
|
26
|
-
const normalized = normalizePregeneratedPathname(pathname);
|
|
27
20
|
let paths = concreteUrlPathsByRoute.get(routePattern);
|
|
28
21
|
if (!paths) {
|
|
29
22
|
paths = /* @__PURE__ */ new Set();
|
|
30
23
|
concreteUrlPathsByRoute.set(routePattern, paths);
|
|
31
24
|
}
|
|
32
|
-
paths.add(
|
|
25
|
+
paths.add(normalizePregeneratedPathname(pathname));
|
|
33
26
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Returns the live backing `Set` for a route pattern (not a copy) to keep
|
|
36
|
-
* lookups allocation-free on the serving hot path. The `ReadonlySet` type
|
|
37
|
-
* forbids mutation at compile time. Callers must treat the result as
|
|
38
|
-
* point-in-time and must NOT retain it across a re-seed: each
|
|
39
|
-
* `initPregeneratedPathsFromGlobals` call runs `clearPregeneratedConcretePaths`,
|
|
40
|
-
* which empties the map, leaving any previously-returned reference stale. Read
|
|
41
|
-
* it, use it, drop it — never cache the reference.
|
|
42
|
-
*/
|
|
43
27
|
function getRenderedConcreteUrlPathsForRoute(routePattern) {
|
|
44
28
|
return concreteUrlPathsByRoute.get(routePattern);
|
|
45
29
|
}
|
|
46
30
|
/**
|
|
47
31
|
* Populate the registry from `globalThis.__VINEXT_PREGENERATED_CONCRETE_PATHS`.
|
|
48
32
|
* No-op when the global is not set (Node path — seed-cache handles it later).
|
|
49
|
-
*
|
|
50
|
-
* runtime `cleanPathname`.
|
|
33
|
+
* Pathnames are normalised so they match the runtime `cleanPathname`.
|
|
51
34
|
*/
|
|
52
35
|
function initPregeneratedPathsFromGlobals() {
|
|
53
36
|
const raw = globalThis.__VINEXT_PREGENERATED_CONCRETE_PATHS;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/server/prerender-manifest.d.ts
|
|
2
|
+
type PrerenderManifestRoute = {
|
|
3
|
+
route: string;
|
|
4
|
+
status?: string;
|
|
5
|
+
revalidate?: number | false;
|
|
6
|
+
expire?: number;
|
|
7
|
+
path?: string;
|
|
8
|
+
router?: string;
|
|
9
|
+
fallback?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type PrerenderManifest = {
|
|
12
|
+
buildId?: string;
|
|
13
|
+
trailingSlash?: boolean;
|
|
14
|
+
routes?: PrerenderManifestRoute[];
|
|
15
|
+
};
|
|
16
|
+
declare function readPrerenderManifest(manifestPath: string): PrerenderManifest | null;
|
|
17
|
+
declare function getRenderedAppRoutes(routes: PrerenderManifestRoute[]): PrerenderManifestRoute[];
|
|
18
|
+
/**
|
|
19
|
+
* Returns true when `pathname` contains bracket-delimited route params,
|
|
20
|
+
* indicating it is a fallback-shell placeholder (e.g. `/en/blog/[slug]`)
|
|
21
|
+
* rather than a concrete rendered URL.
|
|
22
|
+
*/
|
|
23
|
+
declare function isFallbackShellArtifactPath(pathname: string, route?: PrerenderManifestRoute): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Build the pregenerated concrete-path payload table from a prerender manifest.
|
|
26
|
+
*
|
|
27
|
+
* Filters out fallback-shell placeholder paths and groups remaining concrete
|
|
28
|
+
* paths by route pattern. Returns an empty array when the manifest has no
|
|
29
|
+
* rendered App routes or all routes are fallback-shell artifacts.
|
|
30
|
+
*/
|
|
31
|
+
declare function buildPregeneratedConcretePathTable(manifest: PrerenderManifest): Array<[string, string[]]>;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { buildPregeneratedConcretePathTable, getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
//#region src/server/prerender-manifest.ts
|
|
3
|
+
function readPrerenderManifest(manifestPath) {
|
|
4
|
+
if (!fs.existsSync(manifestPath)) return null;
|
|
5
|
+
try {
|
|
6
|
+
return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
7
|
+
} catch (error) {
|
|
8
|
+
console.warn(`[vinext] Failed to read prerender manifest at ${manifestPath}:`, error);
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function getRenderedAppRoutes(routes) {
|
|
13
|
+
return routes.filter((r) => r.status === "rendered" && r.router === "app");
|
|
14
|
+
}
|
|
15
|
+
function groupRoutesByPattern(routes) {
|
|
16
|
+
const byPattern = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const r of routes) {
|
|
18
|
+
const pathname = r.path ?? r.route;
|
|
19
|
+
const existing = byPattern.get(r.route);
|
|
20
|
+
if (existing) existing.push(pathname);
|
|
21
|
+
else byPattern.set(r.route, [pathname]);
|
|
22
|
+
}
|
|
23
|
+
return byPattern;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns true when `pathname` contains bracket-delimited route params,
|
|
27
|
+
* indicating it is a fallback-shell placeholder (e.g. `/en/blog/[slug]`)
|
|
28
|
+
* rather than a concrete rendered URL.
|
|
29
|
+
*/
|
|
30
|
+
function isFallbackShellArtifactPath(pathname, route) {
|
|
31
|
+
if (route?.fallback === true) return true;
|
|
32
|
+
if (route?.fallback === void 0) {
|
|
33
|
+
if (process.env.NODE_ENV !== "production") console.warn("[vinext] Legacy manifest detected: missing `fallback` flag for route. Using bracket heuristic for fallback-shell detection. A concrete URL containing literal brackets may be misclassified as a fallback shell.");
|
|
34
|
+
return pathname.includes("[") || pathname.includes("]");
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build the pregenerated concrete-path payload table from a prerender manifest.
|
|
40
|
+
*
|
|
41
|
+
* Filters out fallback-shell placeholder paths and groups remaining concrete
|
|
42
|
+
* paths by route pattern. Returns an empty array when the manifest has no
|
|
43
|
+
* rendered App routes or all routes are fallback-shell artifacts.
|
|
44
|
+
*/
|
|
45
|
+
function buildPregeneratedConcretePathTable(manifest) {
|
|
46
|
+
const routes = manifest?.routes;
|
|
47
|
+
if (!routes?.length) return [];
|
|
48
|
+
const concreteRoutes = getRenderedAppRoutes(routes).filter((r) => {
|
|
49
|
+
return !isFallbackShellArtifactPath(r.path ?? r.route, r);
|
|
50
|
+
});
|
|
51
|
+
return Array.from(groupRoutesByPattern(concreteRoutes).entries());
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { buildPregeneratedConcretePathTable, getRenderedAppRoutes, isFallbackShellArtifactPath, readPrerenderManifest };
|
|
@@ -5,7 +5,6 @@ type PrerenderRouteParamsPayload = {
|
|
|
5
5
|
params: PrerenderRouteParams;
|
|
6
6
|
routePattern: string;
|
|
7
7
|
};
|
|
8
|
-
/** @public exported for #1716 serving consumers; not yet referenced in-repo */
|
|
9
8
|
type PrerenderRouteParamsRouteMatch = {
|
|
10
9
|
kind: "exact";
|
|
11
10
|
params: PrerenderRouteParams;
|
|
@@ -21,4 +20,4 @@ declare function prerenderRouteParamsPayloadMatchesRoute(payload: PrerenderRoute
|
|
|
21
20
|
declare function matchPrerenderRouteParamsPayload(payload: PrerenderRouteParamsPayload | null, routePattern: string, params: PrerenderRouteParams): PrerenderRouteParamsRouteMatch | null;
|
|
22
21
|
declare function encodePrerenderRouteParams(pattern: string, params: PrerenderRouteParams, fallbackParamNames?: readonly string[]): PrerenderRouteParamsPayload | null;
|
|
23
22
|
//#endregion
|
|
24
|
-
export { PrerenderRouteParams, PrerenderRouteParamsPayload,
|
|
23
|
+
export { PrerenderRouteParams, PrerenderRouteParamsPayload, encodePrerenderRouteParams, matchPrerenderRouteParamsPayload, prerenderRouteParamsPayloadMatchesRoute, readTrustedPrerenderRouteParams, readTrustedPrerenderRouteParamsFromHeaders, serializePrerenderRouteParamsHeader };
|