vinext 0.1.6 → 0.1.7
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/client-build-config.d.ts +4 -6
- package/dist/build/client-build-config.js +27 -7
- package/dist/build/prerender.js +1 -2
- package/dist/entries/app-rsc-entry.d.ts +2 -1
- package/dist/entries/app-rsc-entry.js +35 -10
- package/dist/index.js +47 -20
- package/dist/plugins/og-assets.js +6 -6
- package/dist/plugins/remove-console.js +1 -1
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/server/app-action-request.d.ts +4 -0
- package/dist/server/app-action-request.js +9 -0
- package/dist/server/app-bfcache-identity.d.ts +12 -2
- package/dist/server/app-bfcache-identity.js +52 -23
- package/dist/server/app-history-state.d.ts +1 -2
- package/dist/server/app-history-state.js +1 -1
- package/dist/server/app-page-method.js +1 -1
- package/dist/server/app-page-stream.js +2 -1
- package/dist/server/app-route-handler-cache.js +1 -1
- package/dist/server/app-route-handler-dispatch.js +2 -2
- package/dist/server/app-route-handler-execution.js +3 -2
- package/dist/server/app-route-handler-policy.d.ts +1 -1
- package/dist/server/app-route-handler-policy.js +1 -6
- package/dist/server/app-rsc-errors.d.ts +12 -1
- package/dist/server/app-rsc-errors.js +22 -2
- package/dist/server/app-rsc-handler.d.ts +13 -12
- package/dist/server/app-rsc-handler.js +24 -26
- package/dist/server/app-rsc-response-finalizer.js +5 -1
- package/dist/server/app-server-action-execution.js +1 -1
- package/dist/server/app-ssr-entry.js +7 -5
- package/dist/server/metadata-route-response.d.ts +1 -1
- package/dist/shims/dynamic.js +1 -1
- package/package.json +1 -1
|
@@ -26,12 +26,10 @@ declare function createClientAssetFileNames(assetsDir: string): (assetInfo: Clie
|
|
|
26
26
|
*
|
|
27
27
|
* Splits the client bundle into:
|
|
28
28
|
* - "framework" — React, ReactDOM, and scheduler (loaded on every page)
|
|
29
|
-
* - "vinext" — vinext shims
|
|
29
|
+
* - "vinext" — shared vinext runtime shims
|
|
30
30
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* common chunks based on the import graph — no manual intervention
|
|
34
|
-
* needed.
|
|
31
|
+
* Route-owned client shims and all other vendor code are left to the bundler's
|
|
32
|
+
* graph-based chunking so they stay behind their client-reference boundaries.
|
|
35
33
|
*
|
|
36
34
|
* Why not split every npm package into its own chunk?
|
|
37
35
|
* - Per-package splitting (`vendor-X`) creates 50-200+ chunks for a
|
|
@@ -48,7 +46,7 @@ declare function createClientAssetFileNames(assetsDir: string): (assetInfo: Clie
|
|
|
48
46
|
* well: shared dependencies between routes get their own chunks,
|
|
49
47
|
* and route-specific code stays in route chunks.
|
|
50
48
|
*/
|
|
51
|
-
declare function createClientManualChunks(shimsDir: string): (id: string) => string | undefined;
|
|
49
|
+
declare function createClientManualChunks(shimsDir: string, preserveRouteBoundaries?: boolean): (id: string) => string | undefined;
|
|
52
50
|
/**
|
|
53
51
|
* Rollup output config with manualChunks for client code-splitting.
|
|
54
52
|
* Used by both CLI builds and multi-environment builds.
|
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
//#region src/build/client-build-config.ts
|
|
2
|
+
const ROUTE_OWNED_CLIENT_SHIMS = new Set([
|
|
3
|
+
"compat-router",
|
|
4
|
+
"dynamic",
|
|
5
|
+
"dynamic-preload-chunks",
|
|
6
|
+
"form",
|
|
7
|
+
"image",
|
|
8
|
+
"layout-segment-context",
|
|
9
|
+
"legacy-image",
|
|
10
|
+
"link",
|
|
11
|
+
"offline",
|
|
12
|
+
"router",
|
|
13
|
+
"script",
|
|
14
|
+
"web-vitals"
|
|
15
|
+
]);
|
|
2
16
|
const NEXT_CLIENT_CSS_ASSET_FILE_NAMES = "css/[name].[hash:8][extname]";
|
|
3
17
|
const NEXT_CLIENT_STATIC_MEDIA_FILE_NAMES = "media/[name].[hash:8][extname]";
|
|
4
18
|
function joinAssetFileNamePattern(assetsDir, pattern) {
|
|
@@ -48,12 +62,10 @@ function getPackageName(id) {
|
|
|
48
62
|
*
|
|
49
63
|
* Splits the client bundle into:
|
|
50
64
|
* - "framework" — React, ReactDOM, and scheduler (loaded on every page)
|
|
51
|
-
* - "vinext" — vinext shims
|
|
65
|
+
* - "vinext" — shared vinext runtime shims
|
|
52
66
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* common chunks based on the import graph — no manual intervention
|
|
56
|
-
* needed.
|
|
67
|
+
* Route-owned client shims and all other vendor code are left to the bundler's
|
|
68
|
+
* graph-based chunking so they stay behind their client-reference boundaries.
|
|
57
69
|
*
|
|
58
70
|
* Why not split every npm package into its own chunk?
|
|
59
71
|
* - Per-package splitting (`vendor-X`) creates 50-200+ chunks for a
|
|
@@ -70,7 +82,7 @@ function getPackageName(id) {
|
|
|
70
82
|
* well: shared dependencies between routes get their own chunks,
|
|
71
83
|
* and route-specific code stays in route chunks.
|
|
72
84
|
*/
|
|
73
|
-
function createClientManualChunks(shimsDir) {
|
|
85
|
+
function createClientManualChunks(shimsDir, preserveRouteBoundaries = false) {
|
|
74
86
|
return function clientManualChunks(id) {
|
|
75
87
|
if (id.includes("node_modules")) {
|
|
76
88
|
const pkg = getPackageName(id);
|
|
@@ -78,7 +90,15 @@ function createClientManualChunks(shimsDir) {
|
|
|
78
90
|
if (pkg === "react" || pkg === "react-dom" || pkg === "scheduler") return "framework";
|
|
79
91
|
return;
|
|
80
92
|
}
|
|
81
|
-
if (id.startsWith(shimsDir))
|
|
93
|
+
if (id.startsWith(shimsDir)) {
|
|
94
|
+
if (preserveRouteBoundaries) {
|
|
95
|
+
const relativeId = id.slice(shimsDir.length).split("?", 1)[0] ?? "";
|
|
96
|
+
const extensionIndex = relativeId.lastIndexOf(".");
|
|
97
|
+
const shimName = extensionIndex === -1 ? relativeId : relativeId.slice(0, extensionIndex);
|
|
98
|
+
if (ROUTE_OWNED_CLIENT_SHIMS.has(shimName)) return void 0;
|
|
99
|
+
}
|
|
100
|
+
return "vinext";
|
|
101
|
+
}
|
|
82
102
|
};
|
|
83
103
|
}
|
|
84
104
|
/**
|
package/dist/build/prerender.js
CHANGED
|
@@ -306,7 +306,6 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
|
|
|
306
306
|
for (const route of bundlePageRoutes) {
|
|
307
307
|
if (BLOCKED_PAGES.includes(route.pattern)) continue;
|
|
308
308
|
if (route.pattern === "/404") continue;
|
|
309
|
-
if (!routes.find((r) => r.filePath === route.filePath || r.pattern === route.pattern)) continue;
|
|
310
309
|
const { type, revalidate: classifiedRevalidate } = classifyPagesRoute(route.filePath);
|
|
311
310
|
if (type === "ssr") {
|
|
312
311
|
if (mode === "export") results.push({
|
|
@@ -648,7 +647,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
|
|
|
648
647
|
});
|
|
649
648
|
continue;
|
|
650
649
|
}
|
|
651
|
-
if (
|
|
650
|
+
if (paramSets.length === 0) {
|
|
652
651
|
results.push({
|
|
653
652
|
route: route.pattern,
|
|
654
653
|
status: "skipped",
|
|
@@ -44,7 +44,8 @@ type AppRouterConfig = {
|
|
|
44
44
|
reactMaxHeadersLength?: number; /** Maximum in-memory cache size in bytes. 0 disables the default memory cache. */
|
|
45
45
|
cacheMaxMemorySize?: number; /** Inline app CSS into production HTML (from experimental.inlineCss). */
|
|
46
46
|
inlineCss?: boolean; /** Enables Next.js Cache Components semantics for App Router document HTML. */
|
|
47
|
-
cacheComponents?: boolean; /**
|
|
47
|
+
cacheComponents?: boolean; /** Whether the RSC build discovered any server references. Defaults to true. */
|
|
48
|
+
hasServerActions?: boolean; /** Internationalization routing config for middleware matcher locale handling. */
|
|
48
49
|
i18n?: NextI18nConfig | null;
|
|
49
50
|
imageConfig?: ImageConfig;
|
|
50
51
|
/**
|
|
@@ -20,6 +20,8 @@ const middlewareRequestHeadersPath = resolveEntryPath("../server/middleware-requ
|
|
|
20
20
|
const normalizePathModulePath = resolveEntryPath("../server/normalize-path.js", import.meta.url);
|
|
21
21
|
const appRouteHandlerDispatchPath = resolveEntryPath("../server/app-route-handler-dispatch.js", import.meta.url);
|
|
22
22
|
const appRouteHandlerResponsePath = resolveEntryPath("../server/app-route-handler-response.js", import.meta.url);
|
|
23
|
+
const appMiddlewarePath = resolveEntryPath("../server/app-middleware.js", import.meta.url);
|
|
24
|
+
const metadataRouteResponsePath = resolveEntryPath("../server/metadata-route-response.js", import.meta.url);
|
|
23
25
|
const appServerActionExecutionPath = resolveEntryPath("../server/app-server-action-execution.js", import.meta.url);
|
|
24
26
|
const appRscErrorsPath = resolveEntryPath("../server/app-rsc-errors.js", import.meta.url);
|
|
25
27
|
const appPageExecutionPath = resolveEntryPath("../server/app-page-execution.js", import.meta.url);
|
|
@@ -73,6 +75,7 @@ function generateRscEntry(appDir, routes, middlewarePath, metadataRoutes, global
|
|
|
73
75
|
const cacheMaxMemorySize = config?.cacheMaxMemorySize;
|
|
74
76
|
const inlineCss = config?.inlineCss === true;
|
|
75
77
|
const cacheComponents = config?.cacheComponents === true;
|
|
78
|
+
const hasServerActions = config?.hasServerActions !== false;
|
|
76
79
|
const i18nConfig = config?.i18n ?? null;
|
|
77
80
|
const hasPagesDir = config?.hasPagesDir ?? false;
|
|
78
81
|
const publicFiles = config?.publicFiles ?? [];
|
|
@@ -93,12 +96,12 @@ async function __loadPrerenderPagesRoutes() {
|
|
|
93
96
|
import ${JSON.stringify(serverGlobalsPath)};
|
|
94
97
|
import {
|
|
95
98
|
renderToReadableStream as _renderToReadableStream,
|
|
96
|
-
decodeAction,
|
|
99
|
+
${hasServerActions ? `decodeAction,
|
|
97
100
|
decodeFormState,
|
|
98
101
|
decodeReply,
|
|
99
102
|
loadServerAction,
|
|
100
|
-
createTemporaryReferenceSet
|
|
101
|
-
} from "@vitejs/plugin-rsc/rsc";
|
|
103
|
+
createTemporaryReferenceSet,` : ""}
|
|
104
|
+
} from ${JSON.stringify(hasServerActions ? "@vitejs/plugin-rsc/rsc" : "@vitejs/plugin-rsc/react/rsc")};
|
|
102
105
|
import { createClientManifest as _createClientManifest } from "@vitejs/plugin-rsc/core/rsc";
|
|
103
106
|
import { prerender as _prerender } from "@vitejs/plugin-rsc/vendor/react-server-dom/static.edge";
|
|
104
107
|
import { createRscPrerenderer, createRscRenderer } from ${JSON.stringify(rscStreamHintsPath)};
|
|
@@ -112,7 +115,8 @@ import { getNavigationContext as _getNavigationContext } from "next/navigation";
|
|
|
112
115
|
import { configureMemoryCacheHandler as __configureMemoryCacheHandler } from "vinext/shims/cache-handler";
|
|
113
116
|
import { headersContextFromRequest, getDraftModeCookieHeader, getAndClearPendingCookies, consumeDynamicUsage, consumeInvalidDynamicUsageError, setHeadersAccessPhase } from "next/headers";
|
|
114
117
|
import { mergeMetadata, resolveModuleMetadata, mergeViewport, resolveModuleViewport } from "vinext/metadata";
|
|
115
|
-
${middlewarePath ? `import * as middlewareModule from ${JSON.stringify(normalizePathSeparators(middlewarePath))}
|
|
118
|
+
${middlewarePath ? `import * as middlewareModule from ${JSON.stringify(normalizePathSeparators(middlewarePath))};
|
|
119
|
+
import { applyAppMiddleware as __applyAppMiddleware } from ${JSON.stringify(appMiddlewarePath)};` : ""}
|
|
116
120
|
${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(normalizePathSeparators(instrumentationPath))};
|
|
117
121
|
import { ensureInstrumentationRegistered as __ensureInstrumentationRegistered } from ${JSON.stringify(instrumentationRuntimePath)};` : ""}
|
|
118
122
|
import { createAppRscHandler } from "vinext/server/app-rsc-handler";
|
|
@@ -123,7 +127,8 @@ ${hasPagesDir ? `import {
|
|
|
123
127
|
applyRouteHandlerMiddlewareContext as __applyRouteHandlerMiddlewareContext,
|
|
124
128
|
} from ${JSON.stringify(appRouteHandlerResponsePath)};` : ""}
|
|
125
129
|
const __loadAppRouteHandlerDispatch = () => import(${JSON.stringify(appRouteHandlerDispatchPath)});
|
|
126
|
-
const __loadAppServerActionExecution = () => import(${JSON.stringify(appServerActionExecutionPath)})
|
|
130
|
+
${hasServerActions ? `const __loadAppServerActionExecution = () => import(${JSON.stringify(appServerActionExecutionPath)});` : ""}
|
|
131
|
+
${(metadataRoutes?.length ?? 0) > 0 ? `const __loadMetadataRouteResponse = () => import(${JSON.stringify(metadataRouteResponsePath)});` : ""}
|
|
127
132
|
import {
|
|
128
133
|
sanitizeErrorForClient as __sanitizeErrorForClient,
|
|
129
134
|
} from ${JSON.stringify(appRscErrorsPath)};
|
|
@@ -683,6 +688,7 @@ export default createAppRscHandler({
|
|
|
683
688
|
${instrumentationPath ? `ensureInstrumentation() {
|
|
684
689
|
return __ensureInstrumentationRegistered(_instrumentation);
|
|
685
690
|
},` : ""}
|
|
691
|
+
${hasServerActions ? `
|
|
686
692
|
async handleProgressiveActionRequest({
|
|
687
693
|
actionId,
|
|
688
694
|
cleanPathname,
|
|
@@ -860,14 +866,33 @@ export default createAppRscHandler({
|
|
|
860
866
|
},
|
|
861
867
|
});
|
|
862
868
|
},
|
|
869
|
+
` : ""}
|
|
863
870
|
i18nConfig: __i18nConfig,
|
|
864
|
-
isMiddlewareProxy: ${JSON.stringify(middlewarePath ? isProxyFile(middlewarePath) : false)},
|
|
865
871
|
${hasPagesDir ? `loadPrerenderPagesRoutes: __loadPrerenderPagesRoutes,` : ""}
|
|
866
|
-
|
|
872
|
+
${(metadataRoutes?.length ?? 0) > 0 ? `async handleMetadataRouteRequest(cleanPathname) {
|
|
873
|
+
const { handleMetadataRouteRequest: __handleMetadataRouteRequest } =
|
|
874
|
+
await __loadMetadataRouteResponse();
|
|
875
|
+
return __handleMetadataRouteRequest({
|
|
876
|
+
metadataRoutes,
|
|
877
|
+
cleanPathname,
|
|
878
|
+
makeThenableParams,
|
|
879
|
+
});
|
|
880
|
+
},` : ""}
|
|
867
881
|
matchRoute,
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
882
|
+
${middlewarePath ? `runMiddleware({ cleanPathname, context, isDataRequest, request }) {
|
|
883
|
+
return __applyAppMiddleware({
|
|
884
|
+
basePath: __basePath,
|
|
885
|
+
cleanPathname,
|
|
886
|
+
context,
|
|
887
|
+
filePath: ${JSON.stringify(middlewarePath ? normalizePathSeparators(middlewarePath) : "")},
|
|
888
|
+
i18nConfig: __i18nConfig,
|
|
889
|
+
isDataRequest,
|
|
890
|
+
isProxy: ${JSON.stringify(isProxyFile(middlewarePath))},
|
|
891
|
+
module: middlewareModule,
|
|
892
|
+
request,
|
|
893
|
+
trailingSlash: __trailingSlash,
|
|
894
|
+
});
|
|
895
|
+
},` : ""}
|
|
871
896
|
publicFiles: __publicFiles,
|
|
872
897
|
renderNotFound({ isRscRequest, matchedParams, middlewareContext, request, route, scriptNonce }) {
|
|
873
898
|
const __isEdge = route ? __isEdgeRuntime(__resolveAppPageSegmentConfig({ layouts: route.layouts, page: route.page }).runtime) : false;
|
package/dist/index.js
CHANGED
|
@@ -420,12 +420,16 @@ const _reactServerShims = new Map([
|
|
|
420
420
|
]);
|
|
421
421
|
const clientManualChunks = createClientManualChunks(_shimsDir);
|
|
422
422
|
const clientCodeSplittingConfig = createClientCodeSplittingConfig(clientManualChunks);
|
|
423
|
-
|
|
423
|
+
const appClientManualChunks = createClientManualChunks(_shimsDir, true);
|
|
424
|
+
const appClientCodeSplittingConfig = createClientCodeSplittingConfig(appClientManualChunks);
|
|
425
|
+
function getClientOutputConfigForVite(viteMajorVersion, assetsDir, preserveAppRouteBoundaries = false) {
|
|
426
|
+
const manualChunks = preserveAppRouteBoundaries ? appClientManualChunks : clientManualChunks;
|
|
427
|
+
const codeSplitting = preserveAppRouteBoundaries ? appClientCodeSplittingConfig : clientCodeSplittingConfig;
|
|
424
428
|
return viteMajorVersion >= 8 ? {
|
|
425
429
|
...createClientFileNameConfig(assetsDir),
|
|
426
430
|
assetFileNames: createClientAssetFileNames(assetsDir),
|
|
427
|
-
codeSplitting
|
|
428
|
-
} : createClientOutputConfig(
|
|
431
|
+
codeSplitting
|
|
432
|
+
} : createClientOutputConfig(manualChunks, assetsDir);
|
|
429
433
|
}
|
|
430
434
|
function vinext(options = {}) {
|
|
431
435
|
const viteMajorVersion = getViteMajorVersion();
|
|
@@ -507,13 +511,16 @@ function vinext(options = {}) {
|
|
|
507
511
|
let resolvedReactPath = null;
|
|
508
512
|
let resolvedRscPath = null;
|
|
509
513
|
let resolvedRscTransformsPath = null;
|
|
514
|
+
let rscPluginModulePromise = null;
|
|
510
515
|
resolvedReactPath = resolveOptionalDependency(earlyBaseDir, "@vitejs/plugin-react");
|
|
511
516
|
resolvedRscPath = resolveOptionalDependency(earlyBaseDir, "@vitejs/plugin-rsc");
|
|
512
517
|
resolvedRscTransformsPath = resolveOptionalDependency(earlyBaseDir, "@vitejs/plugin-rsc/transforms");
|
|
513
518
|
let rscPluginPromise = null;
|
|
514
519
|
if (earlyAppDirExists && autoRsc) {
|
|
515
520
|
if (!resolvedRscPath) throw new Error("vinext: App Router detected but @vitejs/plugin-rsc is not installed.\nRun: " + detectPackageManager(process.cwd()) + " @vitejs/plugin-rsc");
|
|
516
|
-
|
|
521
|
+
const rscImport = import(pathToFileURL(resolvedRscPath).href);
|
|
522
|
+
rscPluginModulePromise = rscImport;
|
|
523
|
+
rscPluginPromise = rscImport.then((mod) => {
|
|
517
524
|
const rsc = mod.default;
|
|
518
525
|
return rsc({ entries: {
|
|
519
526
|
rsc: VIRTUAL_RSC_ENTRY,
|
|
@@ -890,6 +897,7 @@ function vinext(options = {}) {
|
|
|
890
897
|
};
|
|
891
898
|
const nextServerExternal = nextConfig?.serverExternalPackages ?? [];
|
|
892
899
|
const userSsrExternal = Array.isArray(config.ssr?.external) ? [...config.ssr.external, ...nextServerExternal] : config.ssr?.external === true ? true : nextServerExternal;
|
|
900
|
+
const externalizeSsrReactInDev = env.command === "serve" && !hasCloudflarePlugin && !hasNitroPlugin;
|
|
893
901
|
const incomingExclude = config.optimizeDeps?.exclude ?? [];
|
|
894
902
|
const incomingInclude = config.optimizeDeps?.include ?? [];
|
|
895
903
|
const depOptimizeAliasPlugin = {
|
|
@@ -944,11 +952,15 @@ function vinext(options = {}) {
|
|
|
944
952
|
},
|
|
945
953
|
ssr: {
|
|
946
954
|
...hasCloudflarePlugin || hasNitroPlugin ? {} : { resolve: {
|
|
947
|
-
external: userSsrExternal === true ? true : [
|
|
955
|
+
external: userSsrExternal === true ? true : [
|
|
956
|
+
...userSsrExternal,
|
|
957
|
+
"ipaddr.js",
|
|
958
|
+
...externalizeSsrReactInDev ? SSR_EXTERNAL_REACT_ENTRIES : []
|
|
959
|
+
],
|
|
948
960
|
...userSsrExternal === true ? {} : { noExternal: true }
|
|
949
961
|
} },
|
|
950
962
|
optimizeDeps: {
|
|
951
|
-
exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE, ["ipaddr.js"], userSsrExternal === true ? SSR_EXTERNAL_REACT_ENTRIES : []),
|
|
963
|
+
exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE, ["ipaddr.js"], userSsrExternal === true || externalizeSsrReactInDev ? SSR_EXTERNAL_REACT_ENTRIES : []),
|
|
952
964
|
entries: optimizeEntries,
|
|
953
965
|
...depOptimizeNodeEnvOptions
|
|
954
966
|
},
|
|
@@ -977,7 +989,7 @@ function vinext(options = {}) {
|
|
|
977
989
|
assetsInlineLimit: clientAssetsInlineLimit,
|
|
978
990
|
...withBuildBundlerOptions(viteMajorVersion, {
|
|
979
991
|
input: appClientInput,
|
|
980
|
-
output: getClientOutputConfigForVite(viteMajorVersion, clientAssetsDir),
|
|
992
|
+
output: getClientOutputConfigForVite(viteMajorVersion, clientAssetsDir, true),
|
|
981
993
|
treeshake: getClientTreeshakeConfigForVite(viteMajorVersion)
|
|
982
994
|
})
|
|
983
995
|
}
|
|
@@ -1127,6 +1139,12 @@ function vinext(options = {}) {
|
|
|
1127
1139
|
if (id === RESOLVED_RSC_ENTRY && hasAppDir) {
|
|
1128
1140
|
const routes = await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher);
|
|
1129
1141
|
const metaRoutes = scanMetadataFiles(appDir);
|
|
1142
|
+
let hasServerActions = true;
|
|
1143
|
+
if (this.environment?.config.command === "build" && rscPluginModulePromise) {
|
|
1144
|
+
const { getPluginApi } = await rscPluginModulePromise;
|
|
1145
|
+
const pluginApi = getPluginApi(this.environment.config);
|
|
1146
|
+
if (pluginApi && !pluginApi.manager.isScanBuild) hasServerActions = Object.keys(pluginApi.manager.serverReferenceMetaMap).length > 0;
|
|
1147
|
+
}
|
|
1130
1148
|
const globalErrorPath = findFileWithExts(appDir, "global-error", fileMatcher);
|
|
1131
1149
|
const globalNotFoundPath = findFileWithExts(appDir, "global-not-found", fileMatcher);
|
|
1132
1150
|
rscClassificationManifest = collectRouteClassificationManifest(routes);
|
|
@@ -1146,6 +1164,7 @@ function vinext(options = {}) {
|
|
|
1146
1164
|
cacheMaxMemorySize: nextConfig?.cacheMaxMemorySize,
|
|
1147
1165
|
inlineCss: nextConfig?.inlineCss,
|
|
1148
1166
|
cacheComponents: nextConfig?.cacheComponents,
|
|
1167
|
+
hasServerActions,
|
|
1149
1168
|
i18n: nextConfig?.i18n,
|
|
1150
1169
|
imageConfig: {
|
|
1151
1170
|
deviceSizes: nextConfig?.images?.deviceSizes,
|
|
@@ -1304,15 +1323,19 @@ function vinext(options = {}) {
|
|
|
1304
1323
|
const hook = mdxDelegate.config;
|
|
1305
1324
|
return (typeof hook === "function" ? hook : hook.handler).call(this, config, env);
|
|
1306
1325
|
},
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1326
|
+
transform: {
|
|
1327
|
+
filter: { id: {
|
|
1328
|
+
include: /\.mdx$/i,
|
|
1329
|
+
exclude: /\?/
|
|
1330
|
+
} },
|
|
1331
|
+
async handler(code, id, options) {
|
|
1332
|
+
const delegate = mdxDelegate ?? await ensureMdxDelegate("on-demand");
|
|
1333
|
+
if (delegate?.transform) {
|
|
1334
|
+
const hook = delegate.transform;
|
|
1335
|
+
return (typeof hook === "function" ? hook : hook.handler).call(this, code, id, options);
|
|
1336
|
+
}
|
|
1337
|
+
if (!hasUserMdxPlugin) throw new Error(`[vinext] Encountered MDX module ${id} but no MDX plugin is configured. Install @mdx-js/rollup or register an MDX plugin manually.`);
|
|
1314
1338
|
}
|
|
1315
|
-
if (!hasUserMdxPlugin) throw new Error(`[vinext] Encountered MDX module ${id} but no MDX plugin is configured. Install @mdx-js/rollup or register an MDX plugin manually.`);
|
|
1316
1339
|
}
|
|
1317
1340
|
},
|
|
1318
1341
|
{
|
|
@@ -1358,6 +1381,7 @@ function vinext(options = {}) {
|
|
|
1358
1381
|
configureServer(server) {
|
|
1359
1382
|
const pageExtensions = fileMatcher.extensionRegex;
|
|
1360
1383
|
let pagesRunner = null;
|
|
1384
|
+
let cachedSSRHandler = null;
|
|
1361
1385
|
function getPagesRunner() {
|
|
1362
1386
|
if (!pagesRunner) pagesRunner = createDirectRunner(server.environments["ssr"] ?? Object.values(server.environments).find((e) => e !== server.environments["rsc"]) ?? Object.values(server.environments)[0]);
|
|
1363
1387
|
return pagesRunner;
|
|
@@ -1843,12 +1867,15 @@ function vinext(options = {}) {
|
|
|
1843
1867
|
const appMatch = matchAppRoute(resolvedPathname, await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher));
|
|
1844
1868
|
if (appMatch && !pagesRouteHasPriorityOverAppRoute(renderMatch.route, appMatch.route)) return next();
|
|
1845
1869
|
}
|
|
1846
|
-
|
|
1870
|
+
if (!cachedSSRHandler || cachedSSRHandler.routes !== routes) cachedSSRHandler = {
|
|
1871
|
+
routes,
|
|
1872
|
+
handler: createSSRHandler(server, getPagesRunner(), routes, pagesDir, nextConfig?.i18n, fileMatcher, nextConfig?.basePath ?? "", nextConfig?.trailingSlash ?? false, middlewarePath !== null, (nextConfig?.rewrites.beforeFiles.length ?? 0) > 0 || (nextConfig?.rewrites.afterFiles.length ?? 0) > 0 || (nextConfig?.rewrites.fallback.length ?? 0) > 0, nextConfig?.clientTraceMetadata, nextConfig?.htmlLimitedBots)
|
|
1873
|
+
};
|
|
1847
1874
|
flushStagedHeaders();
|
|
1848
1875
|
flushRequestHeaders();
|
|
1849
1876
|
if (pipelineResult.middlewareStatus !== void 0) req.__vinextMiddlewareStatus = pipelineResult.middlewareStatus;
|
|
1850
1877
|
req.url = pipelineResult.resolvedUrl;
|
|
1851
|
-
await handler(req, res, pipelineResult.resolvedUrl, req.__vinextMiddlewareStatus, pipelineResult.isDataReq, originalRequestUrl);
|
|
1878
|
+
await cachedSSRHandler.handler(req, res, pipelineResult.resolvedUrl, req.__vinextMiddlewareStatus, pipelineResult.isDataReq, originalRequestUrl);
|
|
1852
1879
|
}
|
|
1853
1880
|
} catch (e) {
|
|
1854
1881
|
next(e);
|
|
@@ -2068,7 +2095,7 @@ function vinext(options = {}) {
|
|
|
2068
2095
|
imageImports.add(absImagePath);
|
|
2069
2096
|
const urlVar = `__vinext_img_url_${varName}`;
|
|
2070
2097
|
const metaVar = `__vinext_img_meta_${varName}`;
|
|
2071
|
-
const replacement = `import ${urlVar} from ${JSON.stringify(absImagePath + "?vinext-image-url")};\nimport ${metaVar} from ${JSON.stringify(absImagePath + "?vinext-meta")};\
|
|
2098
|
+
const replacement = `import ${urlVar} from ${JSON.stringify(absImagePath + "?vinext-image-url")};\nimport ${metaVar} from ${JSON.stringify(absImagePath + "?vinext-meta")};\nvar ${varName} = { src: ${urlVar}, width: ${metaVar}.width, height: ${metaVar}.height };`;
|
|
2072
2099
|
s.overwrite(importNode.start, importNode.end, replacement);
|
|
2073
2100
|
hasChanges = true;
|
|
2074
2101
|
}
|
|
@@ -2154,7 +2181,7 @@ function vinext(options = {}) {
|
|
|
2154
2181
|
const { transformWrapExport, transformHoistInlineDirective } = await import(pathToFileURL(resolvedRscTransformsPath).href);
|
|
2155
2182
|
if (cacheDirective) {
|
|
2156
2183
|
const directiveValue = cacheDirective.expression.value;
|
|
2157
|
-
const variant = directiveValue === "use cache" ? "" : directiveValue.replace("use cache:", "").
|
|
2184
|
+
const variant = directiveValue === "use cache" ? "" : directiveValue.replace("use cache:", "").trim();
|
|
2158
2185
|
const isLayoutOrTemplate = /\/(layout|template)\.(tsx?|jsx?|mjs)$/.test(id);
|
|
2159
2186
|
const modulePath = stripViteModuleQuery(id);
|
|
2160
2187
|
const moduleFileName = path.basename(modulePath);
|
|
@@ -2194,7 +2221,7 @@ function vinext(options = {}) {
|
|
|
2194
2221
|
directive: /^use cache(:\s*\w+)?$/,
|
|
2195
2222
|
runtime: (value, name, meta) => {
|
|
2196
2223
|
const directiveMatch = meta.directiveMatch[0];
|
|
2197
|
-
const variant = directiveMatch === "use cache" ? "" : directiveMatch.replace("use cache:", "").
|
|
2224
|
+
const variant = directiveMatch === "use cache" ? "" : directiveMatch.replace("use cache:", "").trim();
|
|
2198
2225
|
return `(await import(${JSON.stringify(runtimeModuleUrl2)})).registerCachedFunction(${value}, ${JSON.stringify(id + ":" + name)}, ${JSON.stringify(variant)})`;
|
|
2199
2226
|
},
|
|
2200
2227
|
rejectNonAsyncFunction: false
|
|
@@ -46,7 +46,7 @@ function createOgInlineFetchAssetsPlugin() {
|
|
|
46
46
|
const boundary = await ownership.resolveModuleBoundary(id);
|
|
47
47
|
if (boundary === null) return null;
|
|
48
48
|
const { assetRoot, moduleDir } = boundary;
|
|
49
|
-
|
|
49
|
+
const s = new MagicString(code);
|
|
50
50
|
let didReplace = false;
|
|
51
51
|
const readAsBase64 = async (absPath) => {
|
|
52
52
|
const realPath = await ownership.resolveContainedAsset(assetRoot, absPath);
|
|
@@ -75,22 +75,22 @@ function createOgInlineFetchAssetsPlugin() {
|
|
|
75
75
|
`return Promise.resolve(a.buffer);`,
|
|
76
76
|
`})()`
|
|
77
77
|
].join("");
|
|
78
|
-
|
|
78
|
+
s.overwrite(match.index, match.index + fullMatch.length, inlined);
|
|
79
79
|
didReplace = true;
|
|
80
80
|
}
|
|
81
|
-
if (code.includes("readFileSync(")) for (const match of
|
|
81
|
+
if (code.includes("readFileSync(")) for (const match of code.matchAll(/[a-zA-Z_$][a-zA-Z0-9_$]*\.readFileSync\(\s*(?:[a-zA-Z_$][a-zA-Z0-9_$]*\.)?fileURLToPath\(\s*new URL\(\s*(["'])(\.[^"']+)\1\s*,\s*import\.meta\.url\s*\)\s*\)\s*\)/g)) {
|
|
82
82
|
const fullMatch = match[0];
|
|
83
83
|
const relPath = match[2];
|
|
84
84
|
const fileBase64 = await readAsBase64(path.resolve(moduleDir, relPath));
|
|
85
85
|
if (fileBase64 === null) continue;
|
|
86
86
|
const inlined = `Buffer.from(${JSON.stringify(fileBase64)},"base64")`;
|
|
87
|
-
|
|
87
|
+
s.overwrite(match.index, match.index + fullMatch.length, inlined);
|
|
88
88
|
didReplace = true;
|
|
89
89
|
}
|
|
90
90
|
if (!didReplace) return null;
|
|
91
91
|
return {
|
|
92
|
-
code:
|
|
93
|
-
map:
|
|
92
|
+
code: s.toString(),
|
|
93
|
+
map: s.generateMap({ hires: "boundary" })
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -32,7 +32,6 @@ const SCOPE_ENTERING_TYPES = new Set([
|
|
|
32
32
|
*/
|
|
33
33
|
function removeConsoleCalls(code, config) {
|
|
34
34
|
if (config === false) return null;
|
|
35
|
-
const excluded = typeof config === "object" ? new Set(config.exclude.map((s) => s.toLowerCase())) : /* @__PURE__ */ new Set();
|
|
36
35
|
if (!code.match(/\bconsole\b/)) return null;
|
|
37
36
|
let ast;
|
|
38
37
|
try {
|
|
@@ -40,6 +39,7 @@ function removeConsoleCalls(code, config) {
|
|
|
40
39
|
} catch {
|
|
41
40
|
return null;
|
|
42
41
|
}
|
|
42
|
+
const excluded = typeof config === "object" ? new Set(config.exclude.map((s) => s.toLowerCase())) : /* @__PURE__ */ new Set();
|
|
43
43
|
const scopeStack = [{ shadowed: false }];
|
|
44
44
|
function currentScope() {
|
|
45
45
|
return scopeStack[scopeStack.length - 1];
|
|
@@ -13,7 +13,8 @@ const SERVER_EXPORTS = new Set([
|
|
|
13
13
|
const SERVER_PROPS_SSG_CONFLICT = "You can not use getStaticProps or getStaticPaths with getServerSideProps. To use SSG, please remove getServerSideProps";
|
|
14
14
|
const EXPORT_ALL_IN_PAGE_ERROR = "Using `export * from '...'` in a page is disallowed. Please use `export { default } from '...'` instead.\nRead more: https://nextjs.org/docs/messages/export-all-in-page";
|
|
15
15
|
function hasServerExportCandidate(code) {
|
|
16
|
-
|
|
16
|
+
for (const name of SERVER_EXPORTS) if (code.includes(name)) return true;
|
|
17
|
+
return false;
|
|
17
18
|
}
|
|
18
19
|
function hasExportAllCandidate(code) {
|
|
19
20
|
let searchFrom = 0;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import "./headers.js";
|
|
2
|
+
//#region src/server/app-action-request.ts
|
|
3
|
+
function isPossibleAppRouteActionRequest(request) {
|
|
4
|
+
if (request.method.toUpperCase() !== "POST") return false;
|
|
5
|
+
const contentType = request.headers.get("content-type");
|
|
6
|
+
return request.headers.has("x-rsc-action") || request.headers.has("next-action") || contentType === "application/x-www-form-urlencoded" || contentType?.startsWith("multipart/form-data") === true;
|
|
7
|
+
}
|
|
8
|
+
//#endregion
|
|
9
|
+
export { isPossibleAppRouteActionRequest };
|
|
@@ -1,13 +1,23 @@
|
|
|
1
|
-
import { AppElements } from "./app-elements-wire.js";
|
|
1
|
+
import { AppElements, AppElementsWire } from "./app-elements-wire.js";
|
|
2
2
|
import { BfcacheIdMap } from "./app-history-state.js";
|
|
3
3
|
|
|
4
4
|
//#region src/server/app-bfcache-identity.d.ts
|
|
5
5
|
type BfcacheStateKeyMap = Readonly<Record<string, string>>;
|
|
6
|
+
type InitialBfcacheMaps = Readonly<{
|
|
7
|
+
bfcacheIds: BfcacheIdMap;
|
|
8
|
+
stateKeys: BfcacheStateKeyMap;
|
|
9
|
+
}>;
|
|
10
|
+
type AppElementsMetadata = ReturnType<typeof AppElementsWire.readMetadata>;
|
|
6
11
|
declare function createInitialBfcacheIdMap(elements: AppElements): BfcacheIdMap;
|
|
7
12
|
declare function createBfcacheSegmentStateKeyMap(options: {
|
|
8
13
|
elements: AppElements;
|
|
9
14
|
pathname: string;
|
|
10
15
|
}): BfcacheStateKeyMap;
|
|
16
|
+
declare function createInitialBfcacheMaps(options: {
|
|
17
|
+
elements: AppElements;
|
|
18
|
+
metadata: AppElementsMetadata;
|
|
19
|
+
pathname: string;
|
|
20
|
+
}): InitialBfcacheMaps;
|
|
11
21
|
declare function createNextBfcacheIdMap(options: {
|
|
12
22
|
current: BfcacheIdMap;
|
|
13
23
|
currentElements: AppElements;
|
|
@@ -23,4 +33,4 @@ declare function preserveBfcacheIdsForMergedElements(options: {
|
|
|
23
33
|
previous: BfcacheIdMap;
|
|
24
34
|
}): BfcacheIdMap;
|
|
25
35
|
//#endregion
|
|
26
|
-
export { BfcacheStateKeyMap, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|
|
36
|
+
export { BfcacheStateKeyMap, InitialBfcacheMaps, createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createInitialBfcacheMaps, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|
|
@@ -3,7 +3,6 @@ import { normalizePath } from "./normalize-path.js";
|
|
|
3
3
|
import { AppElementsWire } from "./app-elements-wire.js";
|
|
4
4
|
import "./app-elements.js";
|
|
5
5
|
import "./app-bfcache-id.js";
|
|
6
|
-
import { isBfcacheSegmentId } from "./app-history-state.js";
|
|
7
6
|
//#region src/server/app-bfcache-identity.ts
|
|
8
7
|
let nextBfcacheId = 0;
|
|
9
8
|
function rememberBfcacheId(value) {
|
|
@@ -24,6 +23,14 @@ function getTreePathIdentityPrefix(pathname, treePath) {
|
|
|
24
23
|
if (consumedPathnameSegments === 0) return "/";
|
|
25
24
|
return `/${pathnameSegments.slice(0, consumedPathnameSegments).join("/")}`;
|
|
26
25
|
}
|
|
26
|
+
function indexAppElementsMetadata(metadata) {
|
|
27
|
+
const slotBindingsBySlotId = /* @__PURE__ */ new Map();
|
|
28
|
+
for (const binding of metadata.slotBindings) slotBindingsBySlotId.set(binding.slotId, binding);
|
|
29
|
+
return {
|
|
30
|
+
metadata,
|
|
31
|
+
slotBindingsBySlotId
|
|
32
|
+
};
|
|
33
|
+
}
|
|
27
34
|
function readAppElementsMetadata(elements) {
|
|
28
35
|
let metadata;
|
|
29
36
|
try {
|
|
@@ -31,12 +38,11 @@ function readAppElementsMetadata(elements) {
|
|
|
31
38
|
} catch {
|
|
32
39
|
return null;
|
|
33
40
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
};
|
|
41
|
+
return indexAppElementsMetadata(metadata);
|
|
42
|
+
}
|
|
43
|
+
function parseBfcacheSegmentKey(id) {
|
|
44
|
+
const parsed = AppElementsWire.parseElementKey(id);
|
|
45
|
+
return parsed !== null && parsed.kind !== "route" ? parsed : null;
|
|
40
46
|
}
|
|
41
47
|
function createActiveSlotIdentity(id, parsed) {
|
|
42
48
|
const activeSlotBinding = parsed?.slotBindingsBySlotId.get(id);
|
|
@@ -50,9 +56,7 @@ function createActiveSlotIdentity(id, parsed) {
|
|
|
50
56
|
* contained here until vinext has a route-manifest authority equivalent to
|
|
51
57
|
* Next.js CacheNode or segment-cache state.
|
|
52
58
|
*/
|
|
53
|
-
function createBfcacheSegmentIdentity(id, options) {
|
|
54
|
-
const parsed = AppElementsWire.parseElementKey(id);
|
|
55
|
-
if (!parsed) return null;
|
|
59
|
+
function createBfcacheSegmentIdentity(id, parsed, options) {
|
|
56
60
|
if (parsed.kind === "page") return `${id}@${options.pathname}`;
|
|
57
61
|
if (parsed.kind === "slot") {
|
|
58
62
|
const activeSlotIdentity = createActiveSlotIdentity(id, options.metadata);
|
|
@@ -62,16 +66,15 @@ function createBfcacheSegmentIdentity(id, options) {
|
|
|
62
66
|
if (parsed.kind === "layout" || parsed.kind === "template") return `${id}@${getTreePathIdentityPrefix(options.pathname, parsed.treePath)}`;
|
|
63
67
|
return null;
|
|
64
68
|
}
|
|
65
|
-
function
|
|
69
|
+
function collectBfcacheSegmentIdCandidates(elements, metadata = readAppElementsMetadata(elements)) {
|
|
66
70
|
const ids = new Set(Object.keys(elements));
|
|
67
|
-
const metadata = parsed === void 0 ? readAppElementsMetadata(elements) : parsed;
|
|
68
71
|
for (const layoutId of metadata?.metadata.layoutIds ?? []) ids.add(layoutId);
|
|
69
|
-
return
|
|
72
|
+
return ids;
|
|
70
73
|
}
|
|
71
74
|
function createInitialBfcacheIdMap(elements) {
|
|
72
|
-
const
|
|
73
|
-
for (const id of
|
|
74
|
-
return
|
|
75
|
+
const bfcacheIds = {};
|
|
76
|
+
for (const id of collectBfcacheSegmentIdCandidates(elements)) if (parseBfcacheSegmentKey(id) !== null) bfcacheIds[id] = "0";
|
|
77
|
+
return bfcacheIds;
|
|
75
78
|
}
|
|
76
79
|
function normalizeBfcachePathname(pathname) {
|
|
77
80
|
const normalized = normalizePath(normalizePathnameForRouteMatch(pathname));
|
|
@@ -81,8 +84,10 @@ function createBfcacheSegmentStateKeyMap(options) {
|
|
|
81
84
|
const metadata = readAppElementsMetadata(options.elements);
|
|
82
85
|
const normalizedPathname = normalizeBfcachePathname(options.pathname);
|
|
83
86
|
const stateKeys = {};
|
|
84
|
-
for (const id of
|
|
85
|
-
const
|
|
87
|
+
for (const id of collectBfcacheSegmentIdCandidates(options.elements, metadata)) {
|
|
88
|
+
const parsed = parseBfcacheSegmentKey(id);
|
|
89
|
+
if (parsed === null) continue;
|
|
90
|
+
const stateKey = createBfcacheSegmentIdentity(id, parsed, {
|
|
86
91
|
metadata,
|
|
87
92
|
pathname: normalizedPathname
|
|
88
93
|
});
|
|
@@ -90,6 +95,27 @@ function createBfcacheSegmentStateKeyMap(options) {
|
|
|
90
95
|
}
|
|
91
96
|
return stateKeys;
|
|
92
97
|
}
|
|
98
|
+
function createInitialBfcacheMaps(options) {
|
|
99
|
+
const metadata = indexAppElementsMetadata(options.metadata);
|
|
100
|
+
const ids = collectBfcacheSegmentIdCandidates(options.elements, metadata);
|
|
101
|
+
const normalizedPathname = normalizeBfcachePathname(options.pathname);
|
|
102
|
+
const bfcacheIds = {};
|
|
103
|
+
const stateKeys = {};
|
|
104
|
+
for (const id of ids) {
|
|
105
|
+
const parsed = parseBfcacheSegmentKey(id);
|
|
106
|
+
if (parsed === null) continue;
|
|
107
|
+
bfcacheIds[id] = "0";
|
|
108
|
+
const stateKey = createBfcacheSegmentIdentity(id, parsed, {
|
|
109
|
+
metadata,
|
|
110
|
+
pathname: normalizedPathname
|
|
111
|
+
});
|
|
112
|
+
if (stateKey !== null) stateKeys[id] = stateKey;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
bfcacheIds,
|
|
116
|
+
stateKeys
|
|
117
|
+
};
|
|
118
|
+
}
|
|
93
119
|
function createNextBfcacheIdMap(options) {
|
|
94
120
|
const current = options.reuseCurrent === false ? {} : options.current;
|
|
95
121
|
for (const value of Object.values(current)) rememberBfcacheId(value);
|
|
@@ -99,11 +125,13 @@ function createNextBfcacheIdMap(options) {
|
|
|
99
125
|
const currentPathname = normalizeBfcachePathname(options.currentPathname);
|
|
100
126
|
const nextPathname = normalizeBfcachePathname(options.nextPathname);
|
|
101
127
|
const ids = {};
|
|
102
|
-
for (const id of
|
|
103
|
-
const
|
|
128
|
+
for (const id of collectBfcacheSegmentIdCandidates(options.elements, nextMetadata)) {
|
|
129
|
+
const parsed = parseBfcacheSegmentKey(id);
|
|
130
|
+
if (parsed === null) continue;
|
|
131
|
+
const currentValue = createBfcacheSegmentIdentity(id, parsed, {
|
|
104
132
|
metadata: currentMetadata,
|
|
105
133
|
pathname: currentPathname
|
|
106
|
-
}) === createBfcacheSegmentIdentity(id, {
|
|
134
|
+
}) === createBfcacheSegmentIdentity(id, parsed, {
|
|
107
135
|
metadata: nextMetadata,
|
|
108
136
|
pathname: nextPathname
|
|
109
137
|
}) ? current[id] : void 0;
|
|
@@ -115,7 +143,8 @@ function createNextBfcacheIdMap(options) {
|
|
|
115
143
|
}
|
|
116
144
|
function preserveBfcacheIdsForMergedElements(options) {
|
|
117
145
|
const ids = {};
|
|
118
|
-
for (const id of
|
|
146
|
+
for (const id of collectBfcacheSegmentIdCandidates(options.elements)) {
|
|
147
|
+
if (parseBfcacheSegmentKey(id) === null) continue;
|
|
119
148
|
const value = options.next[id] ?? options.previous[id];
|
|
120
149
|
if (value === void 0) continue;
|
|
121
150
|
ids[id] = value;
|
|
@@ -124,4 +153,4 @@ function preserveBfcacheIdsForMergedElements(options) {
|
|
|
124
153
|
return ids;
|
|
125
154
|
}
|
|
126
155
|
//#endregion
|
|
127
|
-
export { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|
|
156
|
+
export { createBfcacheSegmentStateKeyMap, createInitialBfcacheIdMap, createInitialBfcacheMaps, createNextBfcacheIdMap, preserveBfcacheIdsForMergedElements };
|
|
@@ -63,7 +63,6 @@ declare function createHistoryStateWithNavigationMetadata(state: unknown, metada
|
|
|
63
63
|
}): HistoryStateRecord | null;
|
|
64
64
|
declare function createExternalHistoryStatePreservingMetadata(callerState: unknown, currentHistoryState: unknown): unknown;
|
|
65
65
|
declare function readHistoryStatePreviousNextUrl(state: unknown): string | null;
|
|
66
|
-
declare function isBfcacheSegmentId(id: string): boolean;
|
|
67
66
|
declare function readHistoryStateBfcacheIds(state: unknown): BfcacheIdMap | null;
|
|
68
67
|
declare function readHistoryStateBfcacheVersion(state: unknown): number | null;
|
|
69
68
|
/**
|
|
@@ -83,4 +82,4 @@ declare function resolveHistoryTraversalIntent(options: {
|
|
|
83
82
|
historyState: unknown;
|
|
84
83
|
}): HistoryTraversalIntent;
|
|
85
84
|
//#endregion
|
|
86
|
-
export { BfcacheIdMap, HistoryStateSnapshotCache, HistoryTraversalIntent, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl,
|
|
85
|
+
export { BfcacheIdMap, HistoryStateSnapshotCache, HistoryTraversalIntent, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
|
|
@@ -220,4 +220,4 @@ function resolveHistoryTraversalIntent(options) {
|
|
|
220
220
|
};
|
|
221
221
|
}
|
|
222
222
|
//#endregion
|
|
223
|
-
export { HistoryStateSnapshotCache, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl,
|
|
223
|
+
export { HistoryStateSnapshotCache, RestorableClientStateController, createExternalHistoryStatePreservingMetadata, createHashOnlyHistoryStatePreservingNavigationMetadata, createHistoryStateWithNavigationMetadata, createHistoryStateWithPreviousNextUrl, isHistoryStateBfcacheVersionCurrent, readHistoryStateBfcacheIds, readHistoryStateBfcacheVersion, readHistoryStatePreviousNextUrl, readHistoryStateTraversalIndex, resolveHistoryTraversalIntent };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { methodNotAllowedResponse } from "./http-error-responses.js";
|
|
2
2
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
3
|
-
import { isPossibleAppRouteActionRequest } from "./app-
|
|
3
|
+
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
4
4
|
//#region src/server/app-page-method.ts
|
|
5
5
|
function isNonGetOrHead(method) {
|
|
6
6
|
const normalizedMethod = method.toUpperCase();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
1
2
|
import { VINEXT_RSC_VARY_HEADER } from "./app-rsc-cache-busting.js";
|
|
2
3
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
3
4
|
import { applyEdgeRuntimeHeader } from "./app-page-response.js";
|
|
@@ -131,7 +132,7 @@ function createAppPageRscErrorTracker(baseOnError) {
|
|
|
131
132
|
return capturedSpecialError;
|
|
132
133
|
},
|
|
133
134
|
onRenderError(error, requestInfo, errorContext) {
|
|
134
|
-
if (error
|
|
135
|
+
if (isNavigationSignalError(error)) {
|
|
135
136
|
if (capturedSpecialError === null) capturedSpecialError = error;
|
|
136
137
|
} else capturedError = error;
|
|
137
138
|
return baseOnError(error, requestInfo, errorContext);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
2
|
-
import { markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
|
|
3
2
|
import { applyRouteHandlerMiddlewareContext, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, buildRouteHandlerCachedResponse } from "./app-route-handler-response.js";
|
|
3
|
+
import { markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
|
|
4
4
|
import { runAppRouteHandler } from "./app-route-handler-execution.js";
|
|
5
5
|
//#region src/server/app-route-handler-cache.ts
|
|
6
6
|
const EMPTY_PARAMS = Object.freeze({});
|
|
@@ -7,10 +7,10 @@ import { setNavigationContext } from "../shims/navigation-context-state.js";
|
|
|
7
7
|
import { makeThenableParams } from "../shims/thenable-params.js";
|
|
8
8
|
import "../shims/navigation.js";
|
|
9
9
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
10
|
-
import { isKnownDynamicAppRoute, isValidHTTPMethod } from "./app-route-handler-runtime.js";
|
|
11
|
-
import { getAppRouteHandlerRevalidateSeconds, hasAppRouteHandlerDefaultExport, resolveAppRouteHandlerMethod, shouldReadAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
12
10
|
import { applyRouteHandlerMiddlewareContext } from "./app-route-handler-response.js";
|
|
11
|
+
import { isKnownDynamicAppRoute, isValidHTTPMethod } from "./app-route-handler-runtime.js";
|
|
13
12
|
import { createStaticGenerationHeadersContext } from "./app-static-generation.js";
|
|
13
|
+
import { getAppRouteHandlerRevalidateSeconds, hasAppRouteHandlerDefaultExport, resolveAppRouteHandlerMethod, shouldReadAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
14
14
|
import { executeAppRouteHandler } from "./app-route-handler-execution.js";
|
|
15
15
|
import { readAppRouteHandlerCacheResponse } from "./app-route-handler-cache.js";
|
|
16
16
|
import { resolveAppRouteHandlerFetchCacheMode } from "./app-segment-config.js";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { setHeadersContext } from "../shims/headers.js";
|
|
2
|
-
import {
|
|
3
|
-
import { isPossibleAppRouteActionRequest, resolveAppRouteHandlerSpecialError, shouldApplyAppRouteHandlerRevalidateHeader, shouldWriteAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
2
|
+
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
4
3
|
import { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss } from "./app-route-handler-response.js";
|
|
4
|
+
import { createTrackedAppRouteRequest, markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
|
|
5
5
|
import { createStaticGenerationHeadersContext, getAppRouteStaticGenerationErrorMessage } from "./app-static-generation.js";
|
|
6
|
+
import { resolveAppRouteHandlerSpecialError, shouldApplyAppRouteHandlerRevalidateHeader, shouldWriteAppRouteHandlerCache } from "./app-route-handler-policy.js";
|
|
6
7
|
//#region src/server/app-route-handler-execution.ts
|
|
7
8
|
function configureAppRouteStaticGenerationContext(options) {
|
|
8
9
|
if (options.dynamicConfig === "force-static" || options.dynamicConfig === "error") {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
1
2
|
import { RouteHandlerHttpMethod, RouteHandlerModule } from "./app-route-handler-runtime.js";
|
|
2
3
|
|
|
3
4
|
//#region src/server/app-route-handler-policy.d.ts
|
|
@@ -43,7 +44,6 @@ type AppRouteHandlerSpecialError = {
|
|
|
43
44
|
type AppRouteHandlerSpecialErrorOptions = {
|
|
44
45
|
isAction: boolean;
|
|
45
46
|
};
|
|
46
|
-
declare function isPossibleAppRouteActionRequest(request: Pick<Request, "headers" | "method">): boolean;
|
|
47
47
|
declare function getAppRouteHandlerRevalidateSeconds(handler: Pick<AppRouteHandlerModule, "revalidate">): number | null;
|
|
48
48
|
declare function hasAppRouteHandlerDefaultExport(handler: RouteHandlerModule): boolean;
|
|
49
49
|
declare function resolveAppRouteHandlerMethod(handler: AppRouteHandlerModule, method: string): ResolvedAppRouteHandlerMethod;
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import "./headers.js";
|
|
2
1
|
import { parseNextHttpErrorDigest, parseNextRedirectDigest } from "./next-error-digest.js";
|
|
2
|
+
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
3
3
|
import { buildRouteHandlerAllowHeader, collectRouteHandlerMethods } from "./app-route-handler-runtime.js";
|
|
4
4
|
//#region src/server/app-route-handler-policy.ts
|
|
5
|
-
function isPossibleAppRouteActionRequest(request) {
|
|
6
|
-
if (request.method.toUpperCase() !== "POST") return false;
|
|
7
|
-
const contentType = request.headers.get("content-type");
|
|
8
|
-
return request.headers.has("x-rsc-action") || request.headers.has("next-action") || contentType === "application/x-www-form-urlencoded" || contentType?.startsWith("multipart/form-data") === true;
|
|
9
|
-
}
|
|
10
5
|
function getAppRouteHandlerRevalidateSeconds(handler) {
|
|
11
6
|
const { revalidate } = handler;
|
|
12
7
|
if (revalidate === false) return Infinity;
|
|
@@ -19,6 +19,17 @@ type CreateRscOnErrorHandlerOptions = {
|
|
|
19
19
|
declare function hasDigest(error: unknown): error is {
|
|
20
20
|
digest: unknown;
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* vinext's mirror of Next.js's `getDigestForWellKnownError`: returns the digest
|
|
24
|
+
* string only when the error is a genuine control-flow signal — a redirect,
|
|
25
|
+
* notFound/HTTP-access fallback, bail-out-to-client-side-rendering, or
|
|
26
|
+
* dynamic-server-usage throw. Any other digest (e.g. a hashed digest stamped on
|
|
27
|
+
* a real error, or an obfuscated digest transported from a nested boundary)
|
|
28
|
+
* returns undefined so the caller still reports it as a real error. Mere
|
|
29
|
+
* presence of a `digest` field is NOT enough — that conflation swallowed a class
|
|
30
|
+
* of server render errors with no instrumentation/telemetry.
|
|
31
|
+
*/
|
|
32
|
+
declare function getDigestForWellKnownError(error: unknown): string | undefined;
|
|
22
33
|
/**
|
|
23
34
|
* djb2 hash matching Next.js's string-hash package for RSC error digests.
|
|
24
35
|
*/
|
|
@@ -26,4 +37,4 @@ declare function errorDigest(input: string): string;
|
|
|
26
37
|
declare function sanitizeErrorForClient(error: unknown, nodeEnv?: string | undefined): unknown;
|
|
27
38
|
declare function createRscOnErrorHandler(options: CreateRscOnErrorHandlerOptions): (error: unknown) => string | undefined;
|
|
28
39
|
//#endregion
|
|
29
|
-
export { createRscOnErrorHandler, errorDigest, hasDigest, sanitizeErrorForClient };
|
|
40
|
+
export { createRscOnErrorHandler, errorDigest, getDigestForWellKnownError, hasDigest, sanitizeErrorForClient };
|
|
@@ -1,8 +1,26 @@
|
|
|
1
|
+
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
1
2
|
import { resolveAppPageSpecialError } from "./app-page-execution.js";
|
|
2
3
|
//#region src/server/app-rsc-errors.ts
|
|
3
4
|
function hasDigest(error) {
|
|
4
5
|
return Boolean(error && typeof error === "object" && "digest" in error);
|
|
5
6
|
}
|
|
7
|
+
const BAILOUT_TO_CSR_DIGEST = "BAILOUT_TO_CLIENT_SIDE_RENDERING";
|
|
8
|
+
const DYNAMIC_SERVER_USAGE_DIGEST = "DYNAMIC_SERVER_USAGE";
|
|
9
|
+
/**
|
|
10
|
+
* vinext's mirror of Next.js's `getDigestForWellKnownError`: returns the digest
|
|
11
|
+
* string only when the error is a genuine control-flow signal — a redirect,
|
|
12
|
+
* notFound/HTTP-access fallback, bail-out-to-client-side-rendering, or
|
|
13
|
+
* dynamic-server-usage throw. Any other digest (e.g. a hashed digest stamped on
|
|
14
|
+
* a real error, or an obfuscated digest transported from a nested boundary)
|
|
15
|
+
* returns undefined so the caller still reports it as a real error. Mere
|
|
16
|
+
* presence of a `digest` field is NOT enough — that conflation swallowed a class
|
|
17
|
+
* of server render errors with no instrumentation/telemetry.
|
|
18
|
+
*/
|
|
19
|
+
function getDigestForWellKnownError(error) {
|
|
20
|
+
if (!hasDigest(error)) return;
|
|
21
|
+
const digest = String(error.digest);
|
|
22
|
+
if (isNavigationSignalError(error) || digest === BAILOUT_TO_CSR_DIGEST || digest === DYNAMIC_SERVER_USAGE_DIGEST) return digest;
|
|
23
|
+
}
|
|
6
24
|
function getThrownValueMessage(error) {
|
|
7
25
|
return error instanceof Error ? error.message : String(error);
|
|
8
26
|
}
|
|
@@ -27,14 +45,16 @@ function sanitizeErrorForClient(error, nodeEnv = process.env.NODE_ENV) {
|
|
|
27
45
|
function createRscOnErrorHandler(options) {
|
|
28
46
|
return (error) => {
|
|
29
47
|
const nodeEnv = options.nodeEnv ?? process.env.NODE_ENV;
|
|
30
|
-
|
|
48
|
+
const wellKnownDigest = getDigestForWellKnownError(error);
|
|
49
|
+
if (wellKnownDigest !== void 0) return wellKnownDigest;
|
|
31
50
|
if (nodeEnv !== "production" && error instanceof Error && error.message.includes("Only plain objects, and a few built-ins, can be passed to Client Components")) {
|
|
32
51
|
console.error("[vinext] RSC serialization error: a non-plain object was passed from a Server Component to a Client Component.\n\nCommon causes:\n * Passing a module namespace (import * as X) directly as a prop.\n Unlike Next.js (webpack), Vite produces real ESM module namespace objects\n which are not serializable. Fix: pass individual values instead,\n e.g. <Comp value={module.value} />\n * Passing a class instance (new Foo()) as a prop.\n Fix: convert to a plain object, e.g. { id: foo.id, name: foo.name }\n * Passing a Date, Map, or Set. Use .toISOString(), [...map.entries()], etc.\n * Passing Object.create(null). Use { ...obj } to restore a prototype.\n\nOriginal error:", error.message);
|
|
33
52
|
return;
|
|
34
53
|
}
|
|
35
54
|
if (options.requestInfo && options.errorContext && error) options.reportRequestError(error instanceof Error ? error : new Error(getThrownValueMessage(error)), options.requestInfo, options.errorContext);
|
|
55
|
+
if (hasDigest(error)) return String(error.digest);
|
|
36
56
|
if (nodeEnv === "production" && error) return errorDigest(getThrownValueMessage(error) + getThrownValueStack(error));
|
|
37
57
|
};
|
|
38
58
|
}
|
|
39
59
|
//#endregion
|
|
40
|
-
export { createRscOnErrorHandler, errorDigest, hasDigest, sanitizeErrorForClient };
|
|
60
|
+
export { createRscOnErrorHandler, errorDigest, getDigestForWellKnownError, hasDigest, sanitizeErrorForClient };
|
|
@@ -2,21 +2,25 @@ import { NextHeader, NextI18nConfig, NextRedirect, NextRewrite } from "../config
|
|
|
2
2
|
import { ImageConfig } from "./image-optimization.js";
|
|
3
3
|
import { ClientReuseManifestParseResult } from "./client-reuse-manifest.js";
|
|
4
4
|
import { RootParams } from "../shims/root-params.js";
|
|
5
|
-
import {
|
|
6
|
-
import { AppMiddlewareContext } from "./app-middleware.js";
|
|
5
|
+
import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware.js";
|
|
7
6
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
8
7
|
import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
|
|
9
|
-
import { MetadataRouteMakeThenableParams, MetadataRuntimeRoute } from "./metadata-route-response.js";
|
|
10
8
|
import { ReactFormState } from "react-dom/client";
|
|
11
9
|
|
|
12
10
|
//#region src/server/app-rsc-handler.d.ts
|
|
13
11
|
type AppPageParams = Record<string, string | string[]>;
|
|
14
|
-
type MetadataRoutes = readonly MetadataRuntimeRoute[];
|
|
15
|
-
type MakeThenableParams = MetadataRouteMakeThenableParams;
|
|
16
12
|
type StaticParamsMap = AppPrerenderStaticParamsMap;
|
|
17
13
|
type RootParamNamesMap = AppPrerenderRootParamNamesMap;
|
|
18
14
|
type AppRscMiddlewareContext = AppMiddlewareContext;
|
|
15
|
+
type RunAppMiddlewareOptions = {
|
|
16
|
+
cleanPathname: string;
|
|
17
|
+
context: AppRscMiddlewareContext;
|
|
18
|
+
isDataRequest: boolean;
|
|
19
|
+
request: Request;
|
|
20
|
+
};
|
|
19
21
|
type AppRscHandlerRoute = {
|
|
22
|
+
__loadPage?: unknown;
|
|
23
|
+
__loadRouteHandler?: unknown;
|
|
20
24
|
isDynamic: boolean;
|
|
21
25
|
params?: readonly string[];
|
|
22
26
|
page?: unknown;
|
|
@@ -173,18 +177,15 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
|
|
|
173
177
|
* Node server and dev included, not just the Cloudflare worker entry.
|
|
174
178
|
*/
|
|
175
179
|
registerCacheAdapters: (env?: Record<string, unknown>) => void;
|
|
176
|
-
handleProgressiveActionRequest
|
|
177
|
-
|
|
180
|
+
handleProgressiveActionRequest?: (options: HandleProgressiveActionRequestOptions) => Promise<Response | ProgressiveActionFormStateResult | null>;
|
|
181
|
+
handleMetadataRouteRequest?: (cleanPathname: string) => Promise<Response | null>;
|
|
182
|
+
handleServerActionRequest?: (options: HandleServerActionRequestOptions) => Promise<Response | null>;
|
|
178
183
|
i18nConfig: NextI18nConfig | null;
|
|
179
184
|
imageConfig?: ImageConfig;
|
|
180
185
|
isDev: boolean;
|
|
181
|
-
isMiddlewareProxy: boolean;
|
|
182
186
|
loadPrerenderPagesRoutes?: () => Promise<unknown>;
|
|
183
|
-
makeThenableParams: MakeThenableParams;
|
|
184
187
|
matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
|
|
185
|
-
|
|
186
|
-
middlewareFilePath: string | null;
|
|
187
|
-
middlewareModule: MiddlewareModule | null;
|
|
188
|
+
runMiddleware?: (options: RunAppMiddlewareOptions) => Promise<ApplyAppMiddlewareResult>;
|
|
188
189
|
publicFiles: ReadonlySet<string>;
|
|
189
190
|
renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;
|
|
190
191
|
renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;
|
|
@@ -17,8 +17,9 @@ import "./app-page-response.js";
|
|
|
17
17
|
import { buildNextDataNotFoundResponse, normalizePagesDataRequest } from "./pages-data-route.js";
|
|
18
18
|
import { matchPrerenderRouteParamsPayload, readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
19
19
|
import { getRenderedConcreteUrlPathsForRoute } from "./pregenerated-concrete-paths.js";
|
|
20
|
-
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
21
20
|
import { flattenErrorCauses } from "../utils/error-cause.js";
|
|
21
|
+
import { pickRootParams, setRootParams } from "../shims/root-params.js";
|
|
22
|
+
import { createServerActionNotFoundResponse, getServerActionNotFoundMessage } from "./server-action-not-found.js";
|
|
22
23
|
import { buildPageCacheTags } from "./implicit-tags.js";
|
|
23
24
|
import { buildPostMwRequestContext } from "./app-post-middleware-context.js";
|
|
24
25
|
import { finalizeAppRscResponse } from "./app-rsc-response-finalizer.js";
|
|
@@ -47,6 +48,11 @@ function isExecutionContextLike(value) {
|
|
|
47
48
|
if (!value || typeof value !== "object") return false;
|
|
48
49
|
return hasProperty(value, "waitUntil") && typeof value.waitUntil === "function";
|
|
49
50
|
}
|
|
51
|
+
function createMissingServerActionResponse(options, actionId) {
|
|
52
|
+
console.warn(getServerActionNotFoundMessage(actionId));
|
|
53
|
+
options.clearRequestContext();
|
|
54
|
+
return createServerActionNotFoundResponse();
|
|
55
|
+
}
|
|
50
56
|
function redirectDestinationWithBasePath(destination, basePath) {
|
|
51
57
|
if (!basePath || isExternalUrl(destination) || hasBasePath(destination, basePath)) return destination;
|
|
52
58
|
return basePath + destination;
|
|
@@ -165,19 +171,12 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
165
171
|
status: null
|
|
166
172
|
};
|
|
167
173
|
let didMiddlewareRewrite = false;
|
|
168
|
-
if (options.
|
|
169
|
-
const
|
|
170
|
-
const middlewareResult = await applyAppMiddleware({
|
|
171
|
-
basePath: options.basePath,
|
|
174
|
+
if (options.runMiddleware) {
|
|
175
|
+
const middlewareResult = await options.runMiddleware({
|
|
172
176
|
cleanPathname,
|
|
173
177
|
context: middlewareContext,
|
|
174
|
-
filePath: options.middlewareFilePath ?? void 0,
|
|
175
|
-
i18nConfig: options.i18nConfig,
|
|
176
178
|
isDataRequest,
|
|
177
|
-
|
|
178
|
-
module: options.middlewareModule,
|
|
179
|
-
request: userlandRequest,
|
|
180
|
-
trailingSlash: options.trailingSlash
|
|
179
|
+
request: userlandRequest
|
|
181
180
|
});
|
|
182
181
|
if (middlewareResult.kind === "response") return applyConfigHeadersToMiddlewareRedirect(middlewareResult.response, {
|
|
183
182
|
basePathState,
|
|
@@ -211,13 +210,8 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
211
210
|
if (!imageRedirect) return new Response("Invalid image optimization parameters", { status: 400 });
|
|
212
211
|
return Response.redirect(new URL(imageRedirect, url.origin).href, 302);
|
|
213
212
|
}
|
|
214
|
-
if (options.
|
|
215
|
-
const
|
|
216
|
-
const metadataRouteResponse = await handleMetadataRouteRequest({
|
|
217
|
-
metadataRoutes: options.metadataRoutes,
|
|
218
|
-
cleanPathname,
|
|
219
|
-
makeThenableParams: options.makeThenableParams
|
|
220
|
-
});
|
|
213
|
+
if (options.handleMetadataRouteRequest) {
|
|
214
|
+
const metadataRouteResponse = await options.handleMetadataRouteRequest(cleanPathname);
|
|
221
215
|
if (metadataRouteResponse) {
|
|
222
216
|
applyConfigHeadersToResponse(metadataRouteResponse.headers, {
|
|
223
217
|
basePathState,
|
|
@@ -255,13 +249,16 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
255
249
|
const contentType = request.headers.get("content-type") || "";
|
|
256
250
|
const isPostRequest = request.method.toUpperCase() === "POST";
|
|
257
251
|
let progressiveActionResult = null;
|
|
258
|
-
if (isPostRequest && contentType.startsWith("multipart/form-data") && !actionId)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
252
|
+
if (isPostRequest && contentType.startsWith("multipart/form-data") && !actionId) {
|
|
253
|
+
if (options.handleProgressiveActionRequest) progressiveActionResult = await options.handleProgressiveActionRequest({
|
|
254
|
+
actionId,
|
|
255
|
+
cleanPathname,
|
|
256
|
+
contentType,
|
|
257
|
+
middlewareContext,
|
|
258
|
+
request
|
|
259
|
+
});
|
|
260
|
+
else if (preActionMatch?.route.__loadPage && !preActionMatch.route.__loadRouteHandler) return createMissingServerActionResponse(options, null);
|
|
261
|
+
}
|
|
265
262
|
if (progressiveActionResult instanceof Response) return progressiveActionResult;
|
|
266
263
|
const progressiveActionFormState = progressiveActionResult?.kind === "form-state" ? progressiveActionResult : null;
|
|
267
264
|
const isProgressiveActionRender = progressiveActionFormState !== null;
|
|
@@ -269,7 +266,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
269
266
|
const failedProgressiveActionResult = progressiveActionFormState && "actionError" in progressiveActionFormState ? progressiveActionFormState : null;
|
|
270
267
|
const actionFailed = failedProgressiveActionResult !== null;
|
|
271
268
|
const actionError = failedProgressiveActionResult?.actionError;
|
|
272
|
-
const serverActionResponse = isPostRequest && actionId ? await options.handleServerActionRequest({
|
|
269
|
+
const serverActionResponse = isPostRequest && actionId && options.handleServerActionRequest ? await options.handleServerActionRequest({
|
|
273
270
|
actionId,
|
|
274
271
|
cleanPathname,
|
|
275
272
|
contentType,
|
|
@@ -281,6 +278,7 @@ async function handleAppRscRequest(options, request, preMiddlewareRequestContext
|
|
|
281
278
|
searchParams: getResolvedSearchParams()
|
|
282
279
|
}) : null;
|
|
283
280
|
if (serverActionResponse) return serverActionResponse;
|
|
281
|
+
if (isPostRequest && actionId && !options.handleServerActionRequest) return createMissingServerActionResponse(options, actionId);
|
|
284
282
|
let match = preActionMatch;
|
|
285
283
|
const renderPagesForMatchKind = async (matchKind) => {
|
|
286
284
|
const response = match === null || match.route.isDynamic ? await options.renderPagesFallback?.({
|
|
@@ -22,7 +22,11 @@ import { mergeVaryHeader } from "./middleware-response-headers.js";
|
|
|
22
22
|
*/
|
|
23
23
|
function finalizeAppRscResponse(response, request, options) {
|
|
24
24
|
if (response.status >= 300 && response.status < 400) return response;
|
|
25
|
-
if (!response.headers.has("x-vinext-static-file"))
|
|
25
|
+
if (!response.headers.has("x-vinext-static-file")) {
|
|
26
|
+
const varyHeader = response.headers.get("Vary");
|
|
27
|
+
if (varyHeader === null) response.headers.set("Vary", VINEXT_RSC_VARY_HEADER);
|
|
28
|
+
else if (varyHeader !== VINEXT_RSC_VARY_HEADER) mergeVaryHeader(response.headers, VINEXT_RSC_VARY_HEADER);
|
|
29
|
+
}
|
|
26
30
|
if (!response.headers.has("Cache-Control")) applyCdnResponseHeaders(response.headers, { cacheControl: "" });
|
|
27
31
|
if (!options.configHeaders.length) return response;
|
|
28
32
|
const url = new URL(request.url);
|
|
@@ -377,7 +377,7 @@ async function handleProgressiveServerActionRequest(options) {
|
|
|
377
377
|
options.setHeadersAccessPhase(previousHeadersPhase);
|
|
378
378
|
}
|
|
379
379
|
if (!actionRedirect) {
|
|
380
|
-
const actionPendingCookies = options.getAndClearPendingCookies();
|
|
380
|
+
const actionPendingCookies = dedupePendingCookies(options.getAndClearPendingCookies());
|
|
381
381
|
const actionDraftCookie = options.getDraftModeCookieHeader();
|
|
382
382
|
const revalidationKind = resolveActionRevalidationKind(actionPendingCookies.length > 0 || Boolean(actionDraftCookie));
|
|
383
383
|
if (actionFailed) return {
|
|
@@ -18,7 +18,7 @@ import { createSsrErrorMetaRenderer } from "./app-ssr-error-meta.js";
|
|
|
18
18
|
import { createNavigationRuntimeRscMetadataScript, createRscEmbedTransform, createTickBufferedTransform } from "./app-ssr-stream.js";
|
|
19
19
|
import { BeforeInteractiveContext } from "../shims/before-interactive-context.js";
|
|
20
20
|
import { runWithRootParamsScope } from "../shims/root-params.js";
|
|
21
|
-
import {
|
|
21
|
+
import { createInitialBfcacheMaps } from "./app-bfcache-identity.js";
|
|
22
22
|
import { RSC_FORM_STATE_GLOBAL } from "./app-browser-hydration.js";
|
|
23
23
|
import { createClientReferencePreloader } from "./app-client-reference-preloader.js";
|
|
24
24
|
import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
|
|
@@ -186,12 +186,14 @@ async function handleSsr(rscStream, navContext, fontData, options) {
|
|
|
186
186
|
const wireElements = use(flightRoot);
|
|
187
187
|
const elements = AppElementsWire.decode(wireElements);
|
|
188
188
|
const metadata = AppElementsWire.readMetadata(elements);
|
|
189
|
-
const
|
|
190
|
-
const stateKeyTree = createElement(BfcacheStateKeyMapContext.Provider, { value: createBfcacheSegmentStateKeyMap({
|
|
189
|
+
const bfcacheMaps = createInitialBfcacheMaps({
|
|
191
190
|
elements,
|
|
191
|
+
metadata,
|
|
192
192
|
pathname: ssrNavigationContext.pathname
|
|
193
|
-
})
|
|
194
|
-
|
|
193
|
+
});
|
|
194
|
+
const routeTree = createElement(ElementsContext.Provider, { value: elements }, createElement(Slot, { id: metadata.routeId }));
|
|
195
|
+
const stateKeyTree = createElement(BfcacheStateKeyMapContext.Provider, { value: bfcacheMaps.stateKeys }, routeTree);
|
|
196
|
+
return BfcacheIdMapContext ? createElement(BfcacheIdMapContext.Provider, { value: bfcacheMaps.bfcacheIds }, stateKeyTree) : stateKeyTree;
|
|
195
197
|
}
|
|
196
198
|
const flightRootElement = createElement(VinextFlightRoot);
|
|
197
199
|
const root = AppRouterContext ? createElement(AppRouterContext.Provider, { value: ssrAppRouterInstance }, flightRootElement) : flightRootElement;
|
|
@@ -13,4 +13,4 @@ type MetadataRouteRequestOptions = {
|
|
|
13
13
|
};
|
|
14
14
|
declare function handleMetadataRouteRequest(options: MetadataRouteRequestOptions): Promise<Response | null>;
|
|
15
15
|
//#endregion
|
|
16
|
-
export {
|
|
16
|
+
export { MetadataRuntimeRoute, handleMetadataRouteRequest };
|
package/dist/shims/dynamic.js
CHANGED
|
@@ -127,7 +127,7 @@ function dynamic(dynamicInput, options) {
|
|
|
127
127
|
const preloadModuleIds = loadableGenerated?.modules ?? modules;
|
|
128
128
|
if (!ssr) {
|
|
129
129
|
if (isServer) {
|
|
130
|
-
const SSRFalse = (_props) => LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps(
|
|
130
|
+
const SSRFalse = (_props) => LoadingComponent ? React.createElement(LoadingComponent, createDynamicLoadingProps()) : null;
|
|
131
131
|
SSRFalse.displayName = "DynamicSSRFalse";
|
|
132
132
|
return SSRFalse;
|
|
133
133
|
}
|