@rangojs/router 0.21.0 → 0.22.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/dist/bin/rango.js +13 -1
- package/dist/types/browser/event-controller.d.ts +30 -13
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/partial-update.d.ts +2 -1
- package/dist/types/browser/prefetch/default-strategy.d.ts +16 -20
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +14 -0
- package/dist/types/browser/rsc-router.d.ts +13 -2
- package/dist/types/browser/types.d.ts +10 -0
- package/dist/types/build/generate-manifest.d.ts +2 -0
- package/dist/types/cache/background-task.d.ts +22 -0
- package/dist/types/cache/cache-key-utils.d.ts +50 -5
- package/dist/types/cache/cache-policy.d.ts +17 -0
- package/dist/types/cache/cache-scope.d.ts +1 -1
- package/dist/types/cache/cf/cf-cache-store.d.ts +7 -1
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +23 -0
- package/dist/types/cache/index.d.ts +1 -1
- package/dist/types/cache/invalidation-order.d.ts +14 -0
- package/dist/types/cache/memory-segment-store.d.ts +33 -1
- package/dist/types/cache/shell-snapshot.d.ts +10 -1
- package/dist/types/cache/store-scope.d.ts +22 -0
- package/dist/types/cache/tag-invalidation.d.ts +7 -6
- package/dist/types/cache/types.d.ts +63 -14
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +7 -1
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +7 -0
- package/dist/types/internal-suspense-audit.d.ts +1 -0
- package/dist/types/loader-store.d.ts +4 -8
- package/dist/types/outlet-provider.d.ts +2 -1
- package/dist/types/prerender/cloudflare.d.ts +49 -0
- package/dist/types/prerender/create-prerender-trigger.d.ts +121 -0
- package/dist/types/prerender/index.d.ts +12 -0
- package/dist/types/prerender/memory-prerender-store.d.ts +29 -0
- package/dist/types/prerender/on-demand.d.ts +272 -0
- package/dist/types/prerender/producer-guard.d.ts +33 -0
- package/dist/types/prerender/shell-manifest-key.d.ts +1 -18
- package/dist/types/prerender/warm-request.d.ts +65 -0
- package/dist/types/prerender/warm.d.ts +65 -0
- package/dist/types/prerender/writable-store.d.ts +170 -0
- package/dist/types/prerender.d.ts +27 -0
- package/dist/types/reverse.d.ts +1 -1
- package/dist/types/route-content-wrapper.d.ts +3 -1
- package/dist/types/router/error-handling.d.ts +2 -0
- package/dist/types/router/handler-context.d.ts +1 -1
- package/dist/types/router/match-middleware/cache-lookup.d.ts +14 -0
- package/dist/types/router/pattern-matching.d.ts +2 -0
- package/dist/types/router/prefetch-default.d.ts +4 -4
- package/dist/types/router/prerender-match.d.ts +23 -1
- package/dist/types/router/route-trie-builder.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +1 -0
- package/dist/types/router/router-interfaces.d.ts +30 -0
- package/dist/types/router/router-options.d.ts +24 -0
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +2 -1
- package/dist/types/router/segment-resolution/revalidation.d.ts +5 -1
- package/dist/types/router/segment-resolution/streamed-handler-boundary.d.ts +43 -0
- package/dist/types/router/trie-matching.d.ts +2 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +6 -4
- package/dist/types/rsc/shell-capture-constants.d.ts +20 -5
- package/dist/types/rsc/shell-capture.d.ts +14 -1
- package/dist/types/rsc/shell-serve.d.ts +2 -2
- package/dist/types/rsc/ssr-module-loader.d.ts +15 -0
- package/dist/types/rsc/types.d.ts +8 -0
- package/dist/types/segment-boundary-content.d.ts +17 -0
- package/dist/types/segment-loader-promise.d.ts +2 -6
- package/dist/types/server/build-version-table.d.ts +9 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +2 -0
- package/dist/types/server/request-context.d.ts +63 -2
- package/dist/types/suspense-audit-react.d.ts +26 -0
- package/dist/types/suspense-audit.d.ts +157 -0
- package/dist/types/testing/action-form.d.ts +34 -0
- package/dist/types/testing/flight.entry.d.ts +2 -0
- package/dist/types/testing/index.d.ts +4 -0
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/serve-shell-request.d.ts +34 -4
- package/dist/types/testing/shell-status.d.ts +14 -6
- package/dist/types/testing/vitest-stubs/plugin-rsc.d.ts +9 -6
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +7 -0
- package/dist/types/types/route-entry.d.ts +5 -0
- package/dist/types/urls/path-helper.d.ts +18 -0
- package/dist/types/vite/discovery/state.d.ts +11 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/vite/index.js +180 -497
- package/package.json +13 -3
- package/skills/cache-guide/SKILL.md +18 -17
- package/skills/caching/SKILL.md +40 -4
- package/skills/catalog.json +1 -1
- package/skills/cloudflare/SKILL.md +131 -0
- package/skills/comparison/references/framework-comparison.md +1 -1
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +22 -0
- package/skills/hooks/handle-and-actions.md +3 -4
- package/skills/hooks/navigation.md +10 -0
- package/skills/hooks/state.md +5 -4
- package/skills/host-router/SKILL.md +18 -0
- package/skills/loader/SKILL.md +6 -4
- package/skills/middleware/SKILL.md +1 -1
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +31 -8
- package/skills/prerender/SKILL.md +645 -8
- package/skills/rango/SKILL.md +1 -0
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/testing/SKILL.md +2 -1
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/serve-shell-request.md +104 -8
- package/skills/use-cache/SKILL.md +9 -5
- package/skills/vercel/SKILL.md +2 -0
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/browser/event-controller.ts +69 -25
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +75 -35
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +9 -2
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +48 -12
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/react/Link.tsx +37 -42
- package/src/browser/react/NavigationProvider.tsx +63 -3
- package/src/browser/react/context.ts +17 -0
- package/src/browser/react/location-state.ts +5 -19
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +4 -20
- package/src/browser/react/use-link-status.ts +4 -3
- package/src/browser/react/use-navigation.ts +4 -1
- package/src/browser/react/use-params.ts +4 -1
- package/src/browser/react/use-pathname.ts +4 -1
- package/src/browser/react/use-search-params.ts +5 -3
- package/src/browser/react/use-segments.ts +36 -54
- package/src/browser/rsc-router.tsx +79 -39
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +26 -6
- package/src/browser/types.ts +11 -0
- package/src/build/generate-manifest.ts +17 -0
- package/src/build/merge-full-manifests.ts +5 -0
- package/src/build/route-trie.ts +1 -0
- package/src/cache/background-task.ts +61 -0
- package/src/cache/cache-key-utils.ts +91 -12
- package/src/cache/cache-policy.ts +11 -2
- package/src/cache/cache-runtime.ts +23 -23
- package/src/cache/cache-scope.ts +38 -36
- package/src/cache/cf/cf-cache-store.ts +16 -11
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +50 -0
- package/src/cache/index.ts +1 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +17 -0
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +69 -14
- package/src/cache/vercel/vercel-cache-store.ts +20 -6
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +7 -2
- package/src/internal-suspense-audit.ts +12 -0
- package/src/loader-store.ts +4 -9
- package/src/outlet-provider.tsx +25 -1
- package/src/prerender/cloudflare.ts +130 -0
- package/src/prerender/create-prerender-trigger.ts +780 -0
- package/src/prerender/index.ts +39 -0
- package/src/prerender/memory-prerender-store.ts +115 -0
- package/src/prerender/on-demand.ts +339 -0
- package/src/prerender/producer-guard.ts +66 -0
- package/src/prerender/shell-manifest-key.ts +12 -17
- package/src/prerender/warm-request.ts +154 -0
- package/src/prerender/warm.ts +193 -0
- package/src/prerender/writable-store.ts +278 -0
- package/src/prerender.ts +29 -0
- package/src/reverse.ts +1 -1
- package/src/route-content-wrapper.tsx +107 -13
- package/src/router/error-handling.ts +12 -12
- package/src/router/find-match.ts +1 -0
- package/src/router/handler-context.ts +2 -0
- package/src/router/intercept-resolution.ts +15 -8
- package/src/router/loader-resolution.ts +2 -10
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +230 -38
- package/src/router/pattern-matching.ts +14 -0
- package/src/router/prefetch-default.ts +4 -4
- package/src/router/prerender-match.ts +460 -352
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +33 -0
- package/src/router/router-options.ts +30 -0
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +15 -17
- package/src/router/segment-resolution/revalidation.ts +34 -24
- package/src/router/segment-resolution/streamed-handler-boundary.ts +133 -0
- package/src/router/trie-matching.ts +3 -0
- package/src/router.ts +107 -1
- package/src/rsc/handler.ts +51 -4
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +53 -11
- package/src/rsc/shell-build-manifest.ts +10 -8
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +108 -19
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +8 -0
- package/src/segment-boundary-content.ts +25 -0
- package/src/segment-loader-promise.ts +28 -38
- package/src/segment-system.tsx +117 -57
- package/src/server/build-version-table.ts +15 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +13 -0
- package/src/server/loader-registry.ts +6 -1
- package/src/server/request-context.ts +87 -1
- package/src/ssr/ssr-root.tsx +20 -13
- package/src/suspense-audit-react.tsx +98 -0
- package/src/suspense-audit.ts +1030 -0
- package/src/testing/action-form.ts +66 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +3 -0
- package/src/testing/index.ts +19 -0
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/render-route.tsx +25 -12
- package/src/testing/serve-shell-request.ts +190 -34
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +7 -0
- package/src/types/route-entry.ts +6 -0
- package/src/urls/path-helper.ts +69 -9
- package/src/use-loader.tsx +57 -30
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/shell-prerender-phase.ts +5 -5
- package/src/vite/discovery/state.ts +17 -1
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugins/virtual-entries.ts +8 -1
- package/src/vite/router-discovery.ts +14 -0
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/dist/types/browser/react/subscribe-to-nothing.d.ts +0 -7
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/browser/react/subscribe-to-nothing.ts +0 -7
- package/src/segment-content-promise.ts +0 -67
|
@@ -46,7 +46,10 @@ import { withDefer } from "../defer.js";
|
|
|
46
46
|
import { type MetricsStore } from "./context.js";
|
|
47
47
|
import { observePhase, PHASES } from "../router/instrument.js";
|
|
48
48
|
import { getFetchableLoader } from "./fetchable-loader-store.js";
|
|
49
|
-
import type {
|
|
49
|
+
import type {
|
|
50
|
+
SegmentCacheStore,
|
|
51
|
+
ShellSnapshotHandlesValue,
|
|
52
|
+
} from "../cache/types.js";
|
|
50
53
|
import type { RouterVersions } from "../router-versions.js";
|
|
51
54
|
import type { Theme, ResolvedThemeConfig } from "../theme/types.js";
|
|
52
55
|
import type { ExecutionContext, RequestScope } from "../types/request-scope.js";
|
|
@@ -289,6 +292,30 @@ export interface RequestContext<
|
|
|
289
292
|
/** @internal Cache store for segment caching (optional, used by CacheScope) */
|
|
290
293
|
_cacheStore?: SegmentCacheStore;
|
|
291
294
|
|
|
295
|
+
/**
|
|
296
|
+
* @internal Env-scoped writable prerender store (the durable overlay) plus the
|
|
297
|
+
* deployment identity for build-scoped keys, resolved per request from the
|
|
298
|
+
* `prerender` router option. Read by the serve-path overlay lookup before the
|
|
299
|
+
* bundled build manifest. Absent when no prerender store is configured.
|
|
300
|
+
*/
|
|
301
|
+
// ResolvedPrerender<any> (not <TEnv>): onRevalidate's contravariant `env` would
|
|
302
|
+
// otherwise make RequestContext invariant in TEnv, breaking existing
|
|
303
|
+
// RequestContext<{}> -> RequestContext<unknown> assignments.
|
|
304
|
+
_prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @internal Set only on the requestless on-demand producer's context. When
|
|
308
|
+
* present, the standalone request-scoped READS — `cookies()`, `headers()`,
|
|
309
|
+
* `invalidateClientCache()`, `keepClientCache()` — throw a
|
|
310
|
+
* PrerenderPersonalizationError so a personalized render is skipped rather than
|
|
311
|
+
* baked into a shared payload. Response MUTATIONS on the producer context
|
|
312
|
+
* (`ctx.setStatus`/`header`/`setCookie`) stay silent no-op stubs, matching
|
|
313
|
+
* build-time prerender (the design's "throw or skip" contract permits skip):
|
|
314
|
+
* they write to a discarded synthetic response, so there is nothing to leak.
|
|
315
|
+
* Never set on the live request path.
|
|
316
|
+
*/
|
|
317
|
+
_onDemandProducer?: true;
|
|
318
|
+
|
|
292
319
|
/**
|
|
293
320
|
* @internal Compiled `cache.searchParams` filter for default cache-key
|
|
294
321
|
* generation (undefined = "all", the byte-stable unfiltered format). Set
|
|
@@ -365,6 +392,22 @@ export interface RequestContext<
|
|
|
365
392
|
*/
|
|
366
393
|
_shellForcedMiss?: true;
|
|
367
394
|
|
|
395
|
+
/**
|
|
396
|
+
* @internal This request is a router.prerender() warm
|
|
397
|
+
* (prerender/warm-request.ts). In `replace` mode every runtime cache read
|
|
398
|
+
* misses (isWarmReplace); the layers report into the record. A capture's
|
|
399
|
+
* derived context inherits it through the prototype.
|
|
400
|
+
*/
|
|
401
|
+
_prerenderWarm?: import("../prerender/warm-request.js").PrerenderWarmRecord;
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @internal Runs a callback in the async context this request entered the
|
|
405
|
+
* handler with (captureRequestEntryContext). router.prerender() dispatches
|
|
406
|
+
* a warm through it when called from inside a request. Absent where the
|
|
407
|
+
* runtime has no AsyncLocalStorage.snapshot.
|
|
408
|
+
*/
|
|
409
|
+
_runAtRequestEntry?: <T>(fn: () => T) => T;
|
|
410
|
+
|
|
368
411
|
/**
|
|
369
412
|
* @internal The freshness window of the route cache() records this
|
|
370
413
|
* request read or wrote (cache-scope.ts noteRouteRecordWindow), as ms
|
|
@@ -459,6 +502,8 @@ export interface RequestContext<
|
|
|
459
502
|
* host) and miss the record.
|
|
460
503
|
*/
|
|
461
504
|
fixedDocKey?: string;
|
|
505
|
+
/** @internal The snapshot's `handles` record (ShellSnapshotHandlesValue). */
|
|
506
|
+
prerenderHandles?: ShellSnapshotHandlesValue;
|
|
462
507
|
/**
|
|
463
508
|
* @internal Set ONLY by matchPartialWithPprReplay on the navigation-replay
|
|
464
509
|
* serve path. Its presence arms the explicit-scope composition in
|
|
@@ -808,6 +853,18 @@ export interface RequestContext<
|
|
|
808
853
|
*/
|
|
809
854
|
_renderErrors?: unknown[];
|
|
810
855
|
|
|
856
|
+
/**
|
|
857
|
+
* @internal Rejections of streamed (loading()) handlers that were recovered
|
|
858
|
+
* into a declared errorBoundary()/notFoundBoundary() fallback, by segment id.
|
|
859
|
+
* The recovered promise resolves, so Flight reports nothing; cacheRoute
|
|
860
|
+
* (cache-scope.ts) refuses a write only when one of ITS segments is listed,
|
|
861
|
+
* the granularity a Flight error row has. The same errors are also pushed to
|
|
862
|
+
* `_renderErrors` for the document cache and PPR shell capture. A render
|
|
863
|
+
* under a derived context (shell capture, SWR re-render) owns its own map.
|
|
864
|
+
* Allocated on the first recovery.
|
|
865
|
+
*/
|
|
866
|
+
_recoveredHandlerErrors?: Map<string, unknown>;
|
|
867
|
+
|
|
811
868
|
/**
|
|
812
869
|
* @internal Report a non-fatal background error through the router's
|
|
813
870
|
* onError callback. Wired by the RSC handler / router during request
|
|
@@ -926,6 +983,8 @@ export type PublicRequestContext<
|
|
|
926
983
|
| "_transitionWhenRefs"
|
|
927
984
|
| "_pprReplayPostMatchReason"
|
|
928
985
|
| "_cacheStore"
|
|
986
|
+
| "_prerender"
|
|
987
|
+
| "_onDemandProducer"
|
|
929
988
|
| "_searchParamsFilter"
|
|
930
989
|
| "_shellCaptureRun"
|
|
931
990
|
| "_shellImplicitCache"
|
|
@@ -936,6 +995,8 @@ export type PublicRequestContext<
|
|
|
936
995
|
| "_resolvedCacheKeys"
|
|
937
996
|
| "_shellKey"
|
|
938
997
|
| "_shellForcedMiss"
|
|
998
|
+
| "_prerenderWarm"
|
|
999
|
+
| "_runAtRequestEntry"
|
|
939
1000
|
| "_routeRecordWindow"
|
|
940
1001
|
| "_shellFragmentPayload"
|
|
941
1002
|
| "_shellCaptureGuardTripped"
|
|
@@ -957,6 +1018,7 @@ export type PublicRequestContext<
|
|
|
957
1018
|
| "_inActionRevalidation"
|
|
958
1019
|
| "_reportedErrors"
|
|
959
1020
|
| "_renderErrors"
|
|
1021
|
+
| "_recoveredHandlerErrors"
|
|
960
1022
|
| "_renderBarrier"
|
|
961
1023
|
| "_resolveRenderBarrier"
|
|
962
1024
|
| "_renderBarrierSegmentOrder"
|
|
@@ -1007,6 +1069,22 @@ export const UNTRACKED_BACKGROUND_TASK: unique symbol = Symbol.for(
|
|
|
1007
1069
|
// AsyncLocalStorage instance for request context
|
|
1008
1070
|
const requestContextStorage = new AsyncLocalStorage<RequestContext<any>>();
|
|
1009
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* Capture the current async context (RequestContext._runAtRequestEntry), taken
|
|
1074
|
+
* on handler entry before any router scope, so a nested dispatch (a
|
|
1075
|
+
* router.prerender() warm called from a handler, loader or action) does not
|
|
1076
|
+
* inherit the caller's route-definition, loader and cache-scope state. Per
|
|
1077
|
+
* request: workerd refuses a snapshot outside the request that created it.
|
|
1078
|
+
* See docs/design/prerender-every-route.md.
|
|
1079
|
+
*/
|
|
1080
|
+
export function captureRequestEntryContext():
|
|
1081
|
+
| (<T>(fn: () => T) => T)
|
|
1082
|
+
| undefined {
|
|
1083
|
+
return typeof AsyncLocalStorage.snapshot === "function"
|
|
1084
|
+
? AsyncLocalStorage.snapshot()
|
|
1085
|
+
: undefined;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1010
1088
|
/**
|
|
1011
1089
|
* Run a function within a request context
|
|
1012
1090
|
* Used by the RSC handler to provide context to server actions
|
|
@@ -1118,6 +1196,12 @@ export interface CreateRequestContextOptions<TEnv> {
|
|
|
1118
1196
|
initialResponse?: Response;
|
|
1119
1197
|
/** Optional cache store for segment caching (used by CacheScope) */
|
|
1120
1198
|
cacheStore?: SegmentCacheStore;
|
|
1199
|
+
/**
|
|
1200
|
+
* Optional env-scoped writable prerender store + deployment identity (the
|
|
1201
|
+
* durable overlay), resolved per request by the RSC handler from the
|
|
1202
|
+
* `prerender` router option.
|
|
1203
|
+
*/
|
|
1204
|
+
prerender?: import("../prerender/on-demand.js").ResolvedPrerender<any>;
|
|
1121
1205
|
/**
|
|
1122
1206
|
* Compiled `cache.searchParams` filter from the resolved handler cache
|
|
1123
1207
|
* config (handler.ts). Stored as _searchParamsFilter.
|
|
@@ -1168,6 +1252,7 @@ export function createRequestContext<TEnv>(
|
|
|
1168
1252
|
variables,
|
|
1169
1253
|
initialResponse,
|
|
1170
1254
|
cacheStore,
|
|
1255
|
+
prerender,
|
|
1171
1256
|
searchParamsFilter,
|
|
1172
1257
|
explicitTaggedStores,
|
|
1173
1258
|
cacheProfiles,
|
|
@@ -1543,6 +1628,7 @@ export function createRequestContext<TEnv>(
|
|
|
1543
1628
|
|
|
1544
1629
|
_handleStore: handleStore,
|
|
1545
1630
|
_cacheStore: cacheStore,
|
|
1631
|
+
_prerender: prerender,
|
|
1546
1632
|
_versions: versions,
|
|
1547
1633
|
_searchParamsFilter: searchParamsFilter,
|
|
1548
1634
|
_explicitTaggedStores: explicitTaggedStores,
|
package/src/ssr/ssr-root.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { ThemeProvider } from "../theme/ThemeProvider.js";
|
|
9
9
|
import { NonceContext } from "../browser/react/nonce-context.js";
|
|
10
10
|
import {
|
|
11
|
+
HydrationBarrierContext,
|
|
11
12
|
LocationStateContext,
|
|
12
13
|
NavigationStoreContext,
|
|
13
14
|
} from "../browser/react/context.js";
|
|
@@ -122,9 +123,9 @@ function createSsrEventController(opts: {
|
|
|
122
123
|
flushRouteState: () => {},
|
|
123
124
|
setHandleData: () => {},
|
|
124
125
|
getHandleState: () => handleState,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
lockHydration: () => {},
|
|
127
|
+
getHydrationSnapshot: () => undefined,
|
|
128
|
+
releaseHydrationLock: () => {},
|
|
128
129
|
setRouteSegmentIds: () => {},
|
|
129
130
|
setParams: (nextParams) => {
|
|
130
131
|
params = nextParams;
|
|
@@ -286,21 +287,25 @@ export function createSsrRootComponent(opts: SsrRootOptions): React.FC {
|
|
|
286
287
|
}
|
|
287
288
|
|
|
288
289
|
// Create SSR context with request-local pathname/params/handles.
|
|
289
|
-
ssrContextValue
|
|
290
|
-
|
|
291
|
-
eventController: createSsrEventController({
|
|
290
|
+
if (!ssrContextValue) {
|
|
291
|
+
const eventController = createSsrEventController({
|
|
292
292
|
pathname,
|
|
293
293
|
search,
|
|
294
294
|
origin,
|
|
295
295
|
params: resolved.metadata?.params,
|
|
296
296
|
handleData,
|
|
297
297
|
matched: resolved.metadata?.matched,
|
|
298
|
-
})
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
298
|
+
});
|
|
299
|
+
ssrContextValue = {
|
|
300
|
+
store: null as any,
|
|
301
|
+
eventController,
|
|
302
|
+
navigate: async () => {},
|
|
303
|
+
refresh: async () => {},
|
|
304
|
+
version: resolved.metadata?.version,
|
|
305
|
+
basename: resolved.metadata?.basename,
|
|
306
|
+
origin: (eventController.getState().location as URL).origin,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
304
309
|
|
|
305
310
|
// Build content tree from segments.
|
|
306
311
|
// Order must match NavigationProvider: NavigationStoreContext > LocationStateContext > NonceContext > ThemeProvider > content
|
|
@@ -338,7 +343,9 @@ export function createSsrRootComponent(opts: SsrRootOptions): React.FC {
|
|
|
338
343
|
return (
|
|
339
344
|
<NavigationStoreContext.Provider value={ssrContextValue!}>
|
|
340
345
|
<LocationStateContext.Provider value={undefined}>
|
|
341
|
-
{
|
|
346
|
+
<HydrationBarrierContext.Provider value={0}>
|
|
347
|
+
{content}
|
|
348
|
+
</HydrationBarrierContext.Provider>
|
|
342
349
|
</LocationStateContext.Provider>
|
|
343
350
|
</NavigationStoreContext.Provider>
|
|
344
351
|
);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef, type ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
auditCommit,
|
|
4
|
+
auditFallback,
|
|
5
|
+
auditHandover,
|
|
6
|
+
auditMount,
|
|
7
|
+
auditRead,
|
|
8
|
+
auditReveal,
|
|
9
|
+
auditUnmount,
|
|
10
|
+
createBoundaryAudit,
|
|
11
|
+
type BoundaryAudit,
|
|
12
|
+
} from "./suspense-audit.js";
|
|
13
|
+
|
|
14
|
+
// Hooks of the suspense audit (docs/internal/suspense-contract.md), called by
|
|
15
|
+
// dev-only components: React Compiler skips a component with a gated hook.
|
|
16
|
+
|
|
17
|
+
function useRecord(boundary: string, segmentId: string): BoundaryAudit {
|
|
18
|
+
const ref = useRef<BoundaryAudit | null>(null);
|
|
19
|
+
// One position can hold another segment's boundary: its Suspense is keyed.
|
|
20
|
+
if (ref.current === null || ref.current.boundary !== boundary) {
|
|
21
|
+
ref.current = createBoundaryAudit(boundary, segmentId);
|
|
22
|
+
}
|
|
23
|
+
return ref.current;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Passive, not layout: React disconnects the layout effects of content a
|
|
27
|
+
// Suspense boundary hides, and that is not an unmount.
|
|
28
|
+
function useMount(rec: BoundaryAudit): void {
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
auditMount(rec);
|
|
31
|
+
return () => auditUnmount(rec);
|
|
32
|
+
}, [rec]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* One boundary: what each render hands it, what each commit carries, and its
|
|
37
|
+
* mount. Called above the Suspense, which commits while the content waits.
|
|
38
|
+
* `streams` and `nodes` are what else its content waits for (I3 only).
|
|
39
|
+
*/
|
|
40
|
+
export function useBoundaryAudit(
|
|
41
|
+
boundary: string,
|
|
42
|
+
segmentId: string,
|
|
43
|
+
value: unknown,
|
|
44
|
+
streams?: Record<string, unknown>,
|
|
45
|
+
nodes?: unknown,
|
|
46
|
+
): BoundaryAudit {
|
|
47
|
+
const rec = useRecord(boundary, segmentId);
|
|
48
|
+
auditHandover(rec, value);
|
|
49
|
+
useLayoutEffect(() => {
|
|
50
|
+
auditCommit(rec, value, streams, nodes);
|
|
51
|
+
}, [rec, value, streams, nodes]);
|
|
52
|
+
useMount(rec);
|
|
53
|
+
return rec;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The boundary's content is on screen. */
|
|
57
|
+
export function useRevealAudit(rec: BoundaryAudit): void {
|
|
58
|
+
useLayoutEffect(() => {
|
|
59
|
+
auditReveal(rec);
|
|
60
|
+
}, [rec]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* One `useLoader` read of a per-loader stream (I1, I2 at the read site). A
|
|
65
|
+
* read that suspends while mounting keeps no record: only a reader on screen
|
|
66
|
+
* is audited.
|
|
67
|
+
*/
|
|
68
|
+
export function useReadAudit(loaderId: string, stream: unknown): void {
|
|
69
|
+
const rec = useRecord(`read:${loaderId}`, loaderId);
|
|
70
|
+
auditHandover(rec, stream);
|
|
71
|
+
useLayoutEffect(() => {
|
|
72
|
+
auditRead(rec, stream);
|
|
73
|
+
}, [rec, stream]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Wraps a boundary's fallback: mounted means the fallback is on screen. */
|
|
77
|
+
export function AuditedFallback({
|
|
78
|
+
audit,
|
|
79
|
+
children,
|
|
80
|
+
}: {
|
|
81
|
+
audit: BoundaryAudit;
|
|
82
|
+
children: ReactNode;
|
|
83
|
+
}): ReactNode {
|
|
84
|
+
useLayoutEffect(() => auditFallback(audit), [audit]);
|
|
85
|
+
return children;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Wraps a segment's outlet children: the segment's mount (I4). */
|
|
89
|
+
export function AuditedOutlet({
|
|
90
|
+
segmentId,
|
|
91
|
+
children,
|
|
92
|
+
}: {
|
|
93
|
+
segmentId: string;
|
|
94
|
+
children: ReactNode;
|
|
95
|
+
}): ReactNode {
|
|
96
|
+
useMount(useRecord(`outlet:${segmentId}`, segmentId));
|
|
97
|
+
return children;
|
|
98
|
+
}
|