@rangojs/router 0.0.0-experimental.97 → 0.0.0-experimental.98914650
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 +24 -9
- package/dist/bin/rango.js +157 -63
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +1584 -639
- package/package.json +71 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +60 -0
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +222 -30
- package/skills/caching/SKILL.md +263 -8
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +3 -1
- package/skills/hooks/SKILL.md +235 -28
- package/skills/host-router/SKILL.md +122 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +29 -5
- package/skills/layout/SKILL.md +13 -9
- package/skills/links/SKILL.md +173 -17
- package/skills/loader/SKILL.md +170 -23
- package/skills/middleware/SKILL.md +16 -10
- package/skills/migrate-nextjs/SKILL.md +38 -16
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +11 -7
- package/skills/prerender/SKILL.md +14 -33
- package/skills/rango/SKILL.md +250 -25
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +114 -47
- package/skills/route/SKILL.md +42 -5
- package/skills/router-setup/SKILL.md +3 -3
- package/skills/server-actions/SKILL.md +78 -42
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +316 -26
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/vercel/SKILL.md +107 -0
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +0 -65
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +14 -27
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +37 -143
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/navigation-bridge.ts +30 -59
- package/src/browser/navigation-client.ts +96 -84
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +32 -82
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/partial-update.ts +60 -127
- package/src/browser/prefetch/cache.ts +82 -72
- package/src/browser/prefetch/fetch.ts +108 -33
- package/src/browser/prefetch/queue.ts +6 -3
- package/src/browser/rango-state.ts +157 -115
- package/src/browser/react/Link.tsx +0 -2
- package/src/browser/react/NavigationProvider.tsx +41 -48
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/filter-segment-order.ts +0 -2
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +17 -14
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +0 -3
- package/src/browser/react/use-params.ts +11 -11
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +20 -5
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +0 -13
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +70 -34
- package/src/browser/scroll-restoration.ts +22 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +168 -44
- package/src/browser/types.ts +36 -21
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +60 -35
- package/src/build/generate-route-types.ts +3 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +89 -10
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +1 -1
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +122 -22
- package/src/build/route-types/scan-filter.ts +1 -1
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +134 -32
- package/src/cache/cache-scope.ts +100 -74
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2255 -238
- package/src/cache/cf/index.ts +6 -16
- package/src/cache/document-cache.ts +61 -20
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +22 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +25 -61
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +17 -5
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +31 -23
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +63 -9
- package/src/index.ts +64 -9
- package/src/internal-debug.ts +2 -4
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +32 -37
- package/src/prerender.ts +61 -6
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +9 -0
- package/src/reverse.ts +65 -40
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +244 -281
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +40 -17
- package/src/route-definition/redirect.ts +43 -9
- package/src/route-definition/resolve-handler-use.ts +6 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +0 -16
- package/src/route-types.ts +19 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +15 -15
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +44 -23
- package/src/router/handler-context.ts +4 -41
- package/src/router/intercept-resolution.ts +14 -19
- package/src/router/lazy-includes.ts +9 -46
- package/src/router/loader-resolution.ts +91 -46
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +18 -29
- package/src/router/match-api.ts +0 -20
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +57 -58
- package/src/router/match-middleware/background-revalidation.ts +0 -7
- package/src/router/match-middleware/cache-lookup.ts +150 -271
- package/src/router/match-middleware/cache-store.ts +3 -33
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +0 -22
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +31 -80
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +5 -112
- package/src/router/middleware.ts +118 -133
- package/src/router/navigation-snapshot.ts +0 -51
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +62 -67
- package/src/router/prerender-match.ts +99 -63
- package/src/router/preview-match.ts +3 -1
- package/src/router/request-classification.ts +28 -62
- package/src/router/revalidation.ts +50 -56
- package/src/router/route-snapshot.ts +0 -1
- package/src/router/router-context.ts +0 -27
- package/src/router/router-interfaces.ts +68 -35
- package/src/router/router-options.ts +55 -1
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +44 -63
- package/src/router/segment-resolution/helpers.ts +34 -0
- package/src/router/segment-resolution/loader-cache.ts +40 -37
- package/src/router/segment-resolution/revalidation.ts +203 -285
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +0 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +87 -48
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +0 -5
- package/src/router.ts +80 -41
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +83 -78
- package/src/rsc/helpers.ts +93 -5
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/manifest-init.ts +28 -41
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +12 -1
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +76 -62
- package/src/rsc/rsc-rendering.ts +41 -60
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +62 -67
- package/src/rsc/ssr-setup.ts +16 -0
- package/src/rsc/types.ts +10 -5
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-loader-promise.ts +14 -2
- package/src/segment-system.tsx +199 -142
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +150 -51
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +7 -24
- package/src/server/loader-registry.ts +5 -24
- package/src/server/request-context.ts +165 -87
- package/src/ssr/index.tsx +14 -14
- package/src/static-handler.ts +10 -13
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +13 -4
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +97 -22
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +6 -3
- package/src/types/request-scope.ts +0 -19
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +0 -6
- package/src/types/segments.ts +18 -14
- package/src/urls/include-helper.ts +9 -56
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +19 -5
- package/src/urls/path-helper.ts +17 -106
- package/src/urls/pattern-types.ts +36 -19
- package/src/urls/response-types.ts +20 -19
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +292 -107
- package/src/vite/debug.ts +1 -0
- package/src/vite/discovery/bundle-postprocess.ts +8 -7
- package/src/vite/discovery/discover-routers.ts +95 -82
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/prerender-collection.ts +26 -34
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/state.ts +39 -1
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +4 -0
- package/src/vite/plugin-types.ts +185 -10
- package/src/vite/plugins/cjs-to-esm.ts +3 -18
- package/src/vite/plugins/client-ref-dedup.ts +0 -11
- package/src/vite/plugins/client-ref-hashing.ts +12 -11
- package/src/vite/plugins/cloudflare-protocol-stub.ts +1 -21
- package/src/vite/plugins/expose-action-id.ts +4 -75
- package/src/vite/plugins/expose-id-utils.ts +3 -54
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +6 -74
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +0 -13
- package/src/vite/plugins/expose-internal-ids.ts +57 -67
- package/src/vite/plugins/performance-tracks.ts +9 -16
- package/src/vite/plugins/refresh-cmd.ts +1 -1
- package/src/vite/plugins/use-cache-transform.ts +26 -49
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +2 -32
- package/src/vite/plugins/version-plugin.ts +32 -23
- package/src/vite/plugins/virtual-entries.ts +35 -17
- package/src/vite/rango.ts +148 -115
- package/src/vite/router-discovery.ts +220 -68
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +1 -73
- package/src/vite/utils/prerender-utils.ts +0 -34
- package/src/vite/utils/shared-utils.ts +95 -43
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -168,8 +168,6 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
168
168
|
requestCtx._handleStore = createHandleStore();
|
|
169
169
|
|
|
170
170
|
try {
|
|
171
|
-
// Create fresh handler context and loader promises to avoid
|
|
172
|
-
// reusing memoized results from the foreground pass
|
|
173
171
|
const freshHandlerContext = createHandlerContext(
|
|
174
172
|
ctx.matched.params,
|
|
175
173
|
ctx.request,
|
|
@@ -185,10 +183,6 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
185
183
|
const freshLoaderPromises = new Map<string, Promise<any>>();
|
|
186
184
|
setupLoaderAccess(freshHandlerContext, freshLoaderPromises);
|
|
187
185
|
|
|
188
|
-
// Resolve all segments fresh (without revalidation logic)
|
|
189
|
-
// to ensure complete components for caching.
|
|
190
|
-
// Skip DSL loaders — they are never cached (cacheRoute filters them)
|
|
191
|
-
// and are always resolved fresh on each request.
|
|
192
186
|
const freshSegments = await ctx.Store.run(() =>
|
|
193
187
|
resolveAllSegments(
|
|
194
188
|
ctx.entries,
|
|
@@ -200,7 +194,6 @@ export function withBackgroundRevalidation<TEnv>(
|
|
|
200
194
|
),
|
|
201
195
|
);
|
|
202
196
|
|
|
203
|
-
// Also resolve intercept segments fresh if applicable
|
|
204
197
|
let freshInterceptSegments: ResolvedSegment[] = [];
|
|
205
198
|
if (ctx.interceptResult) {
|
|
206
199
|
freshInterceptSegments = await ctx.Store.run(() =>
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
*/
|
|
94
94
|
import type { ResolvedSegment } from "../../types.js";
|
|
95
95
|
import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
96
|
-
import { getRouterContext } from "../router-context.js";
|
|
96
|
+
import { getRouterContext, type RouterContext } from "../router-context.js";
|
|
97
97
|
import { resolveSink, safeEmit } from "../telemetry.js";
|
|
98
98
|
import { pushRevalidationTraceEntry, isTraceActive } from "../logging.js";
|
|
99
99
|
import { treeHasStreaming } from "./segment-resolution.js";
|
|
@@ -103,6 +103,7 @@ import {
|
|
|
103
103
|
getRequestContext,
|
|
104
104
|
_getRequestContext,
|
|
105
105
|
} from "../../server/request-context.js";
|
|
106
|
+
import { paramsEqual } from "../params-util.js";
|
|
106
107
|
|
|
107
108
|
// Lazily initialized prerender store singleton and dynamically imported deps.
|
|
108
109
|
// Dynamic imports prevent pulling in @vitejs/plugin-rsc/rsc virtual module at
|
|
@@ -114,6 +115,9 @@ let _deserializeSegments:
|
|
|
114
115
|
let _restoreHandles:
|
|
115
116
|
| typeof import("../../cache/handle-snapshot.js").restoreHandles
|
|
116
117
|
| undefined;
|
|
118
|
+
let _decodeHandles:
|
|
119
|
+
| typeof import("../../cache/handle-snapshot.js").decodeHandles
|
|
120
|
+
| undefined;
|
|
117
121
|
let _hashParams:
|
|
118
122
|
| typeof import("../../prerender/param-hash.js").hashParams
|
|
119
123
|
| undefined;
|
|
@@ -121,22 +125,6 @@ let _lazyGetRequestContext:
|
|
|
121
125
|
| typeof import("../../server/request-context.js").getRequestContext
|
|
122
126
|
| undefined;
|
|
123
127
|
|
|
124
|
-
function paramsEqual(
|
|
125
|
-
a: Record<string, string>,
|
|
126
|
-
b: Record<string, string>,
|
|
127
|
-
): boolean {
|
|
128
|
-
if (a === b) return true;
|
|
129
|
-
|
|
130
|
-
const keysA = Object.keys(a);
|
|
131
|
-
if (keysA.length !== Object.keys(b).length) return false;
|
|
132
|
-
|
|
133
|
-
for (const key of keysA) {
|
|
134
|
-
if (a[key] !== b[key]) return false;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
128
|
async function ensurePrerenderDeps() {
|
|
141
129
|
if (!_deserializeSegments) {
|
|
142
130
|
const [codec, snapshot, paramHash, reqCtx, store] = await Promise.all([
|
|
@@ -148,6 +136,7 @@ async function ensurePrerenderDeps() {
|
|
|
148
136
|
]);
|
|
149
137
|
_deserializeSegments = codec.deserializeSegments;
|
|
150
138
|
_restoreHandles = snapshot.restoreHandles;
|
|
139
|
+
_decodeHandles = snapshot.decodeHandles;
|
|
151
140
|
_hashParams = paramHash.hashParams;
|
|
152
141
|
_lazyGetRequestContext = reqCtx.getRequestContext;
|
|
153
142
|
if (prerenderStoreInstance === undefined) {
|
|
@@ -161,69 +150,21 @@ async function ensurePrerenderDeps() {
|
|
|
161
150
|
* Deserializes segments, replays handle data, yields segments with partial
|
|
162
151
|
* navigation nullification, and resolves fresh loaders.
|
|
163
152
|
*/
|
|
164
|
-
|
|
165
|
-
|
|
153
|
+
// Resolve loaders fresh on a cache hit (loaders are NEVER cached) and yield
|
|
154
|
+
// the loader segments, updating state.matchedIds and pushing the loader-resolve
|
|
155
|
+
// + cache-hit metrics. Shared verbatim by the prerender-store path
|
|
156
|
+
// (yieldFromStore) and the runtime cache-hit path (withCacheLookup). The router
|
|
157
|
+
// resolve fns are passed in (captured early by the callers) rather than re-read
|
|
158
|
+
// from getRouterContext() here, because that is ALS-backed and the callers run
|
|
159
|
+
// awaits before reaching this point (workerd can disrupt ALS mid-pipeline).
|
|
160
|
+
async function* resolveFreshLoadersAndYield<TEnv>(
|
|
166
161
|
ctx: MatchContext<TEnv>,
|
|
167
162
|
state: MatchPipelineState,
|
|
168
163
|
pipelineStart: number,
|
|
169
|
-
|
|
164
|
+
ms: MatchContext<TEnv>["metricsStore"],
|
|
165
|
+
resolveLoadersOnly: RouterContext<TEnv>["resolveLoadersOnly"],
|
|
166
|
+
resolveLoadersOnlyWithRevalidation: RouterContext<TEnv>["resolveLoadersOnlyWithRevalidation"],
|
|
170
167
|
): AsyncGenerator<ResolvedSegment> {
|
|
171
|
-
const { resolveLoadersOnlyWithRevalidation, resolveLoadersOnly } =
|
|
172
|
-
getRouterContext<TEnv>();
|
|
173
|
-
|
|
174
|
-
if (
|
|
175
|
-
!_deserializeSegments ||
|
|
176
|
-
!_restoreHandles ||
|
|
177
|
-
!_hashParams ||
|
|
178
|
-
!_lazyGetRequestContext
|
|
179
|
-
) {
|
|
180
|
-
throw new Error("yieldFromStore called before ensurePrerenderDeps");
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const segments = await _deserializeSegments(entry.segments);
|
|
184
|
-
|
|
185
|
-
// Replay handle data (same as runtime cache hit path).
|
|
186
|
-
// Prefer the eagerly-captured handleStoreRef to avoid ALS disruption in workerd.
|
|
187
|
-
const handleStore = handleStoreRef ?? _lazyGetRequestContext()?._handleStore;
|
|
188
|
-
if (handleStore) {
|
|
189
|
-
_restoreHandles(entry.handles, handleStore);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
state.cacheHit = true;
|
|
193
|
-
state.cacheSource = "prerender";
|
|
194
|
-
state.cachedSegments = segments;
|
|
195
|
-
state.cachedMatchedIds = segments.map((s) => s.id);
|
|
196
|
-
|
|
197
|
-
// Set streaming flag (once) and resolve render barrier.
|
|
198
|
-
const reqCtx = handleStoreRef ? undefined : _lazyGetRequestContext?.();
|
|
199
|
-
const barrierReqCtx = reqCtx ?? _getRequestContext();
|
|
200
|
-
if (barrierReqCtx) {
|
|
201
|
-
if (barrierReqCtx._treeHasStreaming === undefined) {
|
|
202
|
-
barrierReqCtx._treeHasStreaming = treeHasStreaming(ctx.entries);
|
|
203
|
-
}
|
|
204
|
-
barrierReqCtx._resolveRenderBarrier(segments);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// For partial navigation, nullify components the client already has
|
|
208
|
-
// so parent layouts stay live (client keeps its existing versions).
|
|
209
|
-
// When params changed (e.g., different guide slug), the segments have
|
|
210
|
-
// different content, so we must NOT nullify.
|
|
211
|
-
const paramsChanged =
|
|
212
|
-
!ctx.isFullMatch && !paramsEqual(ctx.matched.params, ctx.prevParams);
|
|
213
|
-
for (const segment of segments) {
|
|
214
|
-
if (
|
|
215
|
-
!ctx.isFullMatch &&
|
|
216
|
-
!paramsChanged &&
|
|
217
|
-
ctx.clientSegmentSet.has(segment.id)
|
|
218
|
-
) {
|
|
219
|
-
segment.component = null;
|
|
220
|
-
segment.loading = undefined;
|
|
221
|
-
}
|
|
222
|
-
yield segment;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Resolve loaders fresh (loaders are never pre-rendered/cached)
|
|
226
|
-
const ms = ctx.metricsStore;
|
|
227
168
|
const loaderStart = performance.now();
|
|
228
169
|
|
|
229
170
|
if (ctx.isFullMatch) {
|
|
@@ -251,6 +192,8 @@ async function* yieldFromStore<TEnv>(
|
|
|
251
192
|
ctx.url,
|
|
252
193
|
ctx.routeKey,
|
|
253
194
|
ctx.actionContext,
|
|
195
|
+
// Loaders are never cached in the segment cache, so segment staleness
|
|
196
|
+
// must not propagate; browser-sent staleness (ctx.stale) still must.
|
|
254
197
|
ctx.stale || undefined,
|
|
255
198
|
),
|
|
256
199
|
);
|
|
@@ -282,6 +225,115 @@ async function* yieldFromStore<TEnv>(
|
|
|
282
225
|
}
|
|
283
226
|
}
|
|
284
227
|
|
|
228
|
+
async function* yieldFromStore<TEnv>(
|
|
229
|
+
entry: PrerenderEntry,
|
|
230
|
+
ctx: MatchContext<TEnv>,
|
|
231
|
+
state: MatchPipelineState,
|
|
232
|
+
pipelineStart: number,
|
|
233
|
+
handleStoreRef?: HandleStore,
|
|
234
|
+
): AsyncGenerator<ResolvedSegment> {
|
|
235
|
+
const { resolveLoadersOnlyWithRevalidation, resolveLoadersOnly } =
|
|
236
|
+
getRouterContext<TEnv>();
|
|
237
|
+
|
|
238
|
+
if (
|
|
239
|
+
!_deserializeSegments ||
|
|
240
|
+
!_restoreHandles ||
|
|
241
|
+
!_decodeHandles ||
|
|
242
|
+
!_hashParams ||
|
|
243
|
+
!_lazyGetRequestContext
|
|
244
|
+
) {
|
|
245
|
+
throw new Error("yieldFromStore called before ensurePrerenderDeps");
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const segments = await _deserializeSegments(entry.segments);
|
|
249
|
+
|
|
250
|
+
// Replay handle data (same as runtime cache hit path). entry.handles is a
|
|
251
|
+
// Flight-encoded string ("" when none) — decode before restore so
|
|
252
|
+
// Promise/ReactNode handle values are revived, not the corrupted JSON form.
|
|
253
|
+
const handleStore = handleStoreRef ?? _lazyGetRequestContext()?._handleStore;
|
|
254
|
+
if (handleStore && entry.handles) {
|
|
255
|
+
const handlesRecord = await _decodeHandles(entry.handles);
|
|
256
|
+
if (handlesRecord) {
|
|
257
|
+
_restoreHandles(handlesRecord, handleStore);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
state.cacheHit = true;
|
|
262
|
+
state.cacheSource = "prerender";
|
|
263
|
+
state.cachedSegments = segments;
|
|
264
|
+
state.cachedMatchedIds = segments.map((s) => s.id);
|
|
265
|
+
|
|
266
|
+
// Set streaming flag (once) and resolve render barrier.
|
|
267
|
+
const reqCtx = handleStoreRef ? undefined : _lazyGetRequestContext?.();
|
|
268
|
+
const barrierReqCtx = reqCtx ?? _getRequestContext();
|
|
269
|
+
if (barrierReqCtx) {
|
|
270
|
+
if (barrierReqCtx._treeHasStreaming === undefined) {
|
|
271
|
+
barrierReqCtx._treeHasStreaming = treeHasStreaming(ctx.entries);
|
|
272
|
+
}
|
|
273
|
+
barrierReqCtx._resolveRenderBarrier(segments);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// For partial navigation, nullify components the client already has
|
|
277
|
+
// so parent layouts stay live (client keeps its existing versions).
|
|
278
|
+
// When params changed (e.g., different guide slug), the segments have
|
|
279
|
+
// different content, so we must NOT nullify.
|
|
280
|
+
const paramsChanged =
|
|
281
|
+
!ctx.isFullMatch && !paramsEqual(ctx.matched.params, ctx.prevParams);
|
|
282
|
+
for (const segment of segments) {
|
|
283
|
+
if (
|
|
284
|
+
!ctx.isFullMatch &&
|
|
285
|
+
!paramsChanged &&
|
|
286
|
+
ctx.clientSegmentSet.has(segment.id)
|
|
287
|
+
) {
|
|
288
|
+
segment.component = null;
|
|
289
|
+
segment.loading = undefined;
|
|
290
|
+
}
|
|
291
|
+
yield segment;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Resolve loaders fresh (loaders are never pre-rendered/cached).
|
|
295
|
+
yield* resolveFreshLoadersAndYield(
|
|
296
|
+
ctx,
|
|
297
|
+
state,
|
|
298
|
+
pipelineStart,
|
|
299
|
+
ctx.metricsStore,
|
|
300
|
+
resolveLoadersOnly,
|
|
301
|
+
resolveLoadersOnlyWithRevalidation,
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Look up a prerendered (build-time cached) entry for the current route and, on
|
|
307
|
+
* a hit, yield its segments. Returns true when an entry was served (the caller
|
|
308
|
+
* should stop the pipeline) and false on a miss. Intercept navigations consult
|
|
309
|
+
* only the intercept-specific entry (`paramHash + "/i"`); a miss there falls
|
|
310
|
+
* through to the normal pipeline so intercept-resolution can run. Callers must
|
|
311
|
+
* guard on `prerenderStoreInstance` after `ensurePrerenderDeps()`.
|
|
312
|
+
*/
|
|
313
|
+
async function* tryPrerenderLookup<TEnv>(
|
|
314
|
+
ctx: MatchContext<TEnv>,
|
|
315
|
+
state: MatchPipelineState,
|
|
316
|
+
pipelineStart: number,
|
|
317
|
+
handleStoreRef?: HandleStore,
|
|
318
|
+
): AsyncGenerator<ResolvedSegment, boolean> {
|
|
319
|
+
const paramHash = _hashParams!(ctx.matched.params);
|
|
320
|
+
const isPassthroughPrerenderRoute = ctx.entries.some(
|
|
321
|
+
(entry) => entry.type === "route" && entry.isPassthrough === true,
|
|
322
|
+
);
|
|
323
|
+
const lookupHash = ctx.isIntercept ? paramHash + "/i" : paramHash;
|
|
324
|
+
const entry = await prerenderStoreInstance!.get(
|
|
325
|
+
ctx.matched.routeKey,
|
|
326
|
+
lookupHash,
|
|
327
|
+
{
|
|
328
|
+
pathname: ctx.pathname,
|
|
329
|
+
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
330
|
+
},
|
|
331
|
+
);
|
|
332
|
+
if (!entry) return false;
|
|
333
|
+
yield* yieldFromStore(entry, ctx, state, pipelineStart, handleStoreRef);
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
|
|
285
337
|
/**
|
|
286
338
|
* Async generator middleware type
|
|
287
339
|
*/
|
|
@@ -326,73 +378,20 @@ export function withCacheLookup<TEnv>(
|
|
|
326
378
|
resolveLoadersOnly,
|
|
327
379
|
} = getRouterContext<TEnv>();
|
|
328
380
|
|
|
329
|
-
// Prerender lookup: check build-time cached data before runtime cache.
|
|
330
|
-
// Prerender data is available regardless of runtime cache configuration.
|
|
331
|
-
// Skip for HMR requests — the dev prerender endpoint reads from a stale
|
|
332
|
-
// RouterRegistry snapshot; rendering fresh ensures edits are visible.
|
|
333
381
|
const isHmr = !!ctx.request.headers.get("X-RSC-HMR");
|
|
334
382
|
if (!ctx.isAction && !isHmr && ctx.matched.pr) {
|
|
335
383
|
await ensurePrerenderDeps();
|
|
336
384
|
if (prerenderStoreInstance) {
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
385
|
+
const served = yield* tryPrerenderLookup(
|
|
386
|
+
ctx,
|
|
387
|
+
state,
|
|
388
|
+
pipelineStart,
|
|
389
|
+
handleStoreRef,
|
|
340
390
|
);
|
|
341
|
-
|
|
342
|
-
if (ctx.isIntercept) {
|
|
343
|
-
// Intercept navigation: try intercept-specific prerender entry
|
|
344
|
-
const entry = await prerenderStoreInstance.get(
|
|
345
|
-
ctx.matched.routeKey,
|
|
346
|
-
paramHash + "/i",
|
|
347
|
-
{
|
|
348
|
-
pathname: ctx.pathname,
|
|
349
|
-
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
350
|
-
},
|
|
351
|
-
);
|
|
352
|
-
if (entry) {
|
|
353
|
-
yield* yieldFromStore(
|
|
354
|
-
entry,
|
|
355
|
-
ctx,
|
|
356
|
-
state,
|
|
357
|
-
pipelineStart,
|
|
358
|
-
handleStoreRef,
|
|
359
|
-
);
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
// No intercept prerender -- fall through to normal pipeline
|
|
363
|
-
// (skip non-intercept prerender to let intercept-resolution run)
|
|
364
|
-
} else {
|
|
365
|
-
// Normal navigation: existing behavior
|
|
366
|
-
const entry = await prerenderStoreInstance.get(
|
|
367
|
-
ctx.matched.routeKey,
|
|
368
|
-
paramHash,
|
|
369
|
-
{
|
|
370
|
-
pathname: ctx.pathname,
|
|
371
|
-
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
372
|
-
},
|
|
373
|
-
);
|
|
374
|
-
if (entry) {
|
|
375
|
-
yield* yieldFromStore(
|
|
376
|
-
entry,
|
|
377
|
-
ctx,
|
|
378
|
-
state,
|
|
379
|
-
pipelineStart,
|
|
380
|
-
handleStoreRef,
|
|
381
|
-
);
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
391
|
+
if (served) return;
|
|
385
392
|
}
|
|
386
393
|
}
|
|
387
394
|
|
|
388
|
-
// Dev-mode static handler interception for non-Node.js runtimes.
|
|
389
|
-
// __PRERENDER_DEV_URL is set by the Vite plugin when the RSC environment
|
|
390
|
-
// lacks a Node.js module runner (e.g. workerd, Deno workers). In those
|
|
391
|
-
// runtimes, handlers that depend on Node APIs like node:fs can't run
|
|
392
|
-
// in-process. We redirect them to the /__rsc_prerender endpoint which
|
|
393
|
-
// resolves segments in a Node.js temp server, same as prerender routes.
|
|
394
|
-
// In Node.js dev mode this variable is undefined -- handlers run
|
|
395
|
-
// in-process where Node APIs work, so no interception is needed.
|
|
396
395
|
if (!ctx.isAction && !ctx.matched.pr && globalThis.__PRERENDER_DEV_URL) {
|
|
397
396
|
const hasStatic = ctx.entries.some(
|
|
398
397
|
(e) =>
|
|
@@ -404,58 +403,18 @@ export function withCacheLookup<TEnv>(
|
|
|
404
403
|
if (hasStatic) {
|
|
405
404
|
await ensurePrerenderDeps();
|
|
406
405
|
if (prerenderStoreInstance) {
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
406
|
+
const served = yield* tryPrerenderLookup(
|
|
407
|
+
ctx,
|
|
408
|
+
state,
|
|
409
|
+
pipelineStart,
|
|
410
|
+
handleStoreRef,
|
|
410
411
|
);
|
|
411
|
-
|
|
412
|
-
if (ctx.isIntercept) {
|
|
413
|
-
const entry = await prerenderStoreInstance.get(
|
|
414
|
-
ctx.matched.routeKey,
|
|
415
|
-
paramHash + "/i",
|
|
416
|
-
{
|
|
417
|
-
pathname: ctx.pathname,
|
|
418
|
-
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
419
|
-
},
|
|
420
|
-
);
|
|
421
|
-
if (entry) {
|
|
422
|
-
yield* yieldFromStore(
|
|
423
|
-
entry,
|
|
424
|
-
ctx,
|
|
425
|
-
state,
|
|
426
|
-
pipelineStart,
|
|
427
|
-
handleStoreRef,
|
|
428
|
-
);
|
|
429
|
-
return;
|
|
430
|
-
}
|
|
431
|
-
// No intercept prerender -- fall through to normal pipeline
|
|
432
|
-
} else {
|
|
433
|
-
const entry = await prerenderStoreInstance.get(
|
|
434
|
-
ctx.matched.routeKey,
|
|
435
|
-
paramHash,
|
|
436
|
-
{
|
|
437
|
-
pathname: ctx.pathname,
|
|
438
|
-
isPassthroughRoute: isPassthroughPrerenderRoute,
|
|
439
|
-
},
|
|
440
|
-
);
|
|
441
|
-
if (entry) {
|
|
442
|
-
yield* yieldFromStore(
|
|
443
|
-
entry,
|
|
444
|
-
ctx,
|
|
445
|
-
state,
|
|
446
|
-
pipelineStart,
|
|
447
|
-
handleStoreRef,
|
|
448
|
-
);
|
|
449
|
-
return;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
412
|
+
if (served) return;
|
|
452
413
|
}
|
|
453
414
|
}
|
|
454
415
|
}
|
|
455
416
|
|
|
456
|
-
// Skip cache during actions
|
|
457
417
|
if (ctx.isAction || !ctx.cacheScope?.enabled) {
|
|
458
|
-
// Cache miss - pass through to segment resolution
|
|
459
418
|
yield* source;
|
|
460
419
|
if (ms) {
|
|
461
420
|
ms.metrics.push({
|
|
@@ -467,7 +426,6 @@ export function withCacheLookup<TEnv>(
|
|
|
467
426
|
return;
|
|
468
427
|
}
|
|
469
428
|
|
|
470
|
-
// Lookup cache
|
|
471
429
|
const cacheResult = await ctx.cacheScope.lookupRoute(
|
|
472
430
|
ctx.pathname,
|
|
473
431
|
ctx.matched.params,
|
|
@@ -475,7 +433,6 @@ export function withCacheLookup<TEnv>(
|
|
|
475
433
|
);
|
|
476
434
|
|
|
477
435
|
if (!cacheResult) {
|
|
478
|
-
// Cache miss - pass through to segment resolution
|
|
479
436
|
yield* source;
|
|
480
437
|
if (ms) {
|
|
481
438
|
ms.metrics.push({
|
|
@@ -487,16 +444,12 @@ export function withCacheLookup<TEnv>(
|
|
|
487
444
|
return;
|
|
488
445
|
}
|
|
489
446
|
|
|
490
|
-
// Cache HIT
|
|
491
447
|
state.cacheHit = true;
|
|
492
448
|
state.cacheSource = "runtime";
|
|
493
449
|
state.shouldRevalidate = cacheResult.shouldRevalidate;
|
|
494
450
|
state.cachedSegments = cacheResult.segments;
|
|
495
451
|
state.cachedMatchedIds = cacheResult.segments.map((s) => s.id);
|
|
496
452
|
|
|
497
|
-
// Apply revalidation to cached segments.
|
|
498
|
-
// For full matches or empty client segment sets, this map is unnecessary:
|
|
499
|
-
// we never run segment-level revalidation and can stream segments directly.
|
|
500
453
|
const canCheckSegmentRevalidation =
|
|
501
454
|
!ctx.isFullMatch &&
|
|
502
455
|
ctx.clientSegmentSet.size > 0 &&
|
|
@@ -506,7 +459,6 @@ export function withCacheLookup<TEnv>(
|
|
|
506
459
|
: undefined;
|
|
507
460
|
|
|
508
461
|
for (const segment of cacheResult.segments) {
|
|
509
|
-
// Skip segments client doesn't have - they need their component
|
|
510
462
|
if (!ctx.clientSegmentSet.has(segment.id)) {
|
|
511
463
|
if (isTraceActive()) {
|
|
512
464
|
pushRevalidationTraceEntry({
|
|
@@ -523,19 +475,13 @@ export function withCacheLookup<TEnv>(
|
|
|
523
475
|
continue;
|
|
524
476
|
}
|
|
525
477
|
|
|
526
|
-
// Skip intercept segments - they're handled separately
|
|
527
478
|
if (segment.namespace?.startsWith("intercept:")) {
|
|
528
479
|
yield segment;
|
|
529
480
|
continue;
|
|
530
481
|
}
|
|
531
482
|
|
|
532
|
-
// Look up revalidation rules for this segment
|
|
533
483
|
const entryInfo = entryRevalidateMap?.get(segment.id);
|
|
534
484
|
|
|
535
|
-
// Even without explicit revalidation rules, route segments and their
|
|
536
|
-
// children must re-render when params or search params change — the
|
|
537
|
-
// handler reads ctx.params/ctx.searchParams so different values produce
|
|
538
|
-
// different content. Matches evaluateRevalidation's default logic.
|
|
539
485
|
const searchChanged = ctx.prevUrl.search !== ctx.url.search;
|
|
540
486
|
const routeParamsChanged = !paramsEqual(
|
|
541
487
|
ctx.matched.params,
|
|
@@ -549,7 +495,6 @@ export function withCacheLookup<TEnv>(
|
|
|
549
495
|
|
|
550
496
|
if (!entryInfo || entryInfo.revalidate.length === 0) {
|
|
551
497
|
if (shouldDefaultRevalidate) {
|
|
552
|
-
// Params or search params changed — must re-render even without custom rules
|
|
553
498
|
if (isTraceActive()) {
|
|
554
499
|
pushRevalidationTraceEntry({
|
|
555
500
|
segmentId: segment.id,
|
|
@@ -566,7 +511,6 @@ export function withCacheLookup<TEnv>(
|
|
|
566
511
|
yield segment;
|
|
567
512
|
continue;
|
|
568
513
|
}
|
|
569
|
-
// No revalidation rules, use default behavior (skip if client has)
|
|
570
514
|
if (isTraceActive()) {
|
|
571
515
|
pushRevalidationTraceEntry({
|
|
572
516
|
segmentId: segment.id,
|
|
@@ -584,7 +528,6 @@ export function withCacheLookup<TEnv>(
|
|
|
584
528
|
continue;
|
|
585
529
|
}
|
|
586
530
|
|
|
587
|
-
// Evaluate revalidation rules
|
|
588
531
|
const shouldRevalidate = await evaluateRevalidation({
|
|
589
532
|
segment,
|
|
590
533
|
prevParams: ctx.prevParams,
|
|
@@ -618,7 +561,6 @@ export function withCacheLookup<TEnv>(
|
|
|
618
561
|
}
|
|
619
562
|
|
|
620
563
|
if (!shouldRevalidate) {
|
|
621
|
-
// Client has it, no revalidation needed
|
|
622
564
|
segment.component = null;
|
|
623
565
|
segment.loading = undefined;
|
|
624
566
|
}
|
|
@@ -626,7 +568,6 @@ export function withCacheLookup<TEnv>(
|
|
|
626
568
|
yield segment;
|
|
627
569
|
}
|
|
628
570
|
|
|
629
|
-
// Set streaming flag (once) and resolve render barrier.
|
|
630
571
|
const barrierReqCtx = _getRequestContext();
|
|
631
572
|
if (barrierReqCtx) {
|
|
632
573
|
if (barrierReqCtx._treeHasStreaming === undefined) {
|
|
@@ -635,77 +576,15 @@ export function withCacheLookup<TEnv>(
|
|
|
635
576
|
barrierReqCtx._resolveRenderBarrier(cacheResult.segments);
|
|
636
577
|
}
|
|
637
578
|
|
|
638
|
-
// Resolve loaders fresh (loaders are
|
|
639
|
-
//
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
);
|
|
649
|
-
|
|
650
|
-
// Update state - full match doesn't track matchedIds separately
|
|
651
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
652
|
-
|
|
653
|
-
// Yield fresh loader segments
|
|
654
|
-
for (const segment of loaderSegments) {
|
|
655
|
-
yield segment;
|
|
656
|
-
}
|
|
657
|
-
} else {
|
|
658
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
659
|
-
}
|
|
660
|
-
} else {
|
|
661
|
-
// Partial match (navigation) - loader resolution with revalidation
|
|
662
|
-
if (resolveLoadersOnlyWithRevalidation) {
|
|
663
|
-
const loaderResult = await Store.run(() =>
|
|
664
|
-
resolveLoadersOnlyWithRevalidation(
|
|
665
|
-
ctx.entries,
|
|
666
|
-
ctx.handlerContext,
|
|
667
|
-
ctx.clientSegmentSet,
|
|
668
|
-
ctx.prevParams,
|
|
669
|
-
ctx.request,
|
|
670
|
-
ctx.prevUrl,
|
|
671
|
-
ctx.url,
|
|
672
|
-
ctx.routeKey,
|
|
673
|
-
ctx.actionContext,
|
|
674
|
-
// Loaders are never cached in the segment cache, so segment
|
|
675
|
-
// staleness (cacheResult.shouldRevalidate) must not propagate.
|
|
676
|
-
// But browser-sent staleness (ctx.stale) — indicating an action
|
|
677
|
-
// happened in this or another tab — must still reach loaders.
|
|
678
|
-
ctx.stale || undefined,
|
|
679
|
-
),
|
|
680
|
-
);
|
|
681
|
-
|
|
682
|
-
// Update state with fresh loader matchedIds
|
|
683
|
-
state.matchedIds = [
|
|
684
|
-
...state.cachedMatchedIds!,
|
|
685
|
-
...loaderResult.matchedIds,
|
|
686
|
-
];
|
|
687
|
-
|
|
688
|
-
// Yield fresh loader segments
|
|
689
|
-
for (const segment of loaderResult.segments) {
|
|
690
|
-
yield segment;
|
|
691
|
-
}
|
|
692
|
-
} else {
|
|
693
|
-
state.matchedIds = state.cachedMatchedIds!;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
if (ms) {
|
|
697
|
-
const loaderEnd = performance.now();
|
|
698
|
-
ms.metrics.push({
|
|
699
|
-
label: "pipeline:loader-resolve",
|
|
700
|
-
duration: loaderEnd - loaderStart,
|
|
701
|
-
startTime: loaderStart - ms.requestStart,
|
|
702
|
-
depth: 1,
|
|
703
|
-
});
|
|
704
|
-
ms.metrics.push({
|
|
705
|
-
label: "pipeline:cache-hit",
|
|
706
|
-
duration: loaderEnd - pipelineStart,
|
|
707
|
-
startTime: pipelineStart - ms.requestStart,
|
|
708
|
-
});
|
|
709
|
-
}
|
|
579
|
+
// Resolve loaders fresh (loaders are never cached). Shared with the
|
|
580
|
+
// prerender-store path via resolveFreshLoadersAndYield.
|
|
581
|
+
yield* resolveFreshLoadersAndYield(
|
|
582
|
+
ctx,
|
|
583
|
+
state,
|
|
584
|
+
pipelineStart,
|
|
585
|
+
ms,
|
|
586
|
+
resolveLoadersOnly,
|
|
587
|
+
resolveLoadersOnlyWithRevalidation,
|
|
588
|
+
);
|
|
710
589
|
};
|
|
711
590
|
}
|