vinext 1.0.0-beta.5 → 1.0.0-beta.6
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-paths.js +3 -4
- package/dist/build/prerender-phase.d.ts +15 -0
- package/dist/build/prerender-phase.js +37 -0
- package/dist/build/prerender-server-entry.js +3 -3
- package/dist/build/prerender-server-pool.js +2 -0
- package/dist/build/prerender.d.ts +6 -2
- package/dist/build/prerender.js +93 -17
- package/dist/build/run-prerender.js +9 -6
- package/dist/client/vinext-next-data.d.ts +2 -0
- package/dist/config/next-config.js +24 -7
- package/dist/deps/.pnpm/image-size@2.0.2/deps/image-size/dist/index.js +808 -0
- package/dist/entries/app-browser-entry.js +2 -1
- package/dist/entries/app-rsc-entry.js +25 -0
- package/dist/entries/pages-client-entry.js +8 -3
- package/dist/index.js +82 -159
- package/dist/plugins/pages-node-externals.d.ts +23 -0
- package/dist/plugins/pages-node-externals.js +206 -0
- package/dist/plugins/transitive-externals.d.ts +24 -0
- package/dist/plugins/transitive-externals.js +121 -0
- package/dist/plugins/typeof-window.d.ts +11 -1
- package/dist/plugins/typeof-window.js +141 -13
- package/dist/plugins/use-cache-callable.d.ts +12 -0
- package/dist/plugins/use-cache-callable.js +209 -0
- package/dist/server/api-handler.js +1 -1
- package/dist/server/app-browser-entry.js +5 -1
- package/dist/server/app-page-boundary-render.js +4 -7
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +5 -9
- package/dist/server/app-page-cache-render.d.ts +1 -0
- package/dist/server/app-page-cache-render.js +3 -1
- package/dist/server/app-page-cache.d.ts +2 -1
- package/dist/server/app-page-cache.js +11 -4
- package/dist/server/app-page-dispatch.js +3 -2
- package/dist/server/app-page-execution.js +19 -6
- package/dist/server/app-page-render.js +4 -1
- package/dist/server/app-page-response.js +7 -14
- package/dist/server/app-page-stream.d.ts +12 -0
- package/dist/server/app-page-stream.js +10 -3
- package/dist/server/app-prerender-endpoints.d.ts +1 -0
- package/dist/server/app-prerender-endpoints.js +12 -0
- package/dist/server/app-response-header-provenance.d.ts +13 -0
- package/dist/server/app-response-header-provenance.js +26 -0
- package/dist/server/app-route-handler-cache.d.ts +1 -0
- package/dist/server/app-route-handler-cache.js +2 -2
- package/dist/server/app-route-handler-dispatch.js +4 -2
- package/dist/server/app-route-handler-execution.js +10 -6
- package/dist/server/app-route-handler-policy.d.ts +1 -0
- package/dist/server/app-route-handler-response.d.ts +3 -1
- package/dist/server/app-route-handler-response.js +15 -5
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +218 -84
- package/dist/server/app-route-request-built-ins.d.ts +16 -0
- package/dist/server/app-route-request-built-ins.js +41 -0
- package/dist/server/app-router-entry.js +2 -2
- package/dist/server/app-rsc-cache-busting.d.ts +2 -0
- package/dist/server/app-rsc-cache-busting.js +24 -16
- package/dist/server/app-rsc-handler.d.ts +2 -0
- package/dist/server/app-rsc-handler.js +13 -11
- package/dist/server/app-rsc-response-finalizer.d.ts +2 -0
- package/dist/server/app-rsc-response-finalizer.js +4 -1
- package/dist/server/app-rsc-state-fingerprint.d.ts +14 -0
- package/dist/server/app-rsc-state-fingerprint.js +13 -0
- package/dist/server/app-server-action-execution.js +2 -2
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +15 -3
- package/dist/server/app-ssr-stream.d.ts +6 -1
- package/dist/server/app-ssr-stream.js +28 -4
- package/dist/server/cache-control.d.ts +11 -7
- package/dist/server/cache-control.js +23 -12
- package/dist/server/config-headers.d.ts +4 -0
- package/dist/server/config-headers.js +19 -3
- package/dist/server/dev-server.js +27 -10
- package/dist/server/headers.d.ts +7 -1
- package/dist/server/headers.js +9 -2
- package/dist/server/http-error-responses.d.ts +1 -1
- package/dist/server/http-error-responses.js +7 -2
- package/dist/server/metadata-route-build-data.js +1 -1
- package/dist/server/metadata-route-cache-policy.d.ts +6 -0
- package/dist/server/metadata-route-cache-policy.js +6 -0
- package/dist/server/metadata-route-response.d.ts +26 -1
- package/dist/server/metadata-route-response.js +219 -6
- package/dist/server/metadata-routes.js +1 -1
- package/dist/server/middleware-response-headers.js +4 -2
- package/dist/server/pages-dev-hydration.js +11 -4
- package/dist/server/pages-page-handler.d.ts +3 -1
- package/dist/server/pages-page-handler.js +4 -15
- package/dist/server/pages-page-response.js +10 -5
- package/dist/server/prerender-cache-life-header.d.ts +11 -0
- package/dist/server/prerender-cache-life-header.js +18 -0
- package/dist/server/prerender-manifest.d.ts +5 -2
- package/dist/server/prerender-manifest.js +4 -1
- package/dist/server/prod-server.js +6 -10
- package/dist/server/request-pipeline.js +2 -0
- package/dist/server/seed-cache.d.ts +4 -1
- package/dist/server/seed-cache.js +28 -4
- package/dist/server/worker-utils.js +1 -1
- package/dist/shims/cache-callable-runtime.d.ts +11 -0
- package/dist/shims/cache-callable-runtime.js +30 -0
- package/dist/shims/cache-request-state.d.ts +4 -1
- package/dist/shims/cache-request-state.js +6 -1
- package/dist/shims/cache-runtime.d.ts +6 -1
- package/dist/shims/cache-runtime.js +114 -24
- package/dist/shims/cache.d.ts +2 -2
- package/dist/shims/cache.js +2 -2
- package/dist/shims/cdn-cache.d.ts +18 -6
- package/dist/shims/cdn-cache.js +4 -2
- package/dist/shims/fetch-cache.js +4 -3
- package/dist/shims/font-local.js +3 -3
- package/dist/shims/head.d.ts +16 -1
- package/dist/shims/head.js +70 -8
- package/dist/shims/internal/app-route-prefetch-policy.d.ts +2 -0
- package/dist/shims/internal/app-route-prefetch-policy.js +9 -3
- package/dist/shims/internal/pages-data-target.d.ts +1 -1
- package/dist/shims/internal/pages-data-target.js +18 -5
- package/dist/shims/link.js +49 -54
- package/dist/shims/navigation-context-state.d.ts +4 -0
- package/dist/shims/navigation.d.ts +28 -1
- package/dist/shims/navigation.js +96 -10
- package/dist/shims/root-params.d.ts +3 -1
- package/dist/shims/root-params.js +7 -1
- package/dist/shims/router.js +177 -76
- package/dist/shims/server.js +2 -1
- package/dist/utils/encode-cache-tag.d.ts +1 -1
- package/dist/utils/encode-cache-tag.js +1 -1
- package/dist/utils/prerender-output-paths.d.ts +3 -1
- package/dist/utils/prerender-output-paths.js +6 -1
- package/package.json +4 -4
|
@@ -9,6 +9,7 @@ import { BLOCKED_PAGES, PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
|
|
|
9
9
|
import { loadNextConfig, resolveNextConfig } from "../config/next-config.js";
|
|
10
10
|
import { readPrerenderSecret } from "./server-manifest.js";
|
|
11
11
|
import { startProdServer } from "../server/prod-server.js";
|
|
12
|
+
import { enterPrerenderPhase } from "./prerender-phase.js";
|
|
12
13
|
import { buildUrlFromParams, resolveParentParams } from "./prerender.js";
|
|
13
14
|
import fs from "node:fs";
|
|
14
15
|
//#region src/build/prerender-paths.ts
|
|
@@ -96,15 +97,13 @@ async function shouldStartPathDiscoveryServer(options) {
|
|
|
96
97
|
return false;
|
|
97
98
|
}
|
|
98
99
|
async function withPrerenderEndpoints(fn) {
|
|
99
|
-
const
|
|
100
|
+
const restorePrerenderPhase = enterPrerenderPhase();
|
|
100
101
|
const previousPathDiscoveryFlag = process.env[PRERENDER_PATH_DISCOVERY_ENV];
|
|
101
|
-
process.env.VINEXT_PRERENDER = "1";
|
|
102
102
|
process.env[PRERENDER_PATH_DISCOVERY_ENV] = "1";
|
|
103
103
|
try {
|
|
104
104
|
return await fn();
|
|
105
105
|
} finally {
|
|
106
|
-
|
|
107
|
-
else process.env.VINEXT_PRERENDER = previousPrerenderFlag;
|
|
106
|
+
restorePrerenderPhase();
|
|
108
107
|
if (previousPathDiscoveryFlag === void 0) delete process.env[PRERENDER_PATH_DISCOVERY_ENV];
|
|
109
108
|
else process.env[PRERENDER_PATH_DISCOVERY_ENV] = previousPathDiscoveryFlag;
|
|
110
109
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/build/prerender-phase.d.ts
|
|
2
|
+
type PrerenderPhaseEnv = {
|
|
3
|
+
NEXT_PHASE?: string;
|
|
4
|
+
NODE_ENV?: string;
|
|
5
|
+
VINEXT_PRERENDER?: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Enter the same process environment phase that Next.js exposes while its
|
|
9
|
+
* static workers execute application code. The returned cleanup is nest-safe:
|
|
10
|
+
* direct prerender helpers can run inside the CLI's broader build scope without
|
|
11
|
+
* overwriting the caller's prior phase when they finish.
|
|
12
|
+
*/
|
|
13
|
+
declare function enterPrerenderPhase(env?: PrerenderPhaseEnv): () => void;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { enterPrerenderPhase };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
|
|
2
|
+
//#region src/build/prerender-phase.ts
|
|
3
|
+
const activePrerenderPhases = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
/**
|
|
5
|
+
* Enter the same process environment phase that Next.js exposes while its
|
|
6
|
+
* static workers execute application code. The returned cleanup is nest-safe:
|
|
7
|
+
* direct prerender helpers can run inside the CLI's broader build scope without
|
|
8
|
+
* overwriting the caller's prior phase when they finish.
|
|
9
|
+
*/
|
|
10
|
+
function enterPrerenderPhase(env = process.env) {
|
|
11
|
+
let state = activePrerenderPhases.get(env);
|
|
12
|
+
if (state) state.depth += 1;
|
|
13
|
+
else {
|
|
14
|
+
state = {
|
|
15
|
+
depth: 1,
|
|
16
|
+
previousPrerenderFlag: env.VINEXT_PRERENDER,
|
|
17
|
+
previousNextPhase: env.NEXT_PHASE
|
|
18
|
+
};
|
|
19
|
+
activePrerenderPhases.set(env, state);
|
|
20
|
+
}
|
|
21
|
+
let restored = false;
|
|
22
|
+
env.VINEXT_PRERENDER = "1";
|
|
23
|
+
env.NEXT_PHASE = PHASE_PRODUCTION_BUILD;
|
|
24
|
+
return () => {
|
|
25
|
+
if (restored) return;
|
|
26
|
+
restored = true;
|
|
27
|
+
state.depth -= 1;
|
|
28
|
+
if (state.depth > 0) return;
|
|
29
|
+
activePrerenderPhases.delete(env);
|
|
30
|
+
if (state.previousPrerenderFlag === void 0) delete env.VINEXT_PRERENDER;
|
|
31
|
+
else env.VINEXT_PRERENDER = state.previousPrerenderFlag;
|
|
32
|
+
if (state.previousNextPhase === void 0) delete env.NEXT_PHASE;
|
|
33
|
+
else env.NEXT_PHASE = state.previousNextPhase;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { enterPrerenderPhase };
|
|
@@ -11,9 +11,9 @@ import { startProdServer } from "../server/prod-server.js";
|
|
|
11
11
|
* vinext production server on an ephemeral port and reports it to the parent
|
|
12
12
|
* over IPC. The parent then load-balances per-route fetches across the pool.
|
|
13
13
|
*
|
|
14
|
-
* `VINEXT_PRERENDER` / `VINEXT_PRERENDER_OUTDIR` are passed via
|
|
15
|
-
* they are set before any module loads (some server
|
|
16
|
-
* import time).
|
|
14
|
+
* `VINEXT_PRERENDER` / `NEXT_PHASE` / `VINEXT_PRERENDER_OUTDIR` are passed via
|
|
15
|
+
* the fork env so they are set before any module loads (some server and user
|
|
16
|
+
* modules read the phase at import time).
|
|
17
17
|
*/
|
|
18
18
|
async function main() {
|
|
19
19
|
const outDir = process.env.VINEXT_PRERENDER_OUTDIR;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
|
+
import { PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
import os from "node:os";
|
|
@@ -105,6 +106,7 @@ async function startPrerenderServerPool(outDir, size, entry = WORKER_ENTRY) {
|
|
|
105
106
|
env: {
|
|
106
107
|
...process.env,
|
|
107
108
|
VINEXT_PRERENDER: "1",
|
|
109
|
+
NEXT_PHASE: PHASE_PRODUCTION_BUILD,
|
|
108
110
|
VINEXT_PRERENDER_OUTDIR: outDir
|
|
109
111
|
},
|
|
110
112
|
stdio: [
|
|
@@ -27,11 +27,15 @@ type PrerenderRouteResult = {
|
|
|
27
27
|
*/
|
|
28
28
|
path?: string;
|
|
29
29
|
/** Which router produced this route. Used by cache seeding. */
|
|
30
|
-
router: "app" | "pages";
|
|
30
|
+
router: "app" | "pages" | "metadata";
|
|
31
31
|
/** Response headers that must be replayed with the prerendered artifact. */
|
|
32
|
-
headers?: Record<string, string>;
|
|
32
|
+
headers?: Record<string, string | string[]>;
|
|
33
|
+
/** Original HTTP status for prerendered App Route-style responses. */
|
|
34
|
+
responseStatus?: number;
|
|
33
35
|
/** Cache tags collected while rendering this route. */
|
|
34
36
|
tags?: string[];
|
|
37
|
+
/** Raw app-tree segments used to derive App Route implicit tags. */
|
|
38
|
+
routeSegments?: string[];
|
|
35
39
|
/** Set to true when this is a PPR fallback shell. */
|
|
36
40
|
fallback?: boolean;
|
|
37
41
|
} | {
|
package/dist/build/prerender.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "../deps/.pnpm/pathslash@0.1.0/deps/pathslash/dist/index.js";
|
|
2
2
|
import { createValidFileMatcher, findFileWithExtensions } from "../routing/file-matcher.js";
|
|
3
3
|
import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
|
|
4
|
-
import { NEXT_CACHE_TAGS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER } from "../server/headers.js";
|
|
4
|
+
import { NEXT_CACHE_TAGS_HEADER, VINEXT_METADATA_ROUTE_CACHE_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_PRERENDER_METADATA_ROUTES_PATH } from "../server/headers.js";
|
|
5
5
|
import { classifyAppRoute, classifyPagesRoute, getAppRouteRenderEntryPath } from "./report.js";
|
|
6
6
|
import { resolveClientStaleTimeSeconds } from "../utils/cache-control-metadata.js";
|
|
7
7
|
import { NoOpCacheHandler, getCacheHandler, setCacheHandler } from "../shims/cache-handler.js";
|
|
@@ -15,9 +15,12 @@ import { navigationRuntimeRscBootstrapExpression } from "../server/app-ssr-strea
|
|
|
15
15
|
import { encodePrerenderRouteParams, serializePrerenderRouteParamsHeader } from "../server/prerender-route-params.js";
|
|
16
16
|
import { readPrerenderSecret } from "./server-manifest.js";
|
|
17
17
|
import { createAppPprFallbackShells, markAppPprDynamicFallbackShellHtml } from "../server/app-ppr-fallback-shell.js";
|
|
18
|
-
import { getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
|
|
18
|
+
import { getAppRouteOutputPath, getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
|
|
19
19
|
import { startProdServer } from "../server/prod-server.js";
|
|
20
20
|
import { prerenderPoolAvailable, resolvePrerenderPoolSize, startPrerenderServerPool } from "./prerender-server-pool.js";
|
|
21
|
+
import { enterPrerenderPhase } from "./prerender-phase.js";
|
|
22
|
+
import { buildAppRouteCacheValue } from "../server/app-route-handler-response.js";
|
|
23
|
+
import { isMetadataResponseCacheable } from "../server/metadata-route-cache-policy.js";
|
|
21
24
|
import fs from "node:fs";
|
|
22
25
|
import os from "node:os";
|
|
23
26
|
//#region src/build/prerender.ts
|
|
@@ -265,8 +268,7 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
|
|
|
265
268
|
});
|
|
266
269
|
const previousHandler = getCacheHandler();
|
|
267
270
|
setCacheHandler(new NoOpCacheHandler());
|
|
268
|
-
const
|
|
269
|
-
process.env.VINEXT_PRERENDER = "1";
|
|
271
|
+
const restorePrerenderPhase = enterPrerenderPhase();
|
|
270
272
|
let ownedProdServerHandle = null;
|
|
271
273
|
let renderPool = null;
|
|
272
274
|
try {
|
|
@@ -497,11 +499,13 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
|
|
|
497
499
|
});
|
|
498
500
|
return { routes: results };
|
|
499
501
|
} finally {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
502
|
+
try {
|
|
503
|
+
if (renderPool) await renderPool.close();
|
|
504
|
+
setCacheHandler(previousHandler);
|
|
505
|
+
if (ownedProdServerHandle) await new Promise((resolve) => ownedProdServerHandle.server.close(() => resolve()));
|
|
506
|
+
} finally {
|
|
507
|
+
restorePrerenderPhase();
|
|
508
|
+
}
|
|
505
509
|
}
|
|
506
510
|
}
|
|
507
511
|
/**
|
|
@@ -530,8 +534,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
530
534
|
fs.mkdirSync(outDir, { recursive: true });
|
|
531
535
|
const previousHandler = getCacheHandler();
|
|
532
536
|
setCacheHandler(new NoOpCacheHandler());
|
|
533
|
-
const
|
|
534
|
-
process.env.VINEXT_PRERENDER = "1";
|
|
537
|
+
const restorePrerenderPhase = enterPrerenderPhase();
|
|
535
538
|
const serverDir = path.dirname(rscBundlePath);
|
|
536
539
|
let rscHandler;
|
|
537
540
|
let staticParamsMap = {};
|
|
@@ -743,14 +746,83 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
743
746
|
isSpeculative: false
|
|
744
747
|
});
|
|
745
748
|
}
|
|
749
|
+
if (metadataRoutes.length > 0) {
|
|
750
|
+
const response = await fetch(`${baseUrl}${VINEXT_PRERENDER_METADATA_ROUTES_PATH}`, { headers: secretHeaders });
|
|
751
|
+
const text = await response.text();
|
|
752
|
+
if (!response.ok) throw new Error(`[vinext] Failed to enumerate prerenderable metadata routes: ${parsePrerenderEndpointError(text)}`);
|
|
753
|
+
const metadataEntries = JSON.parse(text);
|
|
754
|
+
if (!Array.isArray(metadataEntries)) throw new Error("[vinext] Invalid prerender metadata route response");
|
|
755
|
+
const queuedMetadataPaths = /* @__PURE__ */ new Set();
|
|
756
|
+
for (const metadataEntry of metadataEntries) {
|
|
757
|
+
if (typeof metadataEntry !== "object" || metadataEntry === null || typeof Reflect.get(metadataEntry, "path") !== "string" || typeof Reflect.get(metadataEntry, "routePattern") !== "string" || !Array.isArray(Reflect.get(metadataEntry, "routeSegments"))) continue;
|
|
758
|
+
const { path: metadataPath, routePattern, routeSegments } = metadataEntry;
|
|
759
|
+
if (!metadataPath.startsWith("/") || !routePattern.startsWith("/") || routeSegments.some((segment) => typeof segment !== "string") || queuedMetadataPaths.has(metadataPath)) continue;
|
|
760
|
+
queuedMetadataPaths.add(metadataPath);
|
|
761
|
+
urlsToRender.push({
|
|
762
|
+
kind: "metadata",
|
|
763
|
+
metadataRouteSegments: routeSegments,
|
|
764
|
+
urlPath: metadataPath,
|
|
765
|
+
routePattern,
|
|
766
|
+
prerenderRouteParams: null,
|
|
767
|
+
revalidate: false,
|
|
768
|
+
isSpeculative: false
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
}
|
|
746
772
|
/**
|
|
747
773
|
* Render a single URL and return its result.
|
|
748
774
|
* `onProgress` is intentionally not called here; the outer loop calls it
|
|
749
775
|
* exactly once per URL after this function returns, keeping the callback
|
|
750
776
|
* at a single, predictable call site.
|
|
751
777
|
*/
|
|
752
|
-
async function renderUrl({ urlPath, routePattern, prerenderRouteParams, revalidate, isSpeculative, isFallback }) {
|
|
778
|
+
async function renderUrl({ kind, metadataRouteSegments, urlPath, routePattern, prerenderRouteParams, revalidate, isSpeculative, isFallback }) {
|
|
753
779
|
try {
|
|
780
|
+
if (kind === "metadata") {
|
|
781
|
+
const request = new Request(`http://localhost${config.basePath ?? ""}${urlPath}`);
|
|
782
|
+
const response = await runWithHeadersContext(headersContextFromRequest(request), () => rscHandler(request));
|
|
783
|
+
if (!response.ok) {
|
|
784
|
+
await response.body?.cancel();
|
|
785
|
+
return {
|
|
786
|
+
route: routePattern,
|
|
787
|
+
status: "error",
|
|
788
|
+
error: `Metadata route returned ${response.status}`
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
const cacheControl = response.headers.get("cache-control") ?? "";
|
|
792
|
+
if (!isMetadataResponseCacheable(response)) {
|
|
793
|
+
await response.body?.cancel();
|
|
794
|
+
return {
|
|
795
|
+
route: routePattern,
|
|
796
|
+
status: "skipped",
|
|
797
|
+
reason: "dynamic"
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
const requestCacheLife = readPrerenderCacheLifeHeader(response.headers);
|
|
801
|
+
const collectedTags = readPrerenderCacheTagsHeader(response.headers);
|
|
802
|
+
const cacheValue = await buildAppRouteCacheValue(response);
|
|
803
|
+
cacheValue.headers[VINEXT_METADATA_ROUTE_CACHE_HEADER] = "1";
|
|
804
|
+
const outputPath = getAppRouteOutputPath(urlPath);
|
|
805
|
+
const fullPath = path.join(outDir, outputPath);
|
|
806
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
807
|
+
fs.writeFileSync(fullPath, new Uint8Array(cacheValue.body));
|
|
808
|
+
const renderedCacheControl = resolveRenderedCacheControl(requestCacheLife ?? {}, cacheControl, config.expireTime);
|
|
809
|
+
const renderedRevalidate = renderedCacheControl.revalidate ?? false;
|
|
810
|
+
const renderedStale = resolveClientStaleTimeSeconds(requestCacheLife ?? void 0);
|
|
811
|
+
return {
|
|
812
|
+
route: routePattern,
|
|
813
|
+
...urlPath === routePattern ? {} : { path: urlPath },
|
|
814
|
+
status: "rendered",
|
|
815
|
+
outputFiles: [outputPath],
|
|
816
|
+
revalidate: renderedRevalidate,
|
|
817
|
+
...typeof renderedRevalidate === "number" ? { expire: renderedCacheControl.expire } : {},
|
|
818
|
+
...renderedStale === void 0 ? {} : { stale: renderedStale },
|
|
819
|
+
router: "metadata",
|
|
820
|
+
headers: cacheValue.headers,
|
|
821
|
+
responseStatus: cacheValue.status,
|
|
822
|
+
routeSegments: metadataRouteSegments ?? [],
|
|
823
|
+
tags: collectedTags
|
|
824
|
+
};
|
|
825
|
+
}
|
|
754
826
|
const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParams);
|
|
755
827
|
const htmlHeaders = new Headers();
|
|
756
828
|
if (prerenderRouteParamsHeader !== null) htmlHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
|
|
@@ -919,11 +991,13 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
919
991
|
...outputFiles.length > 0 ? { outputFiles } : {}
|
|
920
992
|
};
|
|
921
993
|
} finally {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
994
|
+
try {
|
|
995
|
+
if (renderPool) await renderPool.close();
|
|
996
|
+
setCacheHandler(previousHandler);
|
|
997
|
+
if (ownedProdServerHandle) await new Promise((resolve) => ownedProdServerHandle.server.close(() => resolve()));
|
|
998
|
+
} finally {
|
|
999
|
+
restorePrerenderPhase();
|
|
1000
|
+
}
|
|
927
1001
|
}
|
|
928
1002
|
}
|
|
929
1003
|
function resolveRenderedCacheControl(requestCacheLife, cacheControl, fallbackExpireSeconds) {
|
|
@@ -991,7 +1065,9 @@ function writePrerenderIndex(routes, outDir, options) {
|
|
|
991
1065
|
...typeof r.stale === "number" ? { stale: r.stale } : {},
|
|
992
1066
|
router: r.router,
|
|
993
1067
|
...r.tags && r.tags.length > 0 ? { tags: r.tags } : {},
|
|
1068
|
+
...r.routeSegments ? { routeSegments: r.routeSegments } : {},
|
|
994
1069
|
...r.headers ? { headers: r.headers } : {},
|
|
1070
|
+
...typeof r.responseStatus === "number" ? { responseStatus: r.responseStatus } : {},
|
|
995
1071
|
...r.path ? { path: r.path } : {},
|
|
996
1072
|
...r.fallback ? { fallback: true } : {}
|
|
997
1073
|
};
|
|
@@ -3,9 +3,11 @@ import { findDir } from "../utils/project.js";
|
|
|
3
3
|
import { apiRouter, pagesRouter } from "../routing/pages-router.js";
|
|
4
4
|
import { appRouter } from "../routing/app-router.js";
|
|
5
5
|
import { scanMetadataFiles } from "../server/metadata-routes.js";
|
|
6
|
+
import { PHASE_PRODUCTION_BUILD } from "../shims/constants.js";
|
|
6
7
|
import { loadNextConfig, resolveNextConfig } from "../config/next-config.js";
|
|
7
8
|
import { readPrerenderSecret } from "./server-manifest.js";
|
|
8
9
|
import { rememberCurrentServerEntryImportMtime, startProdServer } from "../server/prod-server.js";
|
|
10
|
+
import { enterPrerenderPhase } from "./prerender-phase.js";
|
|
9
11
|
import { prerenderApp, prerenderPages, writePrerenderIndex } from "./prerender.js";
|
|
10
12
|
import { injectPregeneratedConcretePaths } from "./inject-pregenerated-paths.js";
|
|
11
13
|
import fs from "node:fs";
|
|
@@ -104,12 +106,10 @@ async function runPrerender(options) {
|
|
|
104
106
|
const appDir = findDir(root, "app", "src/app");
|
|
105
107
|
const pagesDir = findDir(root, "pages", "src/pages");
|
|
106
108
|
if (!appDir && !pagesDir) return null;
|
|
107
|
-
const previousPrerenderFlag = process.env.VINEXT_PRERENDER;
|
|
108
|
-
process.env.VINEXT_PRERENDER = "1";
|
|
109
109
|
const manifestDir = path.join(root, "dist", "server");
|
|
110
110
|
const rscBundlePath = options.rscBundlePath ?? path.join(root, "dist", "server", "index.js");
|
|
111
111
|
const serverDir = path.dirname(rscBundlePath);
|
|
112
|
-
const config = options.nextConfig ? { ...options.nextConfig } : { ...await resolveNextConfig(await loadNextConfig(root), root) };
|
|
112
|
+
const config = options.nextConfig ? { ...options.nextConfig } : { ...await resolveNextConfig(await loadNextConfig(root, PHASE_PRODUCTION_BUILD), root) };
|
|
113
113
|
const builtBuildId = readBuiltBuildId(serverDir);
|
|
114
114
|
if (builtBuildId) config.buildId = builtBuildId;
|
|
115
115
|
const mode = config.output === "export" ? "export" : "default";
|
|
@@ -121,6 +121,7 @@ async function runPrerender(options) {
|
|
|
121
121
|
const outDir = mode === "export" ? path.join(root, "dist", "client") : path.join(root, "dist", "server", "prerendered-routes");
|
|
122
122
|
let sharedProdServer = null;
|
|
123
123
|
let sharedPrerenderSecret;
|
|
124
|
+
const restorePrerenderPhase = enterPrerenderPhase();
|
|
124
125
|
try {
|
|
125
126
|
if (appDir && pagesDir) {
|
|
126
127
|
sharedProdServer = await startProdServer({
|
|
@@ -187,9 +188,11 @@ async function runPrerender(options) {
|
|
|
187
188
|
if (result.outputFiles) allOutputFiles.push(...result.outputFiles);
|
|
188
189
|
}
|
|
189
190
|
} finally {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
try {
|
|
192
|
+
if (sharedProdServer) await new Promise((resolve) => sharedProdServer.server.close(() => resolve()));
|
|
193
|
+
} finally {
|
|
194
|
+
restorePrerenderPhase();
|
|
195
|
+
}
|
|
193
196
|
}
|
|
194
197
|
if (allRoutes.length === 0) {
|
|
195
198
|
progress.finish(0, 0, 0);
|
|
@@ -6,6 +6,8 @@ type VinextLinkPrefetchRoute = {
|
|
|
6
6
|
isDynamic: boolean;
|
|
7
7
|
patternParts: string[];
|
|
8
8
|
requiresDynamicNavigationRequest?: boolean;
|
|
9
|
+
/** The route has dynamic params above its root layout. */
|
|
10
|
+
hasRootParams?: true;
|
|
9
11
|
};
|
|
10
12
|
/**
|
|
11
13
|
* Pages Router route pattern exposed to the client so the App Router's
|
|
@@ -332,7 +332,11 @@ async function loadNextConfig(root, phase = DEFAULT_PHASE) {
|
|
|
332
332
|
const normalizedConfigPath = safeRealpath(path.resolve(configPath));
|
|
333
333
|
try {
|
|
334
334
|
const { runnerImport } = await import("vite");
|
|
335
|
-
const
|
|
335
|
+
const virtualConfigId = "virtual:vinext-resolved-next-config";
|
|
336
|
+
const resolvedVirtualConfigId = `\0${virtualConfigId}`;
|
|
337
|
+
const configPathLiteral = JSON.stringify(configPath);
|
|
338
|
+
const phaseLiteral = JSON.stringify(phase);
|
|
339
|
+
const { module: mod } = await runnerImport(virtualConfigId, {
|
|
336
340
|
root,
|
|
337
341
|
logLevel: "error",
|
|
338
342
|
clearScreen: false,
|
|
@@ -351,13 +355,26 @@ async function loadNextConfig(root, phase = DEFAULT_PHASE) {
|
|
|
351
355
|
".json"
|
|
352
356
|
]
|
|
353
357
|
},
|
|
354
|
-
plugins: [
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
358
|
+
plugins: [
|
|
359
|
+
{
|
|
360
|
+
name: "vinext:resolve-next-config-value",
|
|
361
|
+
resolveId(id) {
|
|
362
|
+
if (id === virtualConfigId) return resolvedVirtualConfigId;
|
|
363
|
+
},
|
|
364
|
+
load(id) {
|
|
365
|
+
if (id !== resolvedVirtualConfigId) return;
|
|
366
|
+
return `import * as configModule from ${configPathLiteral};\nconst cjsModule = configModule[${JSON.stringify(VINEXT_CJS_EXPORTS_KEY)}];\nconst cjsInitial = configModule[${JSON.stringify(VINEXT_CJS_INITIAL_KEY)}];\nconst cjsExports = cjsModule && cjsModule.exports;\nconst cjsValue = cjsExports != null && (cjsExports !== cjsInitial || (typeof cjsExports === "object" && Object.keys(cjsExports).length > 0)) ? cjsExports : undefined;\nconst value = cjsValue ?? configModule.default ?? configModule;\nexport default typeof value === "function" ? await value(${phaseLiteral}, { defaultConfig: {} }) : value;\n`;
|
|
367
|
+
}
|
|
368
|
+
},
|
|
369
|
+
...isTypeScriptConfig ? [cjsGlobalsInjectorPlugin(configPath)] : [],
|
|
370
|
+
commonjs({ filter: (id) => {
|
|
371
|
+
const idPath = id.startsWith("file://") ? fileURLToPath(id) : id.split("?")[0];
|
|
372
|
+
if (safeRealpath(path.resolve(idPath)) === normalizedConfigPath) return false;
|
|
373
|
+
return id.includes("node_modules") ? true : void 0;
|
|
374
|
+
} })
|
|
375
|
+
]
|
|
359
376
|
});
|
|
360
|
-
return
|
|
377
|
+
return mod.default;
|
|
361
378
|
} catch (e) {
|
|
362
379
|
if (isCjsError(e) && (filename.endsWith(".js") || filename.endsWith(".cjs"))) try {
|
|
363
380
|
return await loadConfigViaRequire(configPath, root, phase);
|