@rangojs/router 0.24.4 → 0.26.0
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 +1 -0
- package/dist/bin/rango.js +363 -39
- package/dist/testing/vitest.js +37 -4
- package/dist/types/browser/event-controller.d.ts +24 -5
- package/dist/types/browser/intercept-utils.d.ts +5 -2
- package/dist/types/browser/merge-segment-loaders.d.ts +0 -23
- package/dist/types/browser/navigation-transaction.d.ts +5 -5
- package/dist/types/browser/partial-update.d.ts +21 -13
- package/dist/types/browser/prefetch/cache.d.ts +8 -0
- package/dist/types/browser/rango-marker.d.ts +7 -0
- package/dist/types/browser/react/filter-segment-order.d.ts +10 -0
- package/dist/types/browser/react/use-handle.d.ts +20 -0
- package/dist/types/browser/react/use-href.d.ts +6 -0
- package/dist/types/browser/react/use-router.d.ts +6 -1
- package/dist/types/browser/response-adapter.d.ts +5 -3
- package/dist/types/browser/scroll-restoration.d.ts +9 -3
- package/dist/types/browser/segment-reconciler.d.ts +10 -13
- package/dist/types/browser/types.d.ts +38 -8
- package/dist/types/build/route-types/per-module-writer.d.ts +12 -0
- package/dist/types/cache/cf/cf-cache-store.d.ts +0 -2
- package/dist/types/cache/cf/cf-cache-types.d.ts +0 -16
- package/dist/types/cache/cf/cf-shell-frame.d.ts +2 -0
- package/dist/types/cache/handle-snapshot.d.ts +2 -2
- package/dist/types/cache/types.d.ts +16 -6
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +1 -15
- package/dist/types/client-urls/client-urls.d.ts +6 -2
- package/dist/types/client-urls/revalidate-registry.d.ts +1 -1
- package/dist/types/client-urls/server-projection.d.ts +9 -5
- package/dist/types/client-urls/types.d.ts +29 -16
- package/dist/types/client.d.ts +2 -2
- package/dist/types/client.rsc.d.ts +2 -2
- package/dist/types/decode-loader-results.d.ts +28 -7
- package/dist/types/handles/deferred-resolution.d.ts +3 -2
- package/dist/types/handles/meta.d.ts +5 -0
- package/dist/types/href-client.d.ts +3 -1
- package/dist/types/index.rsc.d.ts +1 -1
- package/dist/types/loader-redirect.d.ts +2 -3
- package/dist/types/outlet-context.d.ts +7 -6
- package/dist/types/prefetch-markers.d.ts +14 -5
- package/dist/types/prerender/build-shell-capture.d.ts +1 -2
- package/dist/types/prerender/writable-store.d.ts +2 -3
- package/dist/types/route-content-wrapper.d.ts +17 -14
- package/dist/types/route-definition/helpers-types.d.ts +7 -2
- package/dist/types/route-definition/resolve-handler-use.d.ts +6 -1
- package/dist/types/route-definition/rewrite.d.ts +48 -5
- package/dist/types/route-types.d.ts +2 -2
- package/dist/types/router/handler-context.d.ts +14 -2
- package/dist/types/router/intercept-resolution.d.ts +19 -46
- package/dist/types/router/lazy-includes.d.ts +7 -0
- package/dist/types/router/match-middleware/intercept-resolution.d.ts +2 -2
- package/dist/types/router/middleware.d.ts +0 -16
- package/dist/types/router/navigation-snapshot.d.ts +2 -0
- package/dist/types/router/prefetch-cache-ttl.d.ts +8 -11
- package/dist/types/router/revalidation.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +4 -16
- package/dist/types/router/router-interfaces.d.ts +0 -11
- package/dist/types/router/router-options.d.ts +4 -27
- package/dist/types/router/segment-resolution/mask-nested.d.ts +5 -3
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +31 -8
- package/dist/types/router/segment-resolution/revalidation.d.ts +38 -4
- package/dist/types/router/segment-resolution.d.ts +1 -1
- package/dist/types/router/segment-wrappers.d.ts +3 -5
- package/dist/types/router/substitute-pattern-params.d.ts +3 -2
- package/dist/types/router/tracing.d.ts +2 -2
- package/dist/types/router-versions.d.ts +8 -6
- package/dist/types/rsc/full-payload.d.ts +14 -2
- package/dist/types/rsc/helpers.d.ts +8 -0
- package/dist/types/rsc/manifest-init.d.ts +20 -0
- package/dist/types/rsc/prefetch-render-error.d.ts +22 -0
- package/dist/types/rsc/progressive-enhancement.d.ts +20 -0
- package/dist/types/rsc/rewrite-passes.d.ts +12 -2
- package/dist/types/rsc/server-action.d.ts +6 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +14 -4
- package/dist/types/rsc/shell-capture.d.ts +23 -2
- package/dist/types/rsc/types.d.ts +5 -8
- package/dist/types/segment-system.d.ts +15 -0
- package/dist/types/server/build-version-table.d.ts +10 -13
- package/dist/types/server/context.d.ts +90 -6
- package/dist/types/server/handle-store.d.ts +17 -6
- package/dist/types/server/request-context.d.ts +45 -7
- package/dist/types/server/request-headers.d.ts +12 -0
- package/dist/types/server/rewrite-trail.d.ts +8 -1
- package/dist/types/testing/build-versions.d.ts +0 -3
- package/dist/types/testing/e2e/index.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +1 -1
- package/dist/types/testing/index.d.ts +1 -1
- package/dist/types/testing/internal/client-urls-projection.d.ts +4 -3
- package/dist/types/testing/internal/seed-vars.d.ts +4 -4
- package/dist/types/testing/render-route.d.ts +21 -11
- package/dist/types/testing/run-loader.d.ts +7 -0
- package/dist/types/testing/run-middleware.d.ts +7 -0
- package/dist/types/testing/run-revalidate.d.ts +5 -4
- package/dist/types/testing/serve-shell-request.d.ts +42 -5
- package/dist/types/testing/shell-status.d.ts +17 -0
- package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/testing/vitest.d.ts +10 -1
- package/dist/types/thenable-status.d.ts +0 -6
- package/dist/types/types/handler-context.d.ts +12 -1
- package/dist/types/types/loader-types.d.ts +10 -4
- package/dist/types/types/route-entry.d.ts +2 -1
- package/dist/types/urls/path-helper-types.d.ts +4 -2
- package/dist/types/vite/discovery/client-urls-projection.d.ts +55 -5
- package/dist/types/vite/discovery/state.d.ts +20 -0
- package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +28 -16
- package/dist/types/vite/plugins/hoist/source.d.ts +8 -7
- package/dist/types/vite/plugins/virtual-entries.d.ts +6 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +7 -0
- package/dist/vite/index.js +6819 -6555
- package/package.json +1 -1
- package/skills/app-structure/SKILL.md +255 -0
- package/skills/app-structure/content-site.md +333 -0
- package/skills/app-structure/e-commerce.md +435 -0
- package/skills/app-structure/large-app.md +885 -0
- package/skills/app-structure/multi-app.md +280 -0
- package/skills/breadcrumbs/SKILL.md +6 -1
- package/skills/cache-guide/SKILL.md +4 -8
- package/skills/caching/SKILL.md +6 -6
- package/skills/catalog.json +12 -0
- package/skills/client-urls/SKILL.md +185 -32
- package/skills/comparison/references/framework-comparison.md +1 -1
- package/skills/composability/SKILL.md +10 -8
- package/skills/handler-use/SKILL.md +48 -9
- package/skills/hooks/handle-and-actions.md +104 -0
- package/skills/hooks/navigation.md +24 -10
- package/skills/hooks/urls.md +1 -1
- package/skills/host-router/SKILL.md +1 -1
- package/skills/i18n/SKILL.md +2 -1
- package/skills/intercept/SKILL.md +60 -29
- package/skills/layout/SKILL.md +6 -3
- package/skills/links/SKILL.md +151 -17
- package/skills/loader/SKILL.md +42 -19
- package/skills/middleware/SKILL.md +111 -15
- package/skills/observability/SKILL.md +11 -0
- package/skills/parallel/SKILL.md +5 -5
- package/skills/ppr/SKILL.md +103 -52
- package/skills/prerender/SKILL.md +4 -5
- package/skills/rango/SKILL.md +3 -0
- package/skills/response-routes/SKILL.md +4 -1
- package/skills/router-setup/SKILL.md +0 -2
- package/skills/scripts/SKILL.md +12 -1
- package/skills/server-actions/SKILL.md +60 -20
- package/skills/testing/SKILL.md +1 -0
- package/skills/testing/client-components.md +13 -10
- package/skills/testing/loader.md +25 -24
- package/skills/testing/middleware.md +11 -11
- package/skills/testing/render-handler.md +17 -17
- package/skills/testing/response-routes.md +4 -1
- package/skills/testing/serve-shell-request.md +86 -22
- package/skills/testing/server-actions.md +16 -16
- package/skills/ux-architecture/SKILL.md +980 -0
- package/skills/vercel/SKILL.md +1 -1
- package/skills/view-transitions/SKILL.md +43 -10
- package/src/__augment-tests__/augmented.check.ts +28 -0
- package/src/browser/event-controller.ts +44 -18
- package/src/browser/intercept-utils.ts +3 -2
- package/src/browser/merge-segment-loaders.ts +0 -85
- package/src/browser/navigation-bridge.ts +112 -84
- package/src/browser/navigation-client.ts +20 -15
- package/src/browser/navigation-store.ts +4 -2
- package/src/browser/navigation-transaction.ts +9 -8
- package/src/browser/partial-update.ts +90 -32
- package/src/browser/prefetch/cache.ts +8 -0
- package/src/browser/prefetch/fetch.ts +13 -3
- package/src/browser/rango-marker.ts +13 -0
- package/src/browser/react/NavigationProvider.tsx +25 -7
- package/src/browser/react/filter-segment-order.ts +13 -0
- package/src/browser/react/use-action.ts +9 -15
- package/src/browser/react/use-handle.ts +63 -71
- package/src/browser/react/use-href.tsx +24 -5
- package/src/browser/react/use-link-status.ts +1 -1
- package/src/browser/react/use-navigation.ts +30 -40
- package/src/browser/react/use-router.ts +37 -6
- package/src/browser/react/use-segments.ts +8 -12
- package/src/browser/response-adapter.ts +11 -5
- package/src/browser/rsc-router.tsx +3 -1
- package/src/browser/scroll-restoration.ts +34 -20
- package/src/browser/segment-reconciler.ts +11 -29
- package/src/browser/server-action-bridge.ts +52 -16
- package/src/browser/types.ts +40 -8
- package/src/build/generate-manifest.ts +12 -1
- package/src/build/route-types/codegen.ts +6 -2
- package/src/build/route-types/per-module-writer.ts +94 -61
- package/src/cache/cache-runtime.ts +9 -0
- package/src/cache/cache-scope.ts +2 -1
- package/src/cache/cf/cf-cache-store.ts +6 -7
- package/src/cache/cf/cf-cache-types.ts +0 -17
- package/src/cache/cf/cf-shell-frame.ts +3 -0
- package/src/cache/handle-snapshot.ts +2 -2
- package/src/cache/types.ts +16 -6
- package/src/cache/vercel/vercel-cache-store.ts +8 -19
- package/src/client-urls/client-urls.ts +202 -153
- package/src/client-urls/revalidate-registry.ts +12 -3
- package/src/client-urls/server-projection.ts +137 -66
- package/src/client-urls/types.ts +30 -15
- package/src/client.rsc.tsx +11 -1
- package/src/client.tsx +9 -1
- package/src/decode-loader-results.ts +64 -31
- package/src/handles/deferred-resolution.ts +3 -2
- package/src/handles/meta.ts +5 -0
- package/src/href-client.ts +3 -1
- package/src/index.rsc.ts +1 -0
- package/src/index.ts +12 -4
- package/src/loader-redirect.tsx +2 -3
- package/src/outlet-context.ts +7 -6
- package/src/prefetch-markers.ts +15 -5
- package/src/prerender/build-shell-capture.ts +1 -2
- package/src/prerender/writable-store.ts +2 -3
- package/src/reverse.ts +3 -3
- package/src/route-content-wrapper.tsx +19 -17
- package/src/route-definition/dsl-helpers.ts +41 -21
- package/src/route-definition/helpers-types.ts +7 -2
- package/src/route-definition/resolve-handler-use.ts +23 -10
- package/src/route-definition/rewrite.ts +86 -19
- package/src/route-types.ts +1 -2
- package/src/router/find-match.ts +37 -1
- package/src/router/handler-context.ts +85 -40
- package/src/router/intercept-resolution.ts +161 -307
- package/src/router/lazy-includes.ts +43 -27
- package/src/router/loader-resolution.ts +21 -1
- package/src/router/manifest.ts +15 -10
- package/src/router/match-api.ts +11 -1
- package/src/router/match-middleware/background-revalidation.ts +2 -4
- package/src/router/match-middleware/cache-lookup.ts +16 -20
- package/src/router/match-middleware/intercept-resolution.ts +41 -60
- package/src/router/match-result.ts +31 -2
- package/src/router/middleware.ts +6 -147
- package/src/router/navigation-snapshot.ts +38 -2
- package/src/router/prefetch-cache-ttl.ts +10 -18
- package/src/router/prerender-match.ts +2 -1
- package/src/router/revalidation.ts +24 -3
- package/src/router/router-context.ts +5 -18
- package/src/router/router-interfaces.ts +0 -13
- package/src/router/router-options.ts +4 -28
- package/src/router/segment-resolution/fresh.ts +6 -2
- package/src/router/segment-resolution/helpers.ts +7 -1
- package/src/router/segment-resolution/loader-cache.ts +4 -3
- package/src/router/segment-resolution/mask-nested.ts +5 -3
- package/src/router/segment-resolution/prefetch-deferral.ts +62 -12
- package/src/router/segment-resolution/revalidation.ts +75 -35
- package/src/router/segment-resolution.ts +0 -1
- package/src/router/segment-wrappers.ts +8 -13
- package/src/router/substitute-pattern-params.ts +3 -2
- package/src/router/tracing.ts +2 -2
- package/src/router-versions.ts +7 -7
- package/src/router.ts +5 -17
- package/src/rsc/full-payload.ts +26 -4
- package/src/rsc/handler.ts +86 -48
- package/src/rsc/helpers.ts +13 -0
- package/src/rsc/manifest-init.ts +56 -3
- package/src/rsc/prefetch-render-error.ts +38 -0
- package/src/rsc/progressive-enhancement.ts +161 -211
- package/src/rsc/rewrite-passes.ts +56 -9
- package/src/rsc/rsc-rendering.ts +79 -23
- package/src/rsc/server-action.ts +25 -2
- package/src/rsc/shell-capture-constants.ts +26 -3
- package/src/rsc/shell-capture.ts +137 -51
- package/src/rsc/types.ts +5 -9
- package/src/segment-system.tsx +125 -119
- package/src/server/build-version-table.ts +12 -24
- package/src/server/context.ts +160 -7
- package/src/server/handle-store.ts +80 -12
- package/src/server/request-context.ts +46 -6
- package/src/server/request-headers.ts +32 -0
- package/src/server/rewrite-trail.ts +55 -9
- package/src/ssr/ssr-root.tsx +6 -10
- package/src/testing/build-versions.ts +0 -3
- package/src/testing/dispatch.ts +5 -8
- package/src/testing/e2e/index.ts +1 -0
- package/src/testing/flight.entry.ts +1 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/internal/client-urls-projection.ts +31 -11
- package/src/testing/internal/seed-vars.ts +4 -4
- package/src/testing/render-route.tsx +83 -40
- package/src/testing/run-loader.ts +26 -2
- package/src/testing/run-middleware.ts +10 -0
- package/src/testing/run-revalidate.ts +13 -6
- package/src/testing/serve-shell-request.ts +79 -9
- package/src/testing/shell-status.ts +40 -0
- package/src/testing/vitest-stubs/version.ts +1 -0
- package/src/testing/vitest.ts +74 -7
- package/src/thenable-status.ts +0 -11
- package/src/types/handler-context.ts +12 -1
- package/src/types/loader-types.ts +10 -4
- package/src/types/route-entry.ts +2 -1
- package/src/urls/include-helper.ts +38 -11
- package/src/urls/path-helper-types.ts +4 -2
- package/src/vite/discovery/client-urls-projection.ts +205 -16
- package/src/vite/discovery/discover-routers.ts +2 -2
- package/src/vite/discovery/prerender-collection.ts +2 -6
- package/src/vite/discovery/shell-prerender-phase.ts +1 -5
- package/src/vite/discovery/state.ts +26 -0
- package/src/vite/plugins/client-urls-revalidate-hoist.ts +190 -77
- package/src/vite/plugins/expose-internal-ids.ts +46 -40
- package/src/vite/plugins/hoist/source.ts +8 -7
- package/src/vite/plugins/transition-when-hoist.ts +1 -0
- package/src/vite/plugins/version-plugin.ts +7 -0
- package/src/vite/plugins/version.d.ts +7 -0
- package/src/vite/plugins/virtual-entries.ts +20 -0
- package/src/vite/rango.ts +4 -1
- package/src/vite/router-discovery.ts +39 -7
- package/src/vite/utils/prerender-utils.ts +17 -0
|
@@ -64,12 +64,15 @@ import {
|
|
|
64
64
|
} from "./segment-resolution/prefetch-deferral.js";
|
|
65
65
|
import {
|
|
66
66
|
assertNonCacheableReadAllowed,
|
|
67
|
+
getLoaderReverseScope,
|
|
67
68
|
isInsideLoaderScope,
|
|
69
|
+
scopeReverse,
|
|
68
70
|
runInsideLoaderBodyScope,
|
|
69
71
|
runInsideLoaderRun,
|
|
70
72
|
isInsidePushCallbackScope,
|
|
71
73
|
runInsidePushCallbackScope,
|
|
72
74
|
type LoaderRunIdentity,
|
|
75
|
+
type ScopableReverse,
|
|
73
76
|
} from "../server/context.js";
|
|
74
77
|
import { debugLog } from "./logging.js";
|
|
75
78
|
|
|
@@ -179,6 +182,8 @@ export function wrapLoaderWithErrorHandling<T>(
|
|
|
179
182
|
// The token is the loader's $$id (hash#export in prod, pathfrag#export in dev),
|
|
180
183
|
// not a clean display name.
|
|
181
184
|
const loaderName = segmentId.split(".").pop() || "unknown";
|
|
185
|
+
// Captured now: the rejection can settle outside the request's ALS frame.
|
|
186
|
+
const renderErrors = _getRequestContext()?._renderErrors;
|
|
182
187
|
|
|
183
188
|
return Promise.resolve(promise)
|
|
184
189
|
.then(
|
|
@@ -275,6 +280,11 @@ export function wrapLoaderWithErrorHandling<T>(
|
|
|
275
280
|
};
|
|
276
281
|
}
|
|
277
282
|
|
|
283
|
+
// The error renders in place inside a 200 as a value, which neither
|
|
284
|
+
// Flight nor Fizz reports: record it like their errors, so a writer
|
|
285
|
+
// that reads _renderErrors (the document cache) does not store it.
|
|
286
|
+
renderErrors?.push(error);
|
|
287
|
+
|
|
278
288
|
// Find nearest error boundary
|
|
279
289
|
const fallback = findNearestErrorBoundary(entry);
|
|
280
290
|
|
|
@@ -543,6 +553,11 @@ function createLoaderExecutor<TEnv>(
|
|
|
543
553
|
// (runInsideLoaderScope in fresh.ts). Handler-invoked loaders are NOT
|
|
544
554
|
// inside loader scope. This determines whether rendered() is allowed.
|
|
545
555
|
const isDslLoader = isInsideLoaderScope();
|
|
556
|
+
// The body resolves ctx.reverse(".name") in its DSL declaration's module
|
|
557
|
+
// (a layout's / parallel's / cache()'s loader). A route's loader, and one
|
|
558
|
+
// a handler starts with ctx.use(), resolve from the route. One run per
|
|
559
|
+
// request: the first declaration to start it wins.
|
|
560
|
+
const reverseScope = getLoaderReverseScope();
|
|
546
561
|
|
|
547
562
|
// Owning segment for ctx.handle() attribution, captured SYNCHRONOUSLY at
|
|
548
563
|
// kickoff: segment resolution sets _currentSegmentId while resolving the
|
|
@@ -568,6 +583,7 @@ function createLoaderExecutor<TEnv>(
|
|
|
568
583
|
InternalHandlerContext<any, TEnv>,
|
|
569
584
|
| "_routeName"
|
|
570
585
|
| "_responseType"
|
|
586
|
+
| "_reverseScope"
|
|
571
587
|
| "_currentSegmentId"
|
|
572
588
|
| "_claimLoaderPushes"
|
|
573
589
|
| "_runLoaderIsolated"
|
|
@@ -648,9 +664,13 @@ function createLoaderExecutor<TEnv>(
|
|
|
648
664
|
}) as LoaderContext["use"],
|
|
649
665
|
method: "GET",
|
|
650
666
|
body: undefined,
|
|
651
|
-
reverse:
|
|
667
|
+
reverse: scopeReverse(
|
|
668
|
+
ctx.reverse as ScopableReverse,
|
|
669
|
+
reverseScope,
|
|
670
|
+
) as LoaderContext["reverse"],
|
|
652
671
|
_routeName: internal._routeName,
|
|
653
672
|
_responseType: internal._responseType,
|
|
673
|
+
_reverseScope: reverseScope,
|
|
654
674
|
_currentSegmentId: owningSegmentId,
|
|
655
675
|
_claimLoaderPushes: internal._claimLoaderPushes,
|
|
656
676
|
_runLoaderIsolated: internal._runLoaderIsolated,
|
package/src/router/manifest.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { createRouteHelpers } from "../route-definition";
|
|
|
3
3
|
import {
|
|
4
4
|
getContext,
|
|
5
5
|
runWithPrefixes,
|
|
6
|
+
getDocumentModeEntry,
|
|
6
7
|
getIsolatedLazyParent,
|
|
7
8
|
type EntryData,
|
|
8
9
|
type MetricsStore,
|
|
@@ -11,10 +12,8 @@ import MapRootLayout from "../server/root-layout";
|
|
|
11
12
|
import { joinPrefix } from "./pattern-matching.js";
|
|
12
13
|
import type { RouteEntry } from "../types";
|
|
13
14
|
import type { UrlPatterns } from "../urls";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
resolveIncludeModule,
|
|
17
|
-
} from "../urls/include-provider.js";
|
|
15
|
+
import { isIncludeProvider } from "../urls/include-provider.js";
|
|
16
|
+
import { resolveEntryPatterns } from "./lazy-includes.js";
|
|
18
17
|
import { VERSION } from "@rangojs/router:version";
|
|
19
18
|
|
|
20
19
|
// Tags an error thrown while dynamically importing an async include's module
|
|
@@ -122,12 +121,18 @@ export async function loadManifest(
|
|
|
122
121
|
mountIndex !== undefined ? `#router.M${mountIndex}` : "#router";
|
|
123
122
|
|
|
124
123
|
// For lazy entries, use the captured parent from include() context
|
|
125
|
-
// This ensures routes are registered under the correct layout hierarchy
|
|
124
|
+
// This ensures routes are registered under the correct layout hierarchy.
|
|
125
|
+
// The captured chain comes from an evaluation without isSSR: a document
|
|
126
|
+
// request takes its document-mode copy (getDocumentModeEntry, #1179).
|
|
126
127
|
const lazyContext =
|
|
127
128
|
entry.lazy && entry.lazyPatterns ? entry.lazyContext : null;
|
|
129
|
+
const capturedParent =
|
|
130
|
+
(lazyContext?.parent as EntryData | null | undefined) ?? Store.parent;
|
|
128
131
|
const parentForContext = lazyContext
|
|
129
132
|
? getIsolatedLazyParent(
|
|
130
|
-
|
|
133
|
+
isSSR && capturedParent
|
|
134
|
+
? getDocumentModeEntry(capturedParent)
|
|
135
|
+
: capturedParent,
|
|
131
136
|
)
|
|
132
137
|
: Store.parent;
|
|
133
138
|
|
|
@@ -167,6 +172,9 @@ export async function loadManifest(
|
|
|
167
172
|
// undefined) so a prior lazy build's scope cannot leak into a later
|
|
168
173
|
// non-lazy build on the same ALS-backed Store.
|
|
169
174
|
Store.includeScope = lazyContext?.includeScope;
|
|
175
|
+
// Same rule for the include's tree position (hidden include names).
|
|
176
|
+
Store.scopePath = lazyContext?.scopePath;
|
|
177
|
+
Store.hiddenScopePath = lazyContext?.hiddenScopePath;
|
|
170
178
|
|
|
171
179
|
const handlerExecStart = performance.now();
|
|
172
180
|
const useItems = await getContext().runWithStore(
|
|
@@ -190,10 +198,7 @@ export async function loadManifest(
|
|
|
190
198
|
// cache the resolved patterns on the entry so later renders reuse them.
|
|
191
199
|
if (isIncludeProvider(entry.lazyPatterns)) {
|
|
192
200
|
try {
|
|
193
|
-
|
|
194
|
-
await entry.lazyPatterns(),
|
|
195
|
-
entry.staticPrefix,
|
|
196
|
-
) as unknown as UrlPatterns<any>;
|
|
201
|
+
await resolveEntryPatterns(entry);
|
|
197
202
|
} catch (err) {
|
|
198
203
|
// A failed dynamic import of a REAL, matched route's module is a
|
|
199
204
|
// server error, not a missing route. Tag it so the outer catch
|
package/src/router/match-api.ts
CHANGED
|
@@ -54,10 +54,12 @@ import {
|
|
|
54
54
|
type RouteSnapshot,
|
|
55
55
|
} from "./route-snapshot.js";
|
|
56
56
|
import { resolveNavigation } from "./navigation-snapshot.js";
|
|
57
|
+
import { pathKey, visitorUrl } from "../server/rewrite-trail.js";
|
|
57
58
|
import { withLayoutLoaderCopies } from "../client-urls/layout-loader-copies.js";
|
|
58
59
|
import {
|
|
59
60
|
partialDeferralMode,
|
|
60
61
|
planPrefetchDeferral,
|
|
62
|
+
resolveInterceptDeferralScope,
|
|
61
63
|
requestKind,
|
|
62
64
|
} from "./segment-resolution/prefetch-deferral.js";
|
|
63
65
|
|
|
@@ -375,6 +377,12 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
375
377
|
}
|
|
376
378
|
|
|
377
379
|
setRequestContextPrevRouteKey(nav.effectiveFromMatch?.routeKey);
|
|
380
|
+
// Two visitor URLs can share a rewrite target, and the render may read
|
|
381
|
+
// ctx.rewrittenFrom: a move of the visitor's URL counts as a change.
|
|
382
|
+
if (reqCtx && nav.prevVisitorUrl) {
|
|
383
|
+
reqCtx._visitorMoved =
|
|
384
|
+
pathKey(visitorUrl(reqCtx, cleanUrl)) !== pathKey(nav.prevVisitorUrl);
|
|
385
|
+
}
|
|
378
386
|
|
|
379
387
|
const interceptSelectorContext: InterceptSelectorContext = {
|
|
380
388
|
// The source's params come from matching its URL (the intercept source
|
|
@@ -484,7 +492,6 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
484
492
|
prefetch: kind === "prefetch",
|
|
485
493
|
method: request.method,
|
|
486
494
|
isAction,
|
|
487
|
-
isIntercept,
|
|
488
495
|
isShellCapture: reqCtx?._shellCaptureRun === true,
|
|
489
496
|
}),
|
|
490
497
|
matched,
|
|
@@ -492,6 +499,9 @@ export async function createMatchContextForPartial<TEnv>(
|
|
|
492
499
|
// What the page holds, not the copy forced above: see
|
|
493
500
|
// prefetch-deferral.ts.
|
|
494
501
|
held,
|
|
502
|
+
interceptResult
|
|
503
|
+
? resolveInterceptDeferralScope(interceptResult.intercept)
|
|
504
|
+
: undefined,
|
|
495
505
|
);
|
|
496
506
|
(handlerContext as InternalHandlerContext<any, TEnv>)._prefetchDeferral =
|
|
497
507
|
deferral;
|
|
@@ -230,10 +230,8 @@ export async function rerenderAndCacheRoute<TEnv>(
|
|
|
230
230
|
handlerContext,
|
|
231
231
|
true, // belongsToRoute
|
|
232
232
|
undefined, // no revalidationContext: render fresh
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
// short-circuit Response would abort the write.
|
|
236
|
-
{ skipMiddleware: true },
|
|
233
|
+
// A handler error rejects, so the failure is never cached.
|
|
234
|
+
{ background: true },
|
|
237
235
|
),
|
|
238
236
|
)),
|
|
239
237
|
);
|
|
@@ -101,6 +101,7 @@ import { treeHasStreaming } from "./segment-resolution.js";
|
|
|
101
101
|
import { loaderPins } from "../segment-resolution/loader-cache.js";
|
|
102
102
|
import {
|
|
103
103
|
fillSends,
|
|
104
|
+
interceptFillSkips,
|
|
104
105
|
recordUse,
|
|
105
106
|
} from "../segment-resolution/prefetch-deferral.js";
|
|
106
107
|
import type { PrerenderStore, PrerenderEntry } from "../../prerender/store.js";
|
|
@@ -127,6 +128,7 @@ import { ShellRecordUnavailableError } from "../../cache/shell-snapshot.js";
|
|
|
127
128
|
import { prerenderStoreShortCircuits } from "../navigation-snapshot.js";
|
|
128
129
|
import { paramsEqual } from "../params-util.js";
|
|
129
130
|
import { requestHeaders } from "../../server/request-headers.js";
|
|
131
|
+
import { isInterceptSegment } from "../../browser/intercept-utils.js";
|
|
130
132
|
|
|
131
133
|
// Lazily initialized prerender store singleton and dynamically imported deps.
|
|
132
134
|
// Dynamic imports prevent pulling in @vitejs/plugin-rsc/rsc virtual module at
|
|
@@ -207,6 +209,7 @@ async function* resolveFreshLoadersAndYield<TEnv>(
|
|
|
207
209
|
resolveLoadersOnlyWithRevalidation: RouterContext<TEnv>["resolveLoadersOnlyWithRevalidation"],
|
|
208
210
|
): AsyncGenerator<ResolvedSegment> {
|
|
209
211
|
const loaderStart = performance.now();
|
|
212
|
+
entries = entries.filter((e) => !interceptFillSkips(ctx, e.shortCode));
|
|
210
213
|
|
|
211
214
|
if (ctx.isFullMatch) {
|
|
212
215
|
if (resolveLoadersOnly) {
|
|
@@ -347,14 +350,8 @@ async function* yieldFromStore<TEnv>(
|
|
|
347
350
|
!ctx.isFullMatch && !paramsEqual(ctx.matched.params, ctx.prevParams);
|
|
348
351
|
const resendRouteSegments = replaceable === true && ctx.isAction;
|
|
349
352
|
for (const segment of segments) {
|
|
350
|
-
if (
|
|
351
|
-
|
|
352
|
-
ctx.clientSegmentSet.has(segment.id) &&
|
|
353
|
-
// A stored intercept segment is re-sent, as on the runtime cache path:
|
|
354
|
-
// its loaders run (handleCacheHitIntercept), and a kept (null) one would
|
|
355
|
-
// be left out of the response with its loaders' new data.
|
|
356
|
-
!segment.namespace?.startsWith("intercept:")
|
|
357
|
-
) {
|
|
353
|
+
if (interceptFillSkips(ctx, segment)) continue;
|
|
354
|
+
if (!ctx.isFullMatch && ctx.clientSegmentSet.has(segment.id)) {
|
|
358
355
|
// A fill keeps it (fillSends); otherwise it is sent again when the
|
|
359
356
|
// params changed or an action re-sends the route's own segments.
|
|
360
357
|
const sends =
|
|
@@ -912,10 +909,15 @@ export function withCacheLookup<TEnv>(
|
|
|
912
909
|
const entryRevalidateMap = canCheckSegmentRevalidation
|
|
913
910
|
? buildEntryRevalidateMap(ctx.entries)
|
|
914
911
|
: undefined;
|
|
912
|
+
const searchChanged =
|
|
913
|
+
ctx.prevUrl.search !== ctx.url.search ||
|
|
914
|
+
pipelineReqCtx?._visitorMoved === true;
|
|
915
|
+
const routeParamsChanged = !paramsEqual(ctx.matched.params, ctx.prevParams);
|
|
915
916
|
|
|
916
917
|
yield* liveSegments;
|
|
917
918
|
|
|
918
919
|
for (const segment of cacheResult.segments) {
|
|
920
|
+
if (interceptFillSkips(ctx, segment)) continue;
|
|
919
921
|
if (!ctx.clientSegmentSet.has(segment.id)) {
|
|
920
922
|
if (isTraceActive()) {
|
|
921
923
|
pushRevalidationTraceEntry({
|
|
@@ -932,12 +934,8 @@ export function withCacheLookup<TEnv>(
|
|
|
932
934
|
continue;
|
|
933
935
|
}
|
|
934
936
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
continue;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
// A fill keeps a held segment outright (fillSends).
|
|
937
|
+
// A fill keeps a held segment outright (fillSends), an intercept's
|
|
938
|
+
// included.
|
|
941
939
|
if (
|
|
942
940
|
fillSends(ctx.handlerContext, segment.id, ctx.clientSegmentSet) ===
|
|
943
941
|
false
|
|
@@ -946,14 +944,12 @@ export function withCacheLookup<TEnv>(
|
|
|
946
944
|
yield segment;
|
|
947
945
|
continue;
|
|
948
946
|
}
|
|
947
|
+
if (isInterceptSegment(segment)) {
|
|
948
|
+
yield segment;
|
|
949
|
+
continue;
|
|
950
|
+
}
|
|
949
951
|
|
|
950
952
|
const entryInfo = entryRevalidateMap?.get(segment.id);
|
|
951
|
-
|
|
952
|
-
const searchChanged = ctx.prevUrl.search !== ctx.url.search;
|
|
953
|
-
const routeParamsChanged = !paramsEqual(
|
|
954
|
-
ctx.matched.params,
|
|
955
|
-
ctx.prevParams,
|
|
956
|
-
);
|
|
957
953
|
const shouldDefaultRevalidate =
|
|
958
954
|
(searchChanged || routeParamsChanged) &&
|
|
959
955
|
(segment.type === "route" ||
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* v
|
|
30
30
|
* +----------------------+ +----------------------------+
|
|
31
31
|
* | Fresh intercept? |yes>| resolveInterceptEntry() |
|
|
32
|
-
* | (!cacheHit or | | -
|
|
32
|
+
* | (!cacheHit or | | - loaders, UI |
|
|
33
33
|
* | no intercept segs) | +----------------------------+
|
|
34
34
|
* +----------------------+ |
|
|
35
35
|
* | no v
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
*
|
|
60
60
|
* 1. Fresh intercept (no cache):
|
|
61
61
|
* - Full resolution of intercept entry
|
|
62
|
-
* - Resolves
|
|
62
|
+
* - Resolves loaders and component
|
|
63
63
|
* - Yields all intercept segments
|
|
64
64
|
*
|
|
65
65
|
* 2. Cache hit with intercept:
|
|
@@ -106,6 +106,7 @@ import type { MatchContext, MatchPipelineState } from "../match-context.js";
|
|
|
106
106
|
import { getRouterContext } from "../router-context.js";
|
|
107
107
|
import type { GeneratorMiddleware } from "./cache-lookup.js";
|
|
108
108
|
import { debugLog } from "../logging.js";
|
|
109
|
+
import { isInterceptSegment } from "../../browser/intercept-utils.js";
|
|
109
110
|
|
|
110
111
|
/**
|
|
111
112
|
* Creates intercept resolution middleware
|
|
@@ -151,7 +152,7 @@ export function withInterceptResolution<TEnv>(
|
|
|
151
152
|
|
|
152
153
|
if (skipInterceptResolution) {
|
|
153
154
|
if (ctx.interceptResult && state.cacheHit && ctx.isIntercept) {
|
|
154
|
-
await handleCacheHitIntercept(ctx, state, segments);
|
|
155
|
+
yield* await handleCacheHitIntercept(ctx, state, segments);
|
|
155
156
|
}
|
|
156
157
|
if (ms) {
|
|
157
158
|
ms.metrics.push({
|
|
@@ -212,77 +213,57 @@ export function withInterceptResolution<TEnv>(
|
|
|
212
213
|
};
|
|
213
214
|
}
|
|
214
215
|
|
|
216
|
+
/**
|
|
217
|
+
* A cache or prerender hit that carries the intercept's slot: the slot keeps
|
|
218
|
+
* its stored component and layout, and its loaders, never stored, resolve as
|
|
219
|
+
* loader segments of it. Returns those segments for the caller to yield.
|
|
220
|
+
*/
|
|
215
221
|
async function handleCacheHitIntercept<TEnv>(
|
|
216
222
|
ctx: MatchContext<TEnv>,
|
|
217
223
|
state: MatchPipelineState,
|
|
218
224
|
segments: ResolvedSegment[],
|
|
219
|
-
): Promise<
|
|
220
|
-
if (!ctx.interceptResult) return;
|
|
225
|
+
): Promise<ResolvedSegment[]> {
|
|
226
|
+
if (!ctx.interceptResult) return [];
|
|
221
227
|
|
|
222
228
|
const { resolveInterceptLoadersOnly } = getRouterContext<TEnv>();
|
|
223
229
|
|
|
224
230
|
const slotName = ctx.interceptResult.intercept.slotName;
|
|
225
231
|
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
ctx.interceptResult!.intercept,
|
|
236
|
-
ctx.interceptResult!.entry,
|
|
237
|
-
ctx.matched.params,
|
|
238
|
-
ctx.handlerContext,
|
|
239
|
-
true, // belongsToRoute
|
|
240
|
-
{
|
|
241
|
-
clientSegmentIds: ctx.clientSegmentSet,
|
|
242
|
-
prevParams: ctx.prevParams,
|
|
243
|
-
request: ctx.request,
|
|
244
|
-
prevUrl: ctx.prevUrl,
|
|
245
|
-
nextUrl: ctx.url,
|
|
246
|
-
routeKey: ctx.routeKey,
|
|
247
|
-
actionContext: ctx.actionContext,
|
|
248
|
-
stale: ctx.stale,
|
|
249
|
-
},
|
|
250
|
-
),
|
|
251
|
-
);
|
|
232
|
+
const cachedSlot = segments.filter(isInterceptSegment);
|
|
233
|
+
// A record stored before 0.25.0 carries the loaders' aggregate on the slot;
|
|
234
|
+
// the loader segments below replace it. Build versions hash the router's
|
|
235
|
+
// code, so an upgrade does not read one; a custom store that ignores
|
|
236
|
+
// versions can.
|
|
237
|
+
for (const slot of cachedSlot) {
|
|
238
|
+
delete slot.loaderDataPromise;
|
|
239
|
+
delete slot.loaderIds;
|
|
240
|
+
}
|
|
252
241
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
interceptMainSegment.loaderIds = freshLoaderResult.loaderIds;
|
|
261
|
-
debugLog(
|
|
262
|
-
"matchPartial.intercept",
|
|
263
|
-
freshLoaderResult.loaderIds.length > 0
|
|
264
|
-
? "cache hit with fresh intercept loaders"
|
|
265
|
-
: "cache hit, every intercept loader held",
|
|
242
|
+
const loaderSegments = resolveInterceptLoadersOnly
|
|
243
|
+
? await ctx.Store.run(() =>
|
|
244
|
+
resolveInterceptLoadersOnly(
|
|
245
|
+
ctx.interceptResult!.intercept,
|
|
246
|
+
ctx.interceptResult!.entry,
|
|
247
|
+
ctx.handlerContext,
|
|
248
|
+
true, // belongsToRoute
|
|
266
249
|
{
|
|
267
|
-
|
|
268
|
-
|
|
250
|
+
clientSegmentIds: ctx.clientSegmentSet,
|
|
251
|
+
prevParams: ctx.prevParams,
|
|
252
|
+
request: ctx.request,
|
|
253
|
+
prevUrl: ctx.prevUrl,
|
|
254
|
+
nextUrl: ctx.url,
|
|
255
|
+
routeKey: ctx.routeKey,
|
|
256
|
+
actionContext: ctx.actionContext,
|
|
257
|
+
stale: ctx.stale,
|
|
269
258
|
},
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
"cache hit, intercept has no loaders",
|
|
276
|
-
{
|
|
277
|
-
routeName: ctx.localRouteName,
|
|
278
|
-
slotName,
|
|
279
|
-
},
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
259
|
+
),
|
|
260
|
+
)
|
|
261
|
+
: [];
|
|
262
|
+
const interceptSegments = [...cachedSlot, ...loaderSegments];
|
|
263
|
+
state.interceptSegments = interceptSegments;
|
|
284
264
|
state.slots[slotName] = {
|
|
285
265
|
active: true,
|
|
286
266
|
segments: interceptSegments,
|
|
287
267
|
};
|
|
268
|
+
return loaderSegments;
|
|
288
269
|
}
|
|
@@ -109,10 +109,14 @@
|
|
|
109
109
|
*/
|
|
110
110
|
import type { MatchResult, ResolvedSegment } from "../types.js";
|
|
111
111
|
import { isPlaceholder } from "../types/segments.js";
|
|
112
|
+
import { loaderParentId } from "../browser/react/filter-segment-order.js";
|
|
112
113
|
import type { MatchContext, MatchPipelineState } from "./match-context.js";
|
|
113
114
|
import { debugLog } from "./logging.js";
|
|
114
115
|
import { appendMetric } from "./metrics.js";
|
|
115
|
-
import {
|
|
116
|
+
import {
|
|
117
|
+
collectInterceptTargetNames,
|
|
118
|
+
interceptSegmentIds,
|
|
119
|
+
} from "./intercept-resolution.js";
|
|
116
120
|
|
|
117
121
|
export async function collectSegments(
|
|
118
122
|
generator: AsyncGenerator<ResolvedSegment>,
|
|
@@ -192,6 +196,25 @@ function deduplicateLoaderSegments(
|
|
|
192
196
|
return { segments: result, removedIds };
|
|
193
197
|
}
|
|
194
198
|
|
|
199
|
+
/**
|
|
200
|
+
* An intercept's `matched`: the client's ids without any of the slot's (its
|
|
201
|
+
* id and every loader segment on it, another intercept's into the same slot
|
|
202
|
+
* included), then the slot's (interceptSegmentIds). One order for the
|
|
203
|
+
* prefetch, its fill, an action and a revisit: a fill whose `matched` differs
|
|
204
|
+
* from its tree's is rendered as a new tree (browser/partial-update.ts
|
|
205
|
+
* fillHoles).
|
|
206
|
+
*/
|
|
207
|
+
function interceptMatched(
|
|
208
|
+
clientIds: readonly string[],
|
|
209
|
+
slotIds: readonly string[],
|
|
210
|
+
): string[] {
|
|
211
|
+
// loaderParentId leaves a non-loader id as it is: the slot's own id goes too.
|
|
212
|
+
return [
|
|
213
|
+
...clientIds.filter((id) => loaderParentId(id) !== slotIds[0]),
|
|
214
|
+
...slotIds,
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
|
|
195
218
|
export function buildMatchResult<TEnv>(
|
|
196
219
|
allSegments: ResolvedSegment[],
|
|
197
220
|
ctx: MatchContext<TEnv>,
|
|
@@ -223,7 +246,13 @@ export function buildMatchResult<TEnv>(
|
|
|
223
246
|
} else {
|
|
224
247
|
allIds = ctx.interceptResult
|
|
225
248
|
? ctx.clientSegmentIds.length > 0
|
|
226
|
-
?
|
|
249
|
+
? interceptMatched(
|
|
250
|
+
ctx.clientSegmentIds,
|
|
251
|
+
interceptSegmentIds(
|
|
252
|
+
ctx.interceptResult.entry,
|
|
253
|
+
ctx.interceptResult.intercept,
|
|
254
|
+
),
|
|
255
|
+
)
|
|
227
256
|
: allSegments.map((s) => s.id)
|
|
228
257
|
: [...state.matchedIds, ...state.interceptSegments.map((s) => s.id)];
|
|
229
258
|
|