vinext 1.3.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -22
- package/THIRD_PARTY_LICENSES.md +47 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -2
- package/dist/build/prerender.js +4 -3
- package/dist/build/report.d.ts +0 -14
- package/dist/build/report.js +1 -51
- package/dist/check.js +4 -7
- package/dist/cli.js +3 -0
- package/dist/client/dev-error-overlay-store.d.ts +1 -0
- package/dist/client/dev-error-overlay.d.ts +2 -0
- package/dist/client/dev-error-overlay.js +20 -4
- package/dist/client/navigation-runtime.d.ts +13 -1
- package/dist/client/navigation-runtime.js +1 -1
- package/dist/config/config-matchers.js +2 -0
- package/dist/config/destination-params.d.ts +2 -1
- package/dist/config/destination-params.js +52 -2
- package/dist/config/next-config.d.ts +25 -0
- package/dist/config/next-config.js +82 -4
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-codec.js +327 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/dbcs-data.js +123 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/index.js +29 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/internal.js +134 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-codec.js +50 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data-generated.js +455 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/sbcs-data.js +147 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/big5-added.json.js +169 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp936.json.js +2584 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp949.json.js +2220 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/cp950.json.js +227 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/eucjp.json.js +425 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gb18030-ranges.json.js +427 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/gbk-added.json.js +229 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/tables/shiftjis.json.js +292 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf16.js +106 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/encodings/utf7.js +182 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/bom-handling.js +42 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/extend-node.js +147 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/index.js +94 -0
- package/dist/deps/.pnpm/iconv-lite@0.4.24/deps/iconv-lite/lib/streams.js +95 -0
- package/dist/deps/.pnpm/safer-buffer@2.1.2/deps/safer-buffer/safer.js +45 -0
- package/dist/entries/app-rsc-entry.js +17 -49
- package/dist/entries/app-rsc-manifest.js +3 -4
- package/dist/entries/app-ssr-entry.js +1 -0
- package/dist/entries/pages-server-entry.js +36 -9
- package/dist/index.js +112 -90
- package/dist/init-cloudflare.d.ts +1 -3
- package/dist/init-cloudflare.js +10 -48
- package/dist/init-platform.d.ts +2 -0
- package/dist/init-platform.js +4 -0
- package/dist/plugins/extensionless-dynamic-import.js +6 -2
- package/dist/plugins/next-intl-catalog.d.ts +12 -0
- package/dist/plugins/next-intl-catalog.js +85 -0
- package/dist/plugins/pages-node-externals.d.ts +1 -0
- package/dist/plugins/pages-node-externals.js +1 -1
- package/dist/plugins/strip-server-exports.js +2 -1
- package/dist/plugins/use-cache-callable.d.ts +1 -1
- package/dist/plugins/use-cache-callable.js +136 -94
- package/dist/routing/app-route-graph.d.ts +6 -0
- package/dist/routing/app-route-graph.js +9 -1
- package/dist/server/api-handler.js +21 -5
- package/dist/server/app-bfcache-identity.js +1 -1
- package/dist/server/app-browser-entry.js +86 -66
- package/dist/server/app-browser-history-controller.d.ts +5 -4
- package/dist/server/app-browser-history-controller.js +93 -15
- package/dist/server/app-browser-navigation-controller.d.ts +2 -2
- package/dist/server/app-browser-navigation-controller.js +1 -2
- package/dist/server/app-browser-rsc-redirect.js +7 -7
- package/dist/server/app-browser-server-action-client.d.ts +2 -0
- package/dist/server/app-browser-server-action-client.js +5 -4
- package/dist/server/app-browser-state.d.ts +2 -4
- package/dist/server/app-browser-state.js +9 -4
- package/dist/server/app-browser-supplemental-refresh.js +16 -1
- package/dist/server/app-browser-visible-commit.d.ts +1 -1
- package/dist/server/app-browser-visible-commit.js +4 -14
- package/dist/server/app-elements-wire.d.ts +6 -38
- package/dist/server/app-elements-wire.js +4 -41
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-history-state.d.ts +2 -2
- package/dist/server/app-history-state.js +5 -2
- package/dist/server/app-mounted-layouts.d.ts +21 -0
- package/dist/server/app-mounted-layouts.js +67 -0
- package/dist/server/app-optimistic-routing.d.ts +19 -1
- package/dist/server/app-optimistic-routing.js +43 -4
- package/dist/server/app-page-boundary-render.js +10 -14
- package/dist/server/app-page-boundary.js +2 -2
- package/dist/server/app-page-cache-finalizer.d.ts +12 -1
- package/dist/server/app-page-cache-finalizer.js +70 -29
- package/dist/server/app-page-cache.d.ts +13 -1
- package/dist/server/app-page-cache.js +31 -9
- package/dist/server/app-page-dispatch.d.ts +5 -11
- package/dist/server/app-page-dispatch.js +84 -155
- package/dist/server/app-page-element-builder.d.ts +2 -2
- package/dist/server/app-page-element-builder.js +13 -12
- package/dist/server/app-page-execution.d.ts +17 -52
- package/dist/server/app-page-execution.js +102 -95
- package/dist/server/app-page-head.d.ts +13 -0
- package/dist/server/app-page-head.js +44 -16
- package/dist/server/app-page-http-access-fallback-metadata.d.ts +1 -0
- package/dist/server/app-page-http-access-fallback-metadata.js +2 -2
- package/dist/server/app-page-layout-gate.d.ts +35 -0
- package/dist/server/app-page-layout-gate.js +50 -0
- package/dist/server/app-page-params.d.ts +0 -1
- package/dist/server/app-page-params.js +1 -14
- package/dist/server/app-page-probe.d.ts +3 -21
- package/dist/server/app-page-probe.js +4 -37
- package/dist/server/app-page-render.d.ts +2 -13
- package/dist/server/app-page-render.js +103 -234
- package/dist/server/app-page-request.d.ts +1 -3
- package/dist/server/app-page-request.js +1 -1
- package/dist/server/app-page-response.js +3 -3
- package/dist/server/app-page-route-wiring.d.ts +13 -6
- package/dist/server/app-page-route-wiring.js +86 -63
- package/dist/server/app-page-rsc-render-status.d.ts +27 -1
- package/dist/server/app-page-rsc-render-status.js +121 -13
- package/dist/server/app-page-stream.d.ts +12 -8
- package/dist/server/app-page-stream.js +4 -3
- package/dist/server/app-pages-bridge.d.ts +4 -0
- package/dist/server/app-pages-bridge.js +7 -3
- package/dist/server/app-render-dependency.d.ts +11 -4
- package/dist/server/app-render-dependency.js +86 -38
- package/dist/server/app-request-stage-dispatch.js +1 -1
- package/dist/server/app-request-stage-independent-entry.js +1 -1
- package/dist/server/app-route-handler-cache.js +2 -2
- package/dist/server/app-route-handler-dispatch.js +14 -9
- package/dist/server/app-route-handler-execution.js +11 -5
- package/dist/server/app-route-handler-policy.d.ts +1 -1
- package/dist/server/app-route-handler-policy.js +3 -3
- package/dist/server/app-route-handler-response.js +1 -1
- package/dist/server/app-route-handler-runtime.d.ts +1 -1
- package/dist/server/app-route-handler-runtime.js +28 -11
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +12 -12
- package/dist/server/app-rsc-cache-busting.js +31 -72
- package/dist/server/app-rsc-error-handler.d.ts +2 -1
- package/dist/server/app-rsc-error-handler.js +10 -2
- package/dist/server/app-rsc-errors.d.ts +8 -0
- package/dist/server/app-rsc-errors.js +11 -1
- package/dist/server/app-rsc-handler.d.ts +5 -5
- package/dist/server/app-rsc-handler.js +80 -83
- package/dist/server/app-rsc-request-normalization.d.ts +10 -16
- package/dist/server/app-rsc-request-normalization.js +12 -18
- package/dist/server/app-rsc-response-finalizer.js +2 -2
- package/dist/server/app-rsc-response-stage.js +9 -15
- package/dist/server/app-server-action-execution.d.ts +3 -1
- package/dist/server/app-server-action-execution.js +15 -8
- package/dist/server/app-ssr-entry.d.ts +8 -0
- package/dist/server/app-ssr-entry.js +22 -16
- package/dist/server/app-ssr-stream.js +1 -1
- package/dist/server/app-visited-response-cache.d.ts +36 -1
- package/dist/server/app-visited-response-cache.js +46 -5
- package/dist/server/app-worker-stages.d.ts +37 -6
- package/dist/server/app-worker-stages.js +81 -9
- package/dist/server/artifact-compatibility.d.ts +0 -1
- package/dist/server/artifact-compatibility.js +1 -10
- package/dist/server/bfcache-identity.d.ts +7 -0
- package/dist/server/bfcache-identity.js +10 -1
- package/dist/server/cache-proof.d.ts +1 -115
- package/dist/server/cache-proof.js +1 -544
- package/dist/server/cacheability-manifest.js +1 -2
- package/dist/server/cacheability-request.js +13 -8
- package/dist/server/dev-origin-check.d.ts +2 -1
- package/dist/server/dev-origin-check.js +2 -1
- package/dist/server/dev-server.js +6 -4
- package/dist/server/headers.d.ts +6 -3
- package/dist/server/headers.js +9 -5
- package/dist/server/image-optimization.d.ts +5 -0
- package/dist/server/image-optimization.js +6 -1
- package/dist/server/isr-cache.d.ts +8 -2
- package/dist/server/isr-cache.js +30 -2
- package/dist/server/metadata-route-response.js +32 -15
- package/dist/server/middleware-matcher.js +19 -6
- package/dist/server/middleware-runtime.js +6 -2
- package/dist/server/multi-stage.d.ts +57 -12
- package/dist/server/multi-stage.js +13 -1
- package/dist/server/navigation-planner.js +1 -1
- package/dist/server/pages-api-route.js +28 -19
- package/dist/server/pages-media-type.d.ts +21 -1
- package/dist/server/pages-media-type.js +69 -5
- package/dist/server/pages-node-compat.d.ts +1 -1
- package/dist/server/pages-node-compat.js +54 -27
- package/dist/server/pages-page-data.js +2 -1
- package/dist/server/pages-page-handler.js +28 -26
- package/dist/server/pages-page-response.d.ts +9 -0
- package/dist/server/pages-page-response.js +18 -4
- package/dist/server/pages-request-pipeline.d.ts +8 -0
- package/dist/server/pages-request-pipeline.js +2 -2
- package/dist/server/pages-request-stage-entry.js +36 -14
- package/dist/server/pages-response-stage-entry.js +9 -3
- package/dist/server/pages-router-entry.js +3 -2
- package/dist/server/prod-server.d.ts +2 -2
- package/dist/server/prod-server.js +47 -9
- package/dist/server/request-error-log.d.ts +9 -0
- package/dist/server/request-error-log.js +13 -0
- package/dist/server/request-pipeline.d.ts +15 -4
- package/dist/server/request-pipeline.js +43 -15
- package/dist/server/rsc-completion-metadata.js +3 -0
- package/dist/server/shared-cache-identity.d.ts +23 -0
- package/dist/server/shared-cache-identity.js +36 -0
- package/dist/server/static-file-cache.d.ts +9 -0
- package/dist/server/static-file-cache.js +13 -2
- package/dist/server/worker-stages.d.ts +16 -3
- package/dist/server/worker-stages.js +23 -4
- package/dist/shims/cache-handler.js +2 -2
- package/dist/shims/cache-request-state.d.ts +23 -26
- package/dist/shims/cache-request-state.js +22 -57
- package/dist/shims/cache-runtime.d.ts +3 -1
- package/dist/shims/cache-runtime.js +94 -48
- package/dist/shims/cache.d.ts +16 -10
- package/dist/shims/cache.js +47 -36
- package/dist/shims/cacheability-classification.d.ts +2 -0
- package/dist/shims/cdn-cache.d.ts +22 -5
- package/dist/shims/client-hook-error.d.ts +2 -0
- package/dist/shims/client-hook-error.js +16 -1
- package/dist/shims/client-page-root.js +2 -2
- package/dist/shims/dynamic.js +9 -6
- package/dist/shims/error-boundary.js +2 -2
- package/dist/shims/fetch-cache-state.d.ts +5 -1
- package/dist/shims/fetch-cache-state.js +1 -3
- package/dist/shims/fetch-cache.d.ts +2 -1
- package/dist/shims/fetch-cache.js +39 -25
- package/dist/shims/form.js +2 -2
- package/dist/shims/headers.d.ts +10 -24
- package/dist/shims/headers.js +22 -70
- package/dist/shims/internal/cache-context-accessor.d.ts +1 -1
- package/dist/shims/internal/navigation-untracked.js +1 -1
- package/dist/shims/link.js +8 -11
- package/dist/shims/metadata.d.ts +23 -21
- package/dist/shims/metadata.js +62 -24
- package/dist/shims/navigation-server.js +1 -1
- package/dist/shims/navigation.d.ts +74 -7
- package/dist/shims/navigation.js +184 -31
- package/dist/shims/navigation.react-server.js +2 -2
- package/dist/shims/request-state-types.d.ts +3 -2
- package/dist/shims/slot.d.ts +16 -0
- package/dist/shims/slot.js +44 -9
- package/dist/shims/unified-request-context.d.ts +7 -1
- package/dist/shims/unified-request-context.js +3 -3
- package/dist/utils/cache-control-metadata.d.ts +5 -0
- package/dist/utils/cache-control-metadata.js +9 -1
- package/dist/utils/cache-life-profiles.d.ts +33 -0
- package/dist/utils/cache-life-profiles.js +111 -0
- package/dist/utils/middleware-request-headers.d.ts +14 -3
- package/dist/utils/middleware-request-headers.js +54 -7
- package/dist/utils/project.d.ts +2 -2
- package/dist/utils/project.js +3 -16
- package/dist/utils/regex.d.ts +5 -0
- package/dist/utils/regex.js +11 -1
- package/dist/utils/text-stream.d.ts +10 -5
- package/dist/utils/text-stream.js +6 -6
- package/package.json +2 -1
- package/dist/build/layout-classification-types.d.ts +0 -60
- package/dist/build/layout-classification-types.js +0 -1
- package/dist/build/layout-classification.d.ts +0 -62
- package/dist/build/layout-classification.js +0 -98
- package/dist/build/route-classification-injector.d.ts +0 -33
- package/dist/build/route-classification-injector.js +0 -59
- package/dist/build/route-classification-manifest.d.ts +0 -54
- package/dist/build/route-classification-manifest.js +0 -143
- package/dist/server/app-browser-client-reuse-manifest.d.ts +0 -11
- package/dist/server/app-browser-client-reuse-manifest.js +0 -101
- package/dist/server/app-layout-param-observation.d.ts +0 -42
- package/dist/server/app-layout-param-observation.js +0 -168
- package/dist/server/client-reuse-manifest.d.ts +0 -103
- package/dist/server/client-reuse-manifest.js +0 -209
- package/dist/server/skip-cache-proof.d.ts +0 -60
- package/dist/server/skip-cache-proof.js +0 -168
- package/dist/server/static-layout-client-reuse-proof.d.ts +0 -14
- package/dist/server/static-layout-client-reuse-proof.js +0 -33
- package/dist/utils/sorted-array.d.ts +0 -8
- package/dist/utils/sorted-array.js +0 -20
|
@@ -2,14 +2,14 @@ import { VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_VARY_HEADER } from "./app-rsc-v
|
|
|
2
2
|
import { NEXT_CACHE_TAGS_HEADER, NEXT_ROUTER_STALE_TIME_HEADER, VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_PARAMS_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_STALE_TIME_PENDING_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
|
|
3
3
|
import { NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, buildRevalidateCacheControl } from "./cache-control.js";
|
|
4
4
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
5
|
-
import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
|
|
6
|
-
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
7
5
|
import { applyPrerenderCacheLifeHeader } from "./prerender-cache-life-header.js";
|
|
8
6
|
import { markFrameworkLinkHeaders } from "./app-response-header-provenance.js";
|
|
7
|
+
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
8
|
+
import { VINEXT_RSC_CONTENT_TYPE, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
|
|
9
9
|
//#region src/server/app-page-response.ts
|
|
10
10
|
function applyTimingHeader(headers, timing) {
|
|
11
11
|
if (!timing) return;
|
|
12
|
-
const handlerStart = Math.round(timing.handlerStart);
|
|
12
|
+
const handlerStart = Math.round(Date.now() - (performance.now() - timing.handlerStart));
|
|
13
13
|
const compileMs = timing.compileEnd !== void 0 ? Math.round(timing.compileEnd - timing.handlerStart) : -1;
|
|
14
14
|
const renderMs = timing.responseKind === "html" && timing.renderEnd !== void 0 && timing.compileEnd !== void 0 ? Math.round(timing.renderEnd - timing.compileEnd) : -1;
|
|
15
15
|
headers.set(VINEXT_TIMING_HEADER, `${handlerStart},${compileMs},${renderMs}`);
|
|
@@ -3,9 +3,7 @@ import { AppElements, AppElementsInterception, AppElementsSlotBinding } from "./
|
|
|
3
3
|
import "./app-elements.js";
|
|
4
4
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
5
5
|
import { AppPageParams } from "./app-page-boundary.js";
|
|
6
|
-
import { ThenableParamsObserver } from "../shims/thenable-params.js";
|
|
7
6
|
import { Metadata, Viewport } from "../shims/metadata.js";
|
|
8
|
-
import { AppLayoutParamAccessTracker } from "./app-layout-param-observation.js";
|
|
9
7
|
import { AppPageRenderDependency } from "./app-render-dependency.js";
|
|
10
8
|
import { AppPageSemanticSegment, resolveAppPageChildSegments } from "./app-page-segment-state.js";
|
|
11
9
|
import { AppPageRenderIdentity } from "./app-page-render-identity.js";
|
|
@@ -172,7 +170,6 @@ type BuildAppPageRouteElementOptions<TModule extends AppPageModule = AppPageModu
|
|
|
172
170
|
*/
|
|
173
171
|
renderElementWithMetadataOutlet?: ((metadataOutlet: ReactNode) => ReactNode) | null;
|
|
174
172
|
globalErrorModule?: TErrorModule | null;
|
|
175
|
-
layoutParamAccess?: AppLayoutParamAccessTracker;
|
|
176
173
|
makeThenableParams: MakeThenableParams;
|
|
177
174
|
matchedParams: AppPageParams;
|
|
178
175
|
metadataPlacement?: "body" | "head";
|
|
@@ -211,7 +208,7 @@ export type AppPageRouteHead = {
|
|
|
211
208
|
/** `null` when resolution failed: like Next.js, the head then has no viewport tags. */
|
|
212
209
|
viewport: Promise<Viewport | null>;
|
|
213
210
|
};
|
|
214
|
-
type MakeThenableParams = (params: AppPageParams
|
|
211
|
+
type MakeThenableParams = (params: AppPageParams) => unknown;
|
|
215
212
|
type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule, TErrorModule extends AppPageErrorModule = AppPageErrorModule> = BuildAppPageRouteElementOptions<TModule, TErrorModule> & {
|
|
216
213
|
interception?: AppElementsInterception | null;
|
|
217
214
|
interceptionId?: string | null;
|
|
@@ -226,6 +223,13 @@ type BuildAppPageElementsOptions<TModule extends AppPageModule = AppPageModule,
|
|
|
226
223
|
* still store the route tree, as a CDN would store Next.js's.
|
|
227
224
|
*/
|
|
228
225
|
isUncacheableRender?: boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Hashed segment identities of the layouts the navigating client holds (see
|
|
228
|
+
* app-mounted-layouts.ts). A render that can never be stored leaves out the
|
|
229
|
+
* outermost layouts it names, as Next.js renders only below where a
|
|
230
|
+
* navigation diverges from the client's router state.
|
|
231
|
+
*/
|
|
232
|
+
mountedLayouts?: ReadonlySet<string> | null;
|
|
229
233
|
mountedSlotIds?: ReadonlySet<string> | null;
|
|
230
234
|
renderIdentity?: AppPageRenderIdentity;
|
|
231
235
|
renderMode?: AppRscRenderMode;
|
|
@@ -246,9 +250,12 @@ export type AppPageTemplateEntry<TModule extends AppPageModule = AppPageModule>
|
|
|
246
250
|
treePosition: number;
|
|
247
251
|
};
|
|
248
252
|
export declare function createAppPageTreePath(routeSegments: readonly string[] | null | undefined, treePosition: number): string;
|
|
249
|
-
|
|
253
|
+
/**
|
|
254
|
+
* Renders the layout at `layoutIndex` with a placeholder for its children, so
|
|
255
|
+
* whatever it or a component it renders throws comes out.
|
|
256
|
+
*/
|
|
257
|
+
export declare function probeAppPageLayout<TModule extends AppPageModule>(options: {
|
|
250
258
|
layoutIndex: number;
|
|
251
|
-
layoutParamAccess: AppLayoutParamAccessTracker | undefined;
|
|
252
259
|
makeThenableParams: MakeThenableParams;
|
|
253
260
|
matchedParams: AppPageParams;
|
|
254
261
|
route: Pick<AppPageRouteWiringRoute<TModule>, "layoutTreePositions" | "layouts" | "routeSegments">;
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import { APP_RSC_RENDER_MODE_PREFETCH_EMPTY, APP_RSC_RENDER_MODE_PREFETCH_LOADING_SHELL } from "./app-rsc-render-mode.js";
|
|
2
2
|
import { fnv1a64 } from "../utils/hash.js";
|
|
3
3
|
import { createInlineScriptTag, escapeHtmlAttr } from "./html.js";
|
|
4
|
-
import {
|
|
5
|
-
import { APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
4
|
+
import { APP_LAYOUT_IDS_KEY, APP_ROOT_LAYOUT_KEY, APP_SKIPPED_LAYOUT_IDS_KEY, APP_STATIC_SIBLINGS_KEY, AppElementsWire, normalizeAppElementsSlotBindings } from "./app-elements-wire.js";
|
|
6
5
|
import { APP_PREFETCH_LOADING_SHELL_MARKER_KEY, APP_STREAMING_METADATA_BODY_ID_PREFIX } from "./app-elements.js";
|
|
6
|
+
import { createBfcacheChildSegmentStateKey } from "./bfcache-identity.js";
|
|
7
|
+
import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
|
|
8
|
+
import { hashMountedLayoutIdentity } from "./app-mounted-layouts.js";
|
|
9
|
+
import { BfcacheChildrenBoundary, BfcacheSegmentBoundary, Children as Children$1, ParallelSlot, Slot } from "../shims/slot.js";
|
|
10
|
+
import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPageChildSegments, resolveAppPageSegmentStateKey, resolveAppPageTemplateStateKey } from "./app-page-segment-state.js";
|
|
7
11
|
import DefaultGlobalError from "../shims/default-global-error.js";
|
|
8
12
|
import { ErrorBoundary, ForbiddenBoundary, GlobalErrorBoundary, HttpAccessFallbackPassthrough, NotFoundBoundary, RedirectBoundary, UnauthorizedBoundary } from "../shims/error-boundary.js";
|
|
9
|
-
import { AppRouterScrollTarget } from "../shims/app-router-scroll.js";
|
|
10
|
-
import DefaultForbidden from "../shims/default-forbidden.js";
|
|
11
|
-
import DefaultNotFound from "../shims/default-not-found.js";
|
|
12
|
-
import DefaultUnauthorized from "../shims/default-unauthorized.js";
|
|
13
13
|
import { LayoutSegmentProvider } from "../shims/layout-segment-context.js";
|
|
14
14
|
import { withUseCacheLayoutMarker } from "../shims/internal/app-page-props-cache-key.js";
|
|
15
15
|
import { MetadataHead, ViewportHead, renderMetadataToHtml } from "../shims/metadata.js";
|
|
16
|
-
import {
|
|
16
|
+
import { APP_PAGE_NOT_FOUND_BOUNDARY_ID, tagAppPageLayoutError, tagAppPageSlotError } from "./app-page-execution.js";
|
|
17
|
+
import { resolveAppPageBranchParams, resolveAppPageSegmentParams } from "./app-page-params.js";
|
|
18
|
+
import DefaultForbidden from "../shims/default-forbidden.js";
|
|
19
|
+
import DefaultNotFound from "../shims/default-not-found.js";
|
|
20
|
+
import DefaultUnauthorized from "../shims/default-unauthorized.js";
|
|
17
21
|
import { StreamedIconsInsertion } from "../shims/streamed-icons.js";
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
22
|
+
import { createAppRenderDependency, invokeAppComponentMappingErrors, isReactOwnedAppComponent, renderAfterAppDependencies, renderAppComponentWithDependencyBarrier } from "./app-render-dependency.js";
|
|
23
|
+
import { createAppPageLayoutGate, registerAppPageLayoutGate } from "./app-page-layout-gate.js";
|
|
20
24
|
import { probeReactServerSubtree } from "./app-page-probe.js";
|
|
21
|
-
import { APP_PAGE_SEGMENT_KEY, isAppPageRouteGroupSegment, resolveAppPageChildSegments, resolveAppPageSegmentStateKey, resolveAppPageTemplateStateKey } from "./app-page-segment-state.js";
|
|
22
25
|
import { createAppPageSegmentPlan } from "./app-page-segment-plan.js";
|
|
23
26
|
import { resolveAppPageModuleTraceSegment, traceGetLayoutOrPageModule } from "./app-page-tracing.js";
|
|
24
27
|
import { Fragment, Suspense } from "react";
|
|
@@ -44,6 +47,21 @@ function createSlotLayoutElement(LayoutComponent, props, slotLayoutIndex, notFou
|
|
|
44
47
|
const SlotLayoutInvoker = () => invokeAppComponentMappingErrors(LayoutComponent, props, (error) => tagAppPageSlotError(error, slotLayoutIndex, notFoundBoundary));
|
|
45
48
|
return /* @__PURE__ */ jsx(SlotLayoutInvoker, {});
|
|
46
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* A route layout, whose notFound(), forbidden() and unauthorized() are caught
|
|
52
|
+
* above it: its own boundaries wrap only its `children`. The layout's index
|
|
53
|
+
* tags what it throws, so the response's fallback finds that boundary from the
|
|
54
|
+
* render. `onSettled` hears how the layout rendered.
|
|
55
|
+
* https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/create-component-tree.tsx
|
|
56
|
+
*/
|
|
57
|
+
function createRouteLayoutElement(LayoutComponent, props, layoutIndex, dependency, onSettled) {
|
|
58
|
+
const mapError = (error) => tagAppPageLayoutError(error, layoutIndex);
|
|
59
|
+
if (dependency) return renderAppComponentWithDependencyBarrier(LayoutComponent, props, dependency, mapError, onSettled);
|
|
60
|
+
if (isReactOwnedAppComponent(LayoutComponent)) return /* @__PURE__ */ jsx(LayoutComponent, { ...props });
|
|
61
|
+
const RouteLayoutInvoker = () => invokeAppComponentMappingErrors(LayoutComponent, props, mapError, onSettled);
|
|
62
|
+
RouteLayoutInvoker.displayName = LayoutComponent.displayName ?? LayoutComponent.name;
|
|
63
|
+
return /* @__PURE__ */ jsx(RouteLayoutInvoker, {});
|
|
64
|
+
}
|
|
47
65
|
function getDefaultExport(module) {
|
|
48
66
|
return module?.default ?? null;
|
|
49
67
|
}
|
|
@@ -55,37 +73,19 @@ function createAppPageTreePath(routeSegments, treePosition) {
|
|
|
55
73
|
if (treePathSegments.length === 0) return "/";
|
|
56
74
|
return `/${treePathSegments.join("/")}`;
|
|
57
75
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
function
|
|
63
|
-
options.layoutParamAccess?.recordLayoutParamScope(options.layoutId, resolveAppPageSegmentParamScopeKeys(options.routeSegments, options.treePosition));
|
|
64
|
-
const revalidateSeconds = readFiniteRevalidateSeconds(options.layoutModule);
|
|
65
|
-
if (revalidateSeconds !== null) options.layoutParamAccess?.recordLayoutFiniteRevalidate(options.layoutId, revalidateSeconds);
|
|
66
|
-
}
|
|
67
|
-
function probeAppPageLayoutWithTracking(options) {
|
|
76
|
+
/**
|
|
77
|
+
* Renders the layout at `layoutIndex` with a placeholder for its children, so
|
|
78
|
+
* whatever it or a component it renders throws comes out.
|
|
79
|
+
*/
|
|
80
|
+
function probeAppPageLayout(options) {
|
|
68
81
|
const treePosition = options.route.layoutTreePositions?.[options.layoutIndex] ?? 0;
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
layoutId,
|
|
77
|
-
layoutModule,
|
|
78
|
-
layoutParamAccess: options.layoutParamAccess,
|
|
79
|
-
routeSegments: options.route.routeSegments,
|
|
80
|
-
treePosition
|
|
81
|
-
});
|
|
82
|
-
const layoutParams = resolveAppPageSegmentParams(options.route.routeSegments, treePosition, options.matchedParams);
|
|
83
|
-
return probeReactServerSubtree(/* @__PURE__ */ jsx(LayoutComponent, {
|
|
84
|
-
...withUseCacheLayoutMarker(LayoutComponent, { params: options.makeThenableParams(layoutParams, options.layoutParamAccess?.createThenableParamsObserver(layoutId)) }),
|
|
85
|
-
children: APP_PAGE_LAYOUT_PROBE_CHILD
|
|
86
|
-
}));
|
|
87
|
-
};
|
|
88
|
-
return options.layoutParamAccess ? options.layoutParamAccess.runLayoutProbe(layoutId, probe) : probe();
|
|
82
|
+
const LayoutComponent = getDefaultExport(options.route.layouts[options.layoutIndex]);
|
|
83
|
+
if (!LayoutComponent) return null;
|
|
84
|
+
const layoutParams = resolveAppPageSegmentParams(options.route.routeSegments, treePosition, options.matchedParams);
|
|
85
|
+
return probeReactServerSubtree(/* @__PURE__ */ jsx(LayoutComponent, {
|
|
86
|
+
...withUseCacheLayoutMarker(LayoutComponent, { params: options.makeThenableParams(layoutParams) }),
|
|
87
|
+
children: APP_PAGE_LAYOUT_PROBE_CHILD
|
|
88
|
+
}));
|
|
89
89
|
}
|
|
90
90
|
function createAppPageLayoutEntries(route) {
|
|
91
91
|
return route.layouts.map((layoutModule, index) => {
|
|
@@ -426,8 +426,8 @@ function buildAppPageElements(options) {
|
|
|
426
426
|
const notFoundBoundaries = resolveAccessBoundaries(options.route.segmentNotFounds, options.route.segmentNotFoundTreePositions, (entry) => entry.notFoundModule, rootNotFoundModule ? null : DEFAULT_NOT_FOUND_COMPONENT);
|
|
427
427
|
const forbiddenBoundaries = resolveAccessBoundaries(options.route.segmentForbiddens, options.route.segmentForbiddenTreePositions, (entry) => entry.forbiddenModule, rootForbiddenModule ? null : DEFAULT_FORBIDDEN_COMPONENT);
|
|
428
428
|
const unauthorizedBoundaries = resolveAccessBoundaries(options.route.segmentUnauthorizeds, options.route.segmentUnauthorizedTreePositions, (entry) => entry.unauthorizedModule, rootUnauthorizedModule ? null : DEFAULT_UNAUTHORIZED_COMPONENT);
|
|
429
|
+
const layoutGate = createAppPageLayoutGate();
|
|
429
430
|
const layoutDependenciesByIndex = /* @__PURE__ */ new Map();
|
|
430
|
-
const renderDependenciesByElementId = /* @__PURE__ */ new Map();
|
|
431
431
|
const layoutDependenciesBefore = [];
|
|
432
432
|
const slotDependenciesByLayoutIndex = [];
|
|
433
433
|
const templateDependenciesById = /* @__PURE__ */ new Map();
|
|
@@ -488,6 +488,13 @@ function buildAppPageElements(options) {
|
|
|
488
488
|
templateEntries
|
|
489
489
|
});
|
|
490
490
|
const routeResetKey = segmentPlan.routeResetKey;
|
|
491
|
+
const skippedLayoutIds = /* @__PURE__ */ new Set();
|
|
492
|
+
if (options.mountedLayouts && options.isRscRequest === true && options.isUncacheableRender === true && renderMode === "navigation" && interception === null) for (const layoutEntry of layoutEntries) {
|
|
493
|
+
const identity = segmentPlan.bfcacheSegmentIdentities[layoutEntry.id];
|
|
494
|
+
if (identity === void 0) break;
|
|
495
|
+
if (!options.mountedLayouts.has(hashMountedLayoutIdentity(identity))) break;
|
|
496
|
+
skippedLayoutIds.add(layoutEntry.id);
|
|
497
|
+
}
|
|
491
498
|
const slotPlansByKey = new Map(segmentPlan.slots.map((slot) => [slot.key, slot]));
|
|
492
499
|
const resolveRouteSegmentResetKey = (treePosition) => resolveAppPageSegmentStateKey(routeSegments, treePosition, options.matchedParams);
|
|
493
500
|
const metadataEntries = AppElementsWire.createMetadataEntries({
|
|
@@ -530,10 +537,9 @@ function buildAppPageElements(options) {
|
|
|
530
537
|
if (layoutIndex !== void 0) {
|
|
531
538
|
const layoutEntry = layoutEntries[layoutIndex];
|
|
532
539
|
layoutDependenciesBefore[layoutIndex] = [...pageDependencies];
|
|
533
|
-
if (getDefaultExport(layoutEntry.layoutModule)) {
|
|
540
|
+
if (!skippedLayoutIds.has(layoutEntry.id) && getDefaultExport(layoutEntry.layoutModule)) {
|
|
534
541
|
const layoutDependency = createAppRenderDependency();
|
|
535
542
|
layoutDependenciesByIndex.set(layoutIndex, layoutDependency);
|
|
536
|
-
renderDependenciesByElementId.set(layoutEntry.id, layoutDependency);
|
|
537
543
|
pageDependencies.push(layoutDependency);
|
|
538
544
|
}
|
|
539
545
|
slotDependenciesByLayoutIndex[layoutIndex] = [...pageDependencies];
|
|
@@ -581,33 +587,29 @@ function buildAppPageElements(options) {
|
|
|
581
587
|
for (let index = 0; index < layoutEntries.length; index++) {
|
|
582
588
|
const layoutEntry = layoutEntries[index];
|
|
583
589
|
if (isPrefetchLoadingShell && !includesPrefetchTreePosition(layoutEntry.treePosition)) continue;
|
|
590
|
+
if (skippedLayoutIds.has(layoutEntry.id)) continue;
|
|
584
591
|
if (!layoutEntry.layoutModule) continue;
|
|
585
592
|
const layoutComponent = traceGetLayoutOrPageModule(resolveAppPageModuleTraceSegment(routeSegments, layoutEntry.treePosition), () => getDefaultExport(layoutEntry.layoutModule));
|
|
586
593
|
if (!layoutComponent) continue;
|
|
587
594
|
const layoutParams = resolveAppPageSegmentParams(options.route.routeSegments, layoutEntry.treePosition, options.matchedParams);
|
|
588
|
-
|
|
589
|
-
layoutId: layoutEntry.id,
|
|
590
|
-
layoutModule: layoutEntry.layoutModule,
|
|
591
|
-
layoutParamAccess: options.layoutParamAccess,
|
|
592
|
-
routeSegments: options.route.routeSegments,
|
|
593
|
-
treePosition: layoutEntry.treePosition
|
|
594
|
-
});
|
|
595
|
-
const layoutProps = { params: options.makeThenableParams(layoutParams, options.layoutParamAccess?.createThenableParamsObserver(layoutEntry.id)) };
|
|
595
|
+
const layoutProps = { params: options.makeThenableParams(layoutParams) };
|
|
596
596
|
for (const slot of Object.values(options.route.slots ?? {})) {
|
|
597
597
|
const slotName = slot.name;
|
|
598
598
|
if ((slot.layoutIndex >= 0 ? slot.layoutIndex : layoutEntries.length - 1) !== index) continue;
|
|
599
599
|
layoutProps[slotName] = /* @__PURE__ */ jsx(ParallelSlot, { name: slotName });
|
|
600
600
|
}
|
|
601
601
|
const LayoutComponent = layoutComponent;
|
|
602
|
-
const
|
|
603
|
-
|
|
602
|
+
const ancestorLoadingEntry = findNearestAncestorLoadingEntry(layoutEntry.treePosition);
|
|
603
|
+
const holdsResponse = !ancestorLoadingEntry && !isReactOwnedAppComponent(LayoutComponent);
|
|
604
|
+
if (holdsResponse) layoutGate.hold(layoutEntry.id, index);
|
|
605
|
+
let layoutElement = createRouteLayoutElement(LayoutComponent, withUseCacheLayoutMarker(LayoutComponent, {
|
|
604
606
|
...layoutProps,
|
|
605
607
|
children: /* @__PURE__ */ jsx(Children$1, {})
|
|
606
|
-
}),
|
|
607
|
-
|
|
608
|
-
|
|
608
|
+
}), index, layoutDependenciesByIndex.get(index), holdsResponse ? (failure) => layoutGate.settle(layoutEntry.id, failure) : void 0);
|
|
609
|
+
layoutElement = /* @__PURE__ */ jsx(RedirectBoundary, {
|
|
610
|
+
resetKey: resolveRouteSegmentResetKey(layoutEntry.treePosition),
|
|
611
|
+
children: layoutElement
|
|
609
612
|
});
|
|
610
|
-
const ancestorLoadingEntry = findNearestAncestorLoadingEntry(layoutEntry.treePosition);
|
|
611
613
|
const ancestorLoadingComponent = getDefaultExport(ancestorLoadingEntry?.loadingModule);
|
|
612
614
|
if (ancestorLoadingComponent && ancestorLoadingEntry && isOutermostEntryBelowLoading(ancestorLoadingEntry.treePosition, layoutEntry.treePosition, "layout")) {
|
|
613
615
|
const AncestorLoadingComponent = ancestorLoadingComponent;
|
|
@@ -875,7 +877,20 @@ function buildAppPageElements(options) {
|
|
|
875
877
|
fallback: pageErrorComponent,
|
|
876
878
|
children: routeChildren
|
|
877
879
|
});
|
|
878
|
-
const
|
|
880
|
+
const firstLayoutWithElementTreePosition = layoutEntries.find((entry) => getDefaultExport(entry.layoutModule) !== null)?.treePosition;
|
|
881
|
+
const keepsSegmentLevelLists = String(process.env.__NEXT_CACHE_COMPONENTS) === "true" && firstLayoutWithElementTreePosition !== void 0 && !options.route.childrenSlot && options.semanticPageIdentity === void 0;
|
|
882
|
+
const spineTreePositions = keepsSegmentLevelLists ? Array.from(/* @__PURE__ */ new Set([...orderedTreePositions, ...Array.from({ length: Math.max(0, routeSegments.length - firstLayoutWithElementTreePosition) }, (_, offset) => firstLayoutWithElementTreePosition + 1 + offset)])).sort((left, right) => left - right) : orderedTreePositions;
|
|
883
|
+
const renderedTreePositions = isPrefetchLoadingShell ? spineTreePositions.filter(includesPrefetchTreePosition) : spineTreePositions;
|
|
884
|
+
const firstLayoutBelowShell = keepsSegmentLevelLists && isPrefetchLoadingShell ? layoutEntries.find((entry) => !includesPrefetchTreePosition(entry.treePosition) && getDefaultExport(entry.layoutModule) !== null) : void 0;
|
|
885
|
+
let childSegmentElementId = firstLayoutBelowShell?.id ?? pageElementId;
|
|
886
|
+
let childSegmentTreePosition = firstLayoutBelowShell?.treePosition ?? routeSegments.length + 1;
|
|
887
|
+
const retainChildSegment = (treePosition, children) => treePosition === childSegmentTreePosition - 1 ? /* @__PURE__ */ jsx(BfcacheChildrenBoundary, {
|
|
888
|
+
id: childSegmentElementId,
|
|
889
|
+
children
|
|
890
|
+
}) : /* @__PURE__ */ jsx(BfcacheChildrenBoundary, {
|
|
891
|
+
stateKey: createBfcacheChildSegmentStateKey(resolveAppPageTemplateStateKey(routeSegments, treePosition, options.matchedParams)),
|
|
892
|
+
children
|
|
893
|
+
});
|
|
879
894
|
for (let index = renderedTreePositions.length - 1; index >= 0; index--) {
|
|
880
895
|
const treePosition = renderedTreePositions[index];
|
|
881
896
|
const segmentResetKey = resolveRouteSegmentResetKey(treePosition);
|
|
@@ -925,11 +940,12 @@ function buildAppPageElements(options) {
|
|
|
925
940
|
children: segmentChildren
|
|
926
941
|
}, String(process.env.__NEXT_CACHE_COMPONENTS) === "true" ? void 0 : templateStateKey);
|
|
927
942
|
}
|
|
943
|
+
const layoutHasElement = layoutEntry !== void 0 && getDefaultExport(layoutEntry.layoutModule) !== null;
|
|
944
|
+
if (keepsSegmentLevelLists && !layoutHasElement && treePosition > firstLayoutWithElementTreePosition && treePosition < childSegmentTreePosition) segmentChildren = retainChildSegment(treePosition, segmentChildren);
|
|
928
945
|
if (!layoutEntry) {
|
|
929
946
|
routeChildren = segmentChildren;
|
|
930
947
|
continue;
|
|
931
948
|
}
|
|
932
|
-
const layoutHasElement = getDefaultExport(layoutEntry.layoutModule) !== null;
|
|
933
949
|
const layoutIndex = layoutIndicesByTreePosition.get(treePosition) ?? -1;
|
|
934
950
|
const segmentMap = { children: resolveAppPageLayoutSegmentProviderSegments(options.route.childrenRouteSegments ?? routeSegments, layoutEntry.treePosition, options.matchedParams) };
|
|
935
951
|
for (const [slotKey, slot] of Object.entries(options.route.slots ?? {})) {
|
|
@@ -947,9 +963,16 @@ function buildAppPageElements(options) {
|
|
|
947
963
|
children: layoutHasElement ? /* @__PURE__ */ jsx(Slot, {
|
|
948
964
|
id: layoutEntry.id,
|
|
949
965
|
parallelSlots: createAppPageParallelSlotEntries(layoutIndex, layoutEntries, options.route, getEffectiveSlotParams, resolveSlotOverride),
|
|
950
|
-
children: segmentChildren
|
|
966
|
+
children: keepsSegmentLevelLists ? retainChildSegment(treePosition, segmentChildren) : /* @__PURE__ */ jsx(BfcacheChildrenBoundary, {
|
|
967
|
+
id: childSegmentElementId,
|
|
968
|
+
children: segmentChildren
|
|
969
|
+
})
|
|
951
970
|
}) : segmentChildren
|
|
952
971
|
});
|
|
972
|
+
if (layoutHasElement) {
|
|
973
|
+
childSegmentElementId = layoutEntry.id;
|
|
974
|
+
childSegmentTreePosition = treePosition;
|
|
975
|
+
}
|
|
953
976
|
}
|
|
954
977
|
const globalErrorComponent = getErrorBoundaryExport(options.globalErrorModule);
|
|
955
978
|
routeChildren = /* @__PURE__ */ jsx(GlobalErrorBoundary, {
|
|
@@ -965,9 +988,9 @@ function buildAppPageElements(options) {
|
|
|
965
988
|
createAppPageStreamingMetadataBody(streamingMetadataBodyId)
|
|
966
989
|
] });
|
|
967
990
|
elements[routeId] = pageRenderDependency ? renderAfterAppDependencies(routeElement, [pageRenderDependency]) : routeElement;
|
|
968
|
-
Object.assign(elements, metadataEntries, options.route.staticSiblings && options.route.staticSiblings.length > 0 ? { [APP_STATIC_SIBLINGS_KEY]: options.route.staticSiblings } : {}, shouldRenderPrefetchLoadingShell ? { [APP_PREFETCH_LOADING_SHELL_MARKER_KEY]: "LoadingBoundary" } : {});
|
|
969
|
-
|
|
991
|
+
Object.assign(elements, metadataEntries, options.route.staticSiblings && options.route.staticSiblings.length > 0 ? { [APP_STATIC_SIBLINGS_KEY]: options.route.staticSiblings } : {}, shouldRenderPrefetchLoadingShell ? { [APP_PREFETCH_LOADING_SHELL_MARKER_KEY]: "LoadingBoundary" } : {}, skippedLayoutIds.size > 0 ? { [APP_SKIPPED_LAYOUT_IDS_KEY]: [...skippedLayoutIds] } : {});
|
|
992
|
+
registerAppPageLayoutGate(elements, layoutGate);
|
|
970
993
|
return elements;
|
|
971
994
|
}
|
|
972
995
|
//#endregion
|
|
973
|
-
export { buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage, createAppPageTreePath,
|
|
996
|
+
export { buildAppPageElements, createAppPageLayoutEntries, createAppPageRouteBodyMetadata, createAppPageSourcePage, createAppPageTreePath, probeAppPageLayout, resolveAppPageChildSegments, resolveAppPageLoadingModuleAtOrAbove };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { NavigationContext } from "../shims/navigation-context-state.js";
|
|
2
2
|
import "../shims/navigation.js";
|
|
3
3
|
import { RootParams } from "../shims/root-params.js";
|
|
4
|
-
import {
|
|
4
|
+
import { InitialNavigationCacheMetadata } from "./app-ssr-stream.js";
|
|
5
|
+
import { AppPageFontData, AppPageSsrHandler } from "./app-page-stream.js";
|
|
6
|
+
import { CdnAppPageDocument } from "../shims/cdn-cache.js";
|
|
5
7
|
//#region src/server/app-page-rsc-render-status.d.ts
|
|
6
8
|
/**
|
|
7
9
|
* The status of a finished RSC render, as Next.js's static generation decides
|
|
@@ -10,6 +12,8 @@ import { AppPageSsrHandler } from "./app-page-stream.js";
|
|
|
10
12
|
*/
|
|
11
13
|
export type AppPageRscRenderStatus = {
|
|
12
14
|
kind: "page";
|
|
15
|
+
/** The page's document, when the resolver rendered one to store. */
|
|
16
|
+
document?: CdnAppPageDocument;
|
|
13
17
|
} | {
|
|
14
18
|
kind: "special-error";
|
|
15
19
|
status: number;
|
|
@@ -22,9 +26,28 @@ export type AppPageRscRenderStatus = {
|
|
|
22
26
|
{
|
|
23
27
|
kind: "unstorable";
|
|
24
28
|
};
|
|
29
|
+
/** What the page's document renders with, as an HTML request renders it. */
|
|
30
|
+
type AppPageRscRenderDocumentOptions = {
|
|
31
|
+
clientTraceMetadata?: readonly string[];
|
|
32
|
+
/**
|
|
33
|
+
* When the document's render is given up, as completed-response admission
|
|
34
|
+
* gives up a body it hasn't captured by its deadline.
|
|
35
|
+
*/
|
|
36
|
+
deadlineAt?: number;
|
|
37
|
+
getFontData: () => AppPageFontData;
|
|
38
|
+
getInitialNavigationCacheMetadata: () => InitialNavigationCacheMetadata;
|
|
39
|
+
mirrorNextFlight: () => boolean;
|
|
40
|
+
onSsrError: (error: unknown) => unknown;
|
|
41
|
+
reactMaxHeadersLength?: number;
|
|
42
|
+
};
|
|
25
43
|
type CreateAppPageRscRenderStatusResolverOptions = {
|
|
26
44
|
basePath?: string;
|
|
27
45
|
capturedRscData: Promise<ArrayBuffer>;
|
|
46
|
+
/**
|
|
47
|
+
* Render the page's document from the payload, to be stored beside it.
|
|
48
|
+
* Without it, only a render that threw a special error renders its shell.
|
|
49
|
+
*/
|
|
50
|
+
document?: AppPageRscRenderDocumentOptions;
|
|
28
51
|
getCapturedSpecialError: () => unknown;
|
|
29
52
|
getCapturedSpecialErrors: (error: unknown) => readonly unknown[];
|
|
30
53
|
isForceStatic: boolean;
|
|
@@ -39,6 +62,9 @@ type CreateAppPageRscRenderStatusResolverOptions = {
|
|
|
39
62
|
* a render that threw one renders the document's shell from the same payload,
|
|
40
63
|
* as Next.js's static generation renders HTML beside RSC. Its server
|
|
41
64
|
* components don't run again. A render without a special error is a 200.
|
|
65
|
+
*
|
|
66
|
+
* With `document`, every render renders its document from the payload, as
|
|
67
|
+
* Next.js keeps a page's document and RSC payload in one entry.
|
|
42
68
|
*/
|
|
43
69
|
export declare function createAppPageRscRenderStatusResolver(options: CreateAppPageRscRenderStatusResolverOptions): () => Promise<AppPageRscRenderStatus>;
|
|
44
70
|
/**
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { isRenderDynamicLatched } from "../shims/internal/headers-state.js";
|
|
2
|
+
import "../shims/headers.js";
|
|
3
|
+
import { readStreamAsText } from "../utils/text-stream.js";
|
|
4
|
+
import { buildAppPageFontLinkHeader, resolveAppPageShellSpecialError, resolveAppPageSpecialErrorStoredHeaders } from "./app-page-execution.js";
|
|
5
|
+
import { buildAppPageLinkHeader, isAppSsrRenderResult } from "./app-page-stream.js";
|
|
3
6
|
//#region src/server/app-page-rsc-render-status.ts
|
|
4
7
|
const PAGE_STATUS = { kind: "page" };
|
|
5
8
|
/**
|
|
@@ -8,28 +11,109 @@ const PAGE_STATUS = { kind: "page" };
|
|
|
8
11
|
* a render that threw one renders the document's shell from the same payload,
|
|
9
12
|
* as Next.js's static generation renders HTML beside RSC. Its server
|
|
10
13
|
* components don't run again. A render without a special error is a 200.
|
|
14
|
+
*
|
|
15
|
+
* With `document`, every render renders its document from the payload, as
|
|
16
|
+
* Next.js keeps a page's document and RSC payload in one entry.
|
|
11
17
|
*/
|
|
12
18
|
function createAppPageRscRenderStatusResolver(options) {
|
|
13
19
|
let status;
|
|
14
20
|
return () => status ??= resolveAppPageRscRenderStatus(options);
|
|
15
21
|
}
|
|
16
22
|
async function resolveAppPageRscRenderStatus(options) {
|
|
23
|
+
const deadlineAt = options.document?.deadlineAt;
|
|
24
|
+
if (deadlineAt === void 0) return renderAppPageRscRenderStatus(options);
|
|
25
|
+
const expired = new AbortController();
|
|
26
|
+
const remaining = deadlineAt - Date.now();
|
|
27
|
+
const timer = remaining > 0 ? setTimeout(() => expired.abort(), remaining) : void 0;
|
|
28
|
+
if (timer === void 0) expired.abort();
|
|
29
|
+
try {
|
|
30
|
+
return await unlessExpired(renderAppPageRscRenderStatus(options, expired.signal), expired.signal, () => {}) ?? expiredDocumentStatus(options);
|
|
31
|
+
} finally {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Settle with `promise`, or with `null` once `signal` aborts. */
|
|
36
|
+
function unlessExpired(promise, signal, discard) {
|
|
37
|
+
if (!signal) return promise;
|
|
38
|
+
if (signal.aborted) {
|
|
39
|
+
promise.then(discard, () => {});
|
|
40
|
+
return Promise.resolve(null);
|
|
41
|
+
}
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const onAbort = () => {
|
|
44
|
+
promise.then(discard, () => {});
|
|
45
|
+
resolve(null);
|
|
46
|
+
};
|
|
47
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
48
|
+
promise.then((value) => {
|
|
49
|
+
signal.removeEventListener("abort", onAbort);
|
|
50
|
+
if (signal.aborted) discard(value);
|
|
51
|
+
else resolve(value);
|
|
52
|
+
}, (error) => {
|
|
53
|
+
signal.removeEventListener("abort", onAbort);
|
|
54
|
+
reject(error);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** Read the document, or cancel it and settle with `null` once `signal` aborts. */
|
|
59
|
+
async function readDocumentHtml(stream, signal) {
|
|
60
|
+
if (!signal) return readStreamAsText(stream);
|
|
61
|
+
const reader = stream.getReader();
|
|
62
|
+
const decoder = new TextDecoder();
|
|
63
|
+
const chunks = [];
|
|
64
|
+
for (;;) {
|
|
65
|
+
const result = await unlessExpired(reader.read(), signal, () => {});
|
|
66
|
+
if (result === null) {
|
|
67
|
+
reader.cancel().catch(() => {});
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
if (result.done) break;
|
|
71
|
+
chunks.push(decoder.decode(result.value, { stream: true }));
|
|
72
|
+
}
|
|
73
|
+
chunks.push(decoder.decode());
|
|
74
|
+
return chunks.join("");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A document given up at its deadline isn't stored. A render without a
|
|
78
|
+
* special error is still a 200, but one with a special error needs its shell.
|
|
79
|
+
*/
|
|
80
|
+
function expiredDocumentStatus(options) {
|
|
81
|
+
return options.getCapturedSpecialError() === null ? PAGE_STATUS : { kind: "unstorable" };
|
|
82
|
+
}
|
|
83
|
+
async function renderAppPageRscRenderStatus(options, signal) {
|
|
17
84
|
const rscData = await options.capturedRscData;
|
|
18
|
-
|
|
85
|
+
const documentOptions = options.document;
|
|
86
|
+
if (!documentOptions && options.getCapturedSpecialError() === null) return PAGE_STATUS;
|
|
19
87
|
const ssrHandler = await options.loadSsrHandler();
|
|
88
|
+
if (signal?.aborted) return expiredDocumentStatus(options);
|
|
89
|
+
const fontData = documentOptions?.getFontData() ?? {
|
|
90
|
+
links: [],
|
|
91
|
+
preloads: [],
|
|
92
|
+
styles: []
|
|
93
|
+
};
|
|
94
|
+
const clientTraceMetadataMarker = documentOptions?.clientTraceMetadata && documentOptions.clientTraceMetadata.length > 0 ? crypto.randomUUID() : void 0;
|
|
20
95
|
let rendered;
|
|
21
96
|
try {
|
|
22
|
-
rendered = await ssrHandler.handleSsr(new Response(rscData).body, options.navigationContext, {
|
|
23
|
-
links: [],
|
|
24
|
-
preloads: [],
|
|
25
|
-
styles: []
|
|
26
|
-
}, {
|
|
97
|
+
rendered = await unlessExpired(ssrHandler.handleSsr(new Response(rscData).body, options.navigationContext, fontData, {
|
|
27
98
|
basePath: options.basePath,
|
|
28
99
|
isForceStatic: options.isForceStatic,
|
|
29
|
-
isStaticGeneration: true,
|
|
30
|
-
onSsrError: () => void 0,
|
|
31
100
|
preloadRoutePattern: options.routePattern,
|
|
32
|
-
rootParams: options.rootParams
|
|
101
|
+
rootParams: options.rootParams,
|
|
102
|
+
...documentOptions ? {
|
|
103
|
+
clientTraceMetadata: documentOptions.clientTraceMetadata,
|
|
104
|
+
clientTraceMetadataMarker,
|
|
105
|
+
getInitialNavigationCacheMetadata: documentOptions.getInitialNavigationCacheMetadata,
|
|
106
|
+
isCacheCandidate: true,
|
|
107
|
+
mirrorNextFlight: documentOptions.mirrorNextFlight,
|
|
108
|
+
onSsrError: documentOptions.onSsrError,
|
|
109
|
+
reactMaxHeadersLength: documentOptions.reactMaxHeadersLength,
|
|
110
|
+
signal
|
|
111
|
+
} : {
|
|
112
|
+
isStaticGeneration: true,
|
|
113
|
+
onSsrError: () => void 0
|
|
114
|
+
}
|
|
115
|
+
}), signal, (late) => {
|
|
116
|
+
(isAppSsrRenderResult(late) ? late.htmlStream : late).cancel().catch(() => {});
|
|
33
117
|
});
|
|
34
118
|
} catch (error) {
|
|
35
119
|
const specialError = resolveAppPageShellSpecialError(error, options.getCapturedSpecialErrors(error));
|
|
@@ -41,8 +125,32 @@ async function resolveAppPageRscRenderStatus(options) {
|
|
|
41
125
|
...headers ? { headers } : {}
|
|
42
126
|
};
|
|
43
127
|
}
|
|
44
|
-
(
|
|
45
|
-
|
|
128
|
+
if (rendered === null) return expiredDocumentStatus(options);
|
|
129
|
+
const htmlStream = isAppSsrRenderResult(rendered) ? rendered.htmlStream : rendered;
|
|
130
|
+
if (!documentOptions) {
|
|
131
|
+
htmlStream.cancel().catch(() => {});
|
|
132
|
+
return PAGE_STATUS;
|
|
133
|
+
}
|
|
134
|
+
let html;
|
|
135
|
+
try {
|
|
136
|
+
html = await readDocumentHtml(htmlStream, signal);
|
|
137
|
+
} catch {
|
|
138
|
+
return PAGE_STATUS;
|
|
139
|
+
}
|
|
140
|
+
if (html === null) return expiredDocumentStatus(options);
|
|
141
|
+
if (isRenderDynamicLatched()) return PAGE_STATUS;
|
|
142
|
+
const linkHeader = buildAppPageLinkHeader(isAppSsrRenderResult(rendered) ? rendered.linkHeader : void 0, buildAppPageFontLinkHeader(fontData.preloads), documentOptions.reactMaxHeadersLength);
|
|
143
|
+
if (clientTraceMetadataMarker) {
|
|
144
|
+
const { stripClientTraceMetadataBlock } = await import("./client-trace-metadata.js");
|
|
145
|
+
html = stripClientTraceMetadataBlock(html, clientTraceMetadataMarker);
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
kind: "page",
|
|
149
|
+
document: {
|
|
150
|
+
html,
|
|
151
|
+
...linkHeader ? { linkHeader } : {}
|
|
152
|
+
}
|
|
153
|
+
};
|
|
46
154
|
}
|
|
47
155
|
/**
|
|
48
156
|
* The status Next.js sends an RSC request for a render with this status. Its
|
|
@@ -77,6 +77,8 @@ export type AppPageSsrHandler = {
|
|
|
77
77
|
};
|
|
78
78
|
/** Abort signal for a build-time PPR fallback-shell static render. */
|
|
79
79
|
pprFallbackShellSignal?: AbortSignal;
|
|
80
|
+
/** Aborts a streaming render whose document is given up. */
|
|
81
|
+
signal?: AbortSignal;
|
|
80
82
|
/** Route whose client references load before the render; null for none. */
|
|
81
83
|
preloadRoutePattern?: string | null;
|
|
82
84
|
/** When true, wait for the full React tree before emitting bytes. */
|
|
@@ -94,10 +96,13 @@ export type AppPageSsrHandler = {
|
|
|
94
96
|
/** Mirror inline Flight chunks into Next.js's `self.__next_f` transport, or start
|
|
95
97
|
* mirroring once a function returns true. */
|
|
96
98
|
mirrorNextFlight?: boolean | (() => boolean);
|
|
97
|
-
/** When true,
|
|
98
|
-
*
|
|
99
|
-
*
|
|
99
|
+
/** When true, a shell render error other than a redirect, HTTP access
|
|
100
|
+
* fallback or bail-out resolves to the default `__next_error__`
|
|
101
|
+
* error-document shell (with the original flight payload and
|
|
102
|
+
* bootstrap) instead of rejecting. See handleSsr. */
|
|
100
103
|
fallbackToErrorDocumentOnShellError?: boolean;
|
|
104
|
+
/** Whether the RSC render threw the given shell error. See handleSsr. */
|
|
105
|
+
isServerComponentError?: (error: unknown) => boolean;
|
|
101
106
|
/** The parallel slot not-found boundaries that catch a shell error. See handleSsr. */
|
|
102
107
|
resolveCaughtNotFoundBoundaries?: (error: unknown) => readonly string[] | null;
|
|
103
108
|
dynamicStaleTimeSeconds?: number;
|
|
@@ -151,8 +156,11 @@ type RenderAppPageHtmlStreamOptions = {
|
|
|
151
156
|
isForceStatic?: boolean;
|
|
152
157
|
/** Production render that may be stored under a query-free key. */
|
|
153
158
|
isCacheCandidate?: boolean;
|
|
154
|
-
/**
|
|
159
|
+
/** Whether handleSsr answers a shell error with the error document. Off by
|
|
160
|
+
* default: a boundary render that fails keeps rejecting. */
|
|
155
161
|
fallbackToErrorDocumentOnShellError?: boolean;
|
|
162
|
+
/** Whether the RSC render threw the given shell error. See handleSsr. */
|
|
163
|
+
isServerComponentError?: (error: unknown) => boolean;
|
|
156
164
|
/** The parallel slot not-found boundaries that catch a shell error. See handleSsr. */
|
|
157
165
|
resolveCaughtNotFoundBoundaries?: (error: unknown) => readonly string[] | null;
|
|
158
166
|
/** Dev-only: original server error to surface in the browser overlay. */
|
|
@@ -162,10 +170,6 @@ type RenderAppPageHtmlStreamOptions = {
|
|
|
162
170
|
/** Mirror inline Flight chunks into Next.js's `self.__next_f` transport, or start
|
|
163
171
|
* mirroring once a function returns true. */
|
|
164
172
|
mirrorNextFlight?: boolean | (() => boolean);
|
|
165
|
-
/** True when the app supplies a custom global-error.tsx. Disables the
|
|
166
|
-
* default error-document shell fallback so SSR shell errors keep driving
|
|
167
|
-
* the server-rendered global-error boundary re-render. */
|
|
168
|
-
hasCustomGlobalError?: boolean;
|
|
169
173
|
};
|
|
170
174
|
type RenderAppPageHtmlResponseOptions = {
|
|
171
175
|
clearRequestContext: () => void;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { deferUntilStreamConsumed } from "./defer-until-stream-consumed.js";
|
|
2
2
|
import { VINEXT_RSC_VARY_HEADER } from "./app-rsc-vary.js";
|
|
3
3
|
import { isNavigationSignalError } from "../utils/navigation-signal.js";
|
|
4
|
-
import "./app-rsc-cache-busting.js";
|
|
5
|
-
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
6
4
|
import { markFrameworkLinkHeaders } from "./app-response-header-provenance.js";
|
|
5
|
+
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
6
|
+
import "./app-rsc-cache-busting.js";
|
|
7
7
|
import { applyEdgeRuntimeHeader } from "./app-page-response.js";
|
|
8
8
|
import { getNextErrorDigest } from "./next-error-digest.js";
|
|
9
9
|
import { isAppRenderAbortError } from "./app-render-abort-error.js";
|
|
@@ -86,7 +86,8 @@ async function renderAppPageHtmlStream(options) {
|
|
|
86
86
|
initialDevServerError: options.initialDevServerError,
|
|
87
87
|
onSsrError: options.onSsrError,
|
|
88
88
|
mirrorNextFlight: options.mirrorNextFlight,
|
|
89
|
-
fallbackToErrorDocumentOnShellError: options.fallbackToErrorDocumentOnShellError
|
|
89
|
+
fallbackToErrorDocumentOnShellError: options.fallbackToErrorDocumentOnShellError,
|
|
90
|
+
isServerComponentError: options.isServerComponentError,
|
|
90
91
|
resolveCaughtNotFoundBoundaries: options.resolveCaughtNotFoundBoundaries,
|
|
91
92
|
dynamicStaleTimeSeconds: options.dynamicStaleTimeSeconds,
|
|
92
93
|
getInitialNavigationCacheMetadata: options.getInitialNavigationCacheMetadata
|