@rangojs/router 0.34.0 → 0.35.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 -1
- package/dist/bin/{chunk-4HHFQSDC.js → chunk-3CQXDX3A.js} +5 -5
- package/dist/bin/{client-urls-projection-4Q5EQDAL.js → client-urls-projection-2GBDM5YK.js} +1 -1
- package/dist/bin/rango.js +1 -1
- package/dist/bin/{runtime-discovery-2ZTYRZ3V.js → runtime-discovery-PA3V3IFQ.js} +2 -2
- package/dist/bin/{temp-rsc-server-EUNKRFJD.js → temp-rsc-server-WDXEHDY7.js} +2 -2
- package/dist/types/cache/shell-snapshot.d.ts +1 -1
- package/dist/types/cache/types.d.ts +1 -1
- package/dist/types/client-urls/server-projection.d.ts +1 -1
- package/dist/types/client-urls/types.d.ts +6 -6
- package/dist/types/decode-loader-results.d.ts +1 -1
- package/dist/types/errors.d.ts +3 -3
- package/dist/types/handles/meta.d.ts +2 -2
- package/dist/types/loader-store.d.ts +20 -8
- package/dist/types/outlet-context.d.ts +1 -1
- package/dist/types/route-definition/helpers-types.d.ts +5 -5
- package/dist/types/router/loader-resolution.d.ts +1 -1
- package/dist/types/router/match-context.d.ts +12 -0
- package/dist/types/router/navigation-snapshot.d.ts +17 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +7 -7
- package/dist/types/router/types.d.ts +1 -1
- package/dist/types/rsc/shell-capture-constants.d.ts +2 -2
- package/dist/types/server/context.d.ts +3 -3
- package/dist/types/server/request-context.d.ts +1 -1
- package/dist/types/ssr/index.d.ts +1 -1
- package/dist/types/ssr/ssr-root.d.ts +1 -1
- package/dist/types/ssr-suspension-warning.d.ts +1 -1
- package/dist/types/types/loader-types.d.ts +19 -19
- package/dist/types/types/segments.d.ts +2 -2
- package/dist/types/urls/path-helper-types.d.ts +4 -4
- package/dist/types/urls/pattern-types.d.ts +1 -1
- package/dist/types/vite/plugin-types.d.ts +1 -1
- package/dist/vite/index.js +7 -7
- package/package.json +1 -1
- package/skills/app-structure/e-commerce.md +1 -1
- package/skills/breadcrumbs/SKILL.md +5 -5
- package/skills/cache-guide/SKILL.md +4 -4
- package/skills/caching/SKILL.md +1 -1
- package/skills/catalog.json +2 -2
- package/skills/client-urls/SKILL.md +20 -20
- package/skills/comparison/references/framework-comparison.md +6 -6
- package/skills/defer-hydration/SKILL.md +2 -2
- package/skills/handler-use/SKILL.md +5 -5
- package/skills/hooks/data.md +5 -2
- package/skills/hooks/handle-and-actions.md +9 -9
- package/skills/loader/SKILL.md +52 -47
- package/skills/middleware/SKILL.md +2 -2
- package/skills/migrate-nextjs/SKILL.md +10 -10
- package/skills/migrate-react-router/SKILL.md +1 -1
- package/skills/migrate-react-router/component-migration.md +2 -2
- package/skills/migrate-react-router/data-and-actions.md +2 -2
- package/skills/migrate-react-router/route-mapping.md +2 -2
- package/skills/parallel/SKILL.md +2 -2
- package/skills/ppr/SKILL.md +91 -92
- package/skills/prerender/SKILL.md +5 -5
- package/skills/rango/SKILL.md +7 -7
- package/skills/route/SKILL.md +1 -1
- package/skills/router-setup/SKILL.md +2 -2
- package/skills/scripts/SKILL.md +3 -3
- package/skills/shell-manifest/SKILL.md +3 -3
- package/skills/testing/serve-shell-request.md +1 -1
- package/skills/theme/SKILL.md +2 -2
- package/skills/typesafety/env-and-bindings.md +2 -2
- package/skills/use-cache/SKILL.md +1 -1
- package/skills/ux-architecture/SKILL.md +7 -7
- package/src/cache/shell-snapshot.ts +1 -1
- package/src/cache/types.ts +1 -1
- package/src/client-urls/client-urls.ts +16 -9
- package/src/client-urls/server-projection.ts +4 -4
- package/src/client-urls/types.ts +6 -6
- package/src/decode-loader-results.ts +1 -1
- package/src/errors.ts +9 -9
- package/src/handles/meta.ts +2 -2
- package/src/loader-store.ts +29 -13
- package/src/outlet-context.ts +1 -1
- package/src/route-definition/dsl-helpers.ts +4 -8
- package/src/route-definition/helpers-types.ts +5 -5
- package/src/router/loader-resolution.ts +4 -4
- package/src/router/match-api.ts +2 -0
- package/src/router/match-context.ts +22 -1
- package/src/router/match-middleware/cache-lookup.ts +17 -8
- package/src/router/match-middleware/intercept-resolution.ts +3 -3
- package/src/router/navigation-snapshot.ts +39 -8
- package/src/router/segment-resolution/loader-cache.ts +8 -8
- package/src/router/segment-resolution/prefetch-deferral.ts +1 -1
- package/src/router/segment-resolution/revalidation.ts +3 -3
- package/src/router/types.ts +1 -1
- package/src/rsc/shell-capture-constants.ts +3 -3
- package/src/rsc/shell-capture.ts +12 -12
- package/src/segment-system.tsx +3 -3
- package/src/server/context.ts +5 -5
- package/src/server/cookie-store.ts +1 -1
- package/src/server/request-context.ts +1 -1
- package/src/ssr/index.tsx +6 -6
- package/src/ssr/ssr-root.tsx +1 -1
- package/src/ssr-suspension-warning.ts +4 -4
- package/src/types/loader-types.ts +19 -19
- package/src/types/segments.ts +2 -2
- package/src/urls/path-helper-types.ts +4 -4
- package/src/urls/pattern-types.ts +1 -1
- package/src/use-loader.tsx +5 -3
- package/src/vite/discovery/shell-prerender-phase.ts +1 -1
- package/src/vite/plugin-types.ts +1 -1
package/src/ssr/index.tsx
CHANGED
|
@@ -232,7 +232,7 @@ export interface SSRDependencies<TEnv = unknown> {
|
|
|
232
232
|
*
|
|
233
233
|
* When UNSET, createSSRHandler and createShellCaptureHandler auto-raise to
|
|
234
234
|
* Number.MAX_SAFE_INTEGER for document renders and shell captures whose
|
|
235
|
-
* matched chain has a `loader(Def, { ssr:
|
|
235
|
+
* matched chain has a `loader(Def, { ssr: "await" })` entry (payload segments
|
|
236
236
|
* carry `awaitBeforeFlush`): the loader was awaited before first flush
|
|
237
237
|
* precisely so its content ships in-place, and React 19.2's Fizz would
|
|
238
238
|
* otherwise move any completed boundary over ~500 bytes to an end-of-stream
|
|
@@ -441,7 +441,7 @@ function trackDocumentClientLoads<T>(decode: () => T): {
|
|
|
441
441
|
const SSR_FALSE_FIRST_FLUSH_TURNS = 3;
|
|
442
442
|
|
|
443
443
|
/**
|
|
444
|
-
* True when the matched chain has a `loader(Def, { ssr:
|
|
444
|
+
* True when the matched chain has a `loader(Def, { ssr: "await" })` entry: its
|
|
445
445
|
* payload segments carry `awaitBeforeFlush` (resolveOwnerLoaders).
|
|
446
446
|
*/
|
|
447
447
|
function hasAwaitBeforeFlush(payload: {
|
|
@@ -453,7 +453,7 @@ function hasAwaitBeforeFlush(payload: {
|
|
|
453
453
|
/**
|
|
454
454
|
* The progressiveChunkSize renderHTML and captureShellHTML pass to Fizz (see
|
|
455
455
|
* SSRDependencies.progressiveChunkSize): the explicit option, else the
|
|
456
|
-
* ssr:
|
|
456
|
+
* ssr: "await" auto-raise.
|
|
457
457
|
*/
|
|
458
458
|
function documentChunkSize(
|
|
459
459
|
explicit: number | undefined,
|
|
@@ -463,7 +463,7 @@ function documentChunkSize(
|
|
|
463
463
|
}
|
|
464
464
|
|
|
465
465
|
/**
|
|
466
|
-
* ssr:
|
|
466
|
+
* ssr: "await" documents only: before the first flush, give Fizz the turns a
|
|
467
467
|
* task waiting on an already-settling thenable needs, so a boundary that
|
|
468
468
|
* waits on nothing else completes in place (#1138).
|
|
469
469
|
*
|
|
@@ -953,7 +953,7 @@ export function createSSRHandler<TEnv = unknown>(deps: SSRDependencies<TEnv>) {
|
|
|
953
953
|
|
|
954
954
|
const bootstrap = await resolveBootstrap(deps);
|
|
955
955
|
|
|
956
|
-
// ssr:
|
|
956
|
+
// ssr: "await" auto-raise (see SSRDependencies.progressiveChunkSize).
|
|
957
957
|
// Awaiting the payload here is latency-neutral: fizz cannot emit even
|
|
958
958
|
// <html> until this same promise settles. A rejection lands in the
|
|
959
959
|
// catch below — the same reportRenderError path a shell error takes.
|
|
@@ -1149,7 +1149,7 @@ export function createShellCaptureHandler<TEnv = unknown>(
|
|
|
1149
1149
|
origin: opts.origin,
|
|
1150
1150
|
});
|
|
1151
1151
|
|
|
1152
|
-
// ssr:
|
|
1152
|
+
// ssr: "await" auto-raise (SSRDependencies.progressiveChunkSize); resume()
|
|
1153
1153
|
// inherits it from the postponed state. A rejected or late payload
|
|
1154
1154
|
// skips it and fails or degrades below as before.
|
|
1155
1155
|
const awaitsBeforeFlush = await Promise.race([
|
package/src/ssr/ssr-root.tsx
CHANGED
|
@@ -150,7 +150,7 @@ function createSsrEventController(opts: {
|
|
|
150
150
|
* Deserialize the Flight stream branch into the payload SsrRoot renders,
|
|
151
151
|
* fragment expansion included. Factored out of SsrRoot so createSSRHandler and
|
|
152
152
|
* createShellCaptureHandler can create the promise BEFORE fizz starts and read
|
|
153
|
-
* metadata that must influence the fizz call itself (the ssr:
|
|
153
|
+
* metadata that must influence the fizz call itself (the ssr: "await"
|
|
154
154
|
* progressiveChunkSize auto-raise) — awaiting it there is latency-neutral
|
|
155
155
|
* because fizz cannot emit even <html> until this same promise settles.
|
|
156
156
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Dev-only diagnostic for the { ssr:
|
|
2
|
+
* Dev-only diagnostic for the { ssr: "await" } SSR-completeness opt-in.
|
|
3
3
|
*
|
|
4
4
|
* A document render that awaits flagged loaders before first flush is usually
|
|
5
5
|
* expected to produce an SSR-complete boundary — but the await is scoped per
|
|
@@ -37,7 +37,7 @@ export function warnAwaitedSsrSuspension(
|
|
|
37
37
|
|
|
38
38
|
if (awaitedLoaderIds.includes(loaderId)) {
|
|
39
39
|
console.error(
|
|
40
|
-
`[rango] Loader "${loaderId}" is flagged { ssr:
|
|
40
|
+
`[rango] Loader "${loaderId}" is flagged { ssr: "await" } and was awaited ` +
|
|
41
41
|
`before first flush, but its useLoader read observed a still-pending ` +
|
|
42
42
|
`promise during SSR. If its Suspense fallback appears in the SSR'd HTML, ` +
|
|
43
43
|
`please report it to @rangojs/router with a reproduction.`,
|
|
@@ -46,12 +46,12 @@ export function warnAwaitedSsrSuspension(
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
console.warn(
|
|
49
|
-
`[rango] The document render awaited { ssr:
|
|
49
|
+
`[rango] The document render awaited { ssr: "await" } loader(s) ` +
|
|
50
50
|
`${JSON.stringify(awaitedLoaderIds)} before first flush, but ` +
|
|
51
51
|
`useLoader("${loaderId}") still suspended during SSR. "${loaderId}" is not ` +
|
|
52
52
|
`flagged, so the Suspense boundary above that read streams as its fallback ` +
|
|
53
53
|
`and the content under it stays hidden until JS runs. If the boundary must ` +
|
|
54
|
-
`be SSR-complete, flag "${loaderId}" with { ssr:
|
|
54
|
+
`be SSR-complete, flag "${loaderId}" with { ssr: "await" } too, or move its ` +
|
|
55
55
|
`read behind its own boundary. If it streams deliberately, ignore this.`,
|
|
56
56
|
);
|
|
57
57
|
}
|
|
@@ -75,7 +75,7 @@ export type LoaderContext<
|
|
|
75
75
|
* later ones stream to the client and apply post-hydration (document lane)
|
|
76
76
|
* or progressively (navigation/action lanes). To guarantee a loader's
|
|
77
77
|
* handles are in the SSR'd document, register it as
|
|
78
|
-
* `loader(Def, { ssr:
|
|
78
|
+
* `loader(Def, { ssr: "await" })` so the document render awaits it
|
|
79
79
|
* (see {@link LoaderOptions}).
|
|
80
80
|
*
|
|
81
81
|
* @example
|
|
@@ -175,29 +175,29 @@ export type LoaderFn<
|
|
|
175
175
|
/**
|
|
176
176
|
* SSR delivery for a DSL-registered loader: `loader(Def, { ssr })`.
|
|
177
177
|
*
|
|
178
|
-
* Default (omitted / `
|
|
179
|
-
* its `ctx.use(Handle)` pushes, and any `notFound()`/`redirect()` it
|
|
180
|
-
* may land AFTER the document Response is constructed, so none of
|
|
181
|
-
* guaranteed to be in the SSR'd HTML.
|
|
178
|
+
* Default (omitted / `"stream"`): the loader streams on every render. Its
|
|
179
|
+
* data, its `ctx.use(Handle)` pushes, and any `notFound()`/`redirect()` it
|
|
180
|
+
* throws may land AFTER the document Response is constructed, so none of
|
|
181
|
+
* them are guaranteed to be in the SSR'd HTML.
|
|
182
182
|
*
|
|
183
|
-
* `ssr:
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
* it
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
* BAKE lane: the loader executes at shell capture and its settled return is
|
|
183
|
+
* `ssr: "await"` makes the server renders that produce HTML await this
|
|
184
|
+
* loader: on a DOCUMENT request the loader is awaited before first flush, so
|
|
185
|
+
* no fallback paints for it (`useLoader` still suspends, but on an
|
|
186
|
+
* already-settled promise); a ppr shell capture, at runtime or at build time
|
|
187
|
+
* for a Prerender + ppr route, awaits it too. Client navigations keep
|
|
188
|
+
* streaming it. This is the SSR-completeness opt-in. Choose it when the
|
|
189
|
+
* loader feeds something that must exist in the document: `<head>` meta via
|
|
190
|
+
* a handle, or a real 404 status (an awaited `notFound()` deterministically
|
|
191
|
+
* precedes Response construction, where the streamed default only wins
|
|
192
|
+
* that race opportunistically). Under ppr it is also the BAKE lane: the loader executes at shell capture and its settled return is
|
|
193
193
|
* shell material (nested promises stay live holes), and so are its handle
|
|
194
194
|
* pushes, a pushed promise or `.defer()` included: the capture awaits it and
|
|
195
195
|
* every HIT serves the value it settled to (#1182). A pushed promise that
|
|
196
196
|
* rejects, or misses `ppr.captureTimeout`, keeps the route on MISS. A value
|
|
197
|
-
* that must stay per request belongs to a loader without `ssr:
|
|
197
|
+
* that must stay per request belongs to a loader without `ssr: "await"` — see
|
|
198
198
|
* the ppr docs.
|
|
199
199
|
*
|
|
200
|
-
* Scoped per LOADER, not per segment: an `ssr:
|
|
200
|
+
* Scoped per LOADER, not per segment: an `ssr: "await"` loader alongside a
|
|
201
201
|
* deliberately streaming sibling awaits only itself, and the sibling keeps
|
|
202
202
|
* streaming behind its `loading()`/Suspense boundary. Watch the scoping when
|
|
203
203
|
* the boundary must be SSR-complete: ONE unflagged read under it still
|
|
@@ -206,7 +206,7 @@ export type LoaderFn<
|
|
|
206
206
|
* site naming the unflagged loader (ssr-suspension-warning.ts).
|
|
207
207
|
*/
|
|
208
208
|
export type LoaderOptions = {
|
|
209
|
-
ssr?:
|
|
209
|
+
ssr?: "stream" | "await";
|
|
210
210
|
/**
|
|
211
211
|
* `prefetch: false` keeps this loader out of every `<Link>` prefetch: a
|
|
212
212
|
* prefetch (a partial request with `X-Rango-Prefetch`) does not execute
|
|
@@ -236,7 +236,7 @@ export type LoaderOptions = {
|
|
|
236
236
|
* Limits: a handler that awaits the loader with `ctx.use()` makes it run in
|
|
237
237
|
* the prefetch anyway; the loader cannot call `ctx.rendered()` (it throws
|
|
238
238
|
* on every request); on a `ppr` route the flag is ignored for an
|
|
239
|
-
* `ssr:
|
|
239
|
+
* `ssr: "await"` loader (the bake lane), with a dev warning. In the fill
|
|
240
240
|
* request only deferred work and middleware run, so values a held handler
|
|
241
241
|
* would have set with `ctx.set()` are not visible.
|
|
242
242
|
*/
|
package/src/types/segments.ts
CHANGED
|
@@ -164,7 +164,7 @@ export interface ResolvedSegment {
|
|
|
164
164
|
loaderData?: any; // For loaders: the resolved data from loader execution
|
|
165
165
|
/**
|
|
166
166
|
* True when this loader was awaited before first flush
|
|
167
|
-
* (loader(Def, { ssr:
|
|
167
|
+
* (loader(Def, { ssr: "await" })). Stamped by resolveOwnerLoaders on
|
|
168
168
|
* document AND shell-capture renders — capture bakes flagged loaders and
|
|
169
169
|
* awaits the same lane. Feeds segment-system's settled-value delivery and
|
|
170
170
|
* the dev SSR suspension warning (ssr-suspension-warning.ts).
|
|
@@ -185,7 +185,7 @@ export interface ResolvedSegment {
|
|
|
185
185
|
loaderIds?: string[]; // IDs ($$id) of loaders for this segment
|
|
186
186
|
/**
|
|
187
187
|
* Per-loader UNDECODED results for a layout/route stream map.
|
|
188
|
-
* Flagged (ssr:
|
|
188
|
+
* Flagged (ssr: "await") entries are settled values; unflagged siblings
|
|
189
189
|
* stay promises. Parallel slots do not use this channel — they pin
|
|
190
190
|
* loading() / live-lane holes via use(loaderDataPromise).
|
|
191
191
|
*/
|
|
@@ -356,10 +356,10 @@ export type PathHelpers<TEnv> = {
|
|
|
356
356
|
/**
|
|
357
357
|
* Attach a data loader to the current route/layout.
|
|
358
358
|
*
|
|
359
|
-
* Pass `{ ssr:
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
359
|
+
* Pass `{ ssr: "await" }` to await this loader before first flush on
|
|
360
|
+
* DOCUMENT requests (see {@link LoaderOptions}): the opt-in for loaders
|
|
361
|
+
* whose data, handle pushes, or thrown notFound()/redirect() must be in the
|
|
362
|
+
* SSR'd HTML.
|
|
363
363
|
* Per-loader: a streaming sibling keeps streaming. Under a `ppr` route the
|
|
364
364
|
* flag BAKES: the loader executes at shell capture and its settled return
|
|
365
365
|
* freezes into the shell (nested promises stay live holes) — the pre-flush
|
|
@@ -67,7 +67,7 @@ export interface PartialPrerenderProps {
|
|
|
67
67
|
* Upper bound (serialized UTF-8 bytes) on the loader pins in the capture
|
|
68
68
|
* data snapshot: the bake-lane loader records. The doc record (the handler
|
|
69
69
|
* layer every HIT replays) is exempt. A document HIT is served only from an
|
|
70
|
-
* entry that holds a pin for every `ssr:
|
|
70
|
+
* entry that holds a pin for every `ssr: "await"` loader its HTML baked, so
|
|
71
71
|
* over the cap no document shell is stored: documents render in full
|
|
72
72
|
* (MISS), and client navigations still replay the handler layer and run
|
|
73
73
|
* those loaders fresh. Reported once per key. Defaults to 8 MiB. The whole
|
package/src/use-loader.tsx
CHANGED
|
@@ -256,12 +256,13 @@ function useLoaderInternal<T>(
|
|
|
256
256
|
[groupKey],
|
|
257
257
|
);
|
|
258
258
|
const hasGroups = groupList.length > 0;
|
|
259
|
+
// A grouped read without a key refreshes a bucket no other reader names.
|
|
260
|
+
const usesPrivateBucket = hasGroups && key === undefined;
|
|
259
261
|
const privateBucketIdRef = useRef<string | null>(null);
|
|
260
|
-
if (
|
|
262
|
+
if (usesPrivateBucket && privateBucketIdRef.current === null) {
|
|
261
263
|
privateBucketIdRef.current = `__rg${privateGroupBucketSeq++}`;
|
|
262
264
|
}
|
|
263
|
-
const effectiveKey =
|
|
264
|
-
key ?? (hasGroups ? privateBucketIdRef.current! : undefined);
|
|
265
|
+
const effectiveKey = usesPrivateBucket ? privateBucketIdRef.current! : key;
|
|
265
266
|
const bucketKey =
|
|
266
267
|
effectiveKey === undefined ? loaderId : `${loaderId}::${effectiveKey}`;
|
|
267
268
|
|
|
@@ -352,6 +353,7 @@ function useLoaderInternal<T>(
|
|
|
352
353
|
{
|
|
353
354
|
loaderId,
|
|
354
355
|
ephemeral: !hasContextData,
|
|
356
|
+
owned: usesPrivateBucket,
|
|
355
357
|
group: hasGroups ? groupList : undefined,
|
|
356
358
|
refetch: hasGroups ? groupRefetch : undefined,
|
|
357
359
|
onStreamPending: hasContextData
|
|
@@ -188,7 +188,7 @@ export async function runShellPrerenderPhase(
|
|
|
188
188
|
injectRSCPayload: htmlStream.injectRSCPayload,
|
|
189
189
|
headScripts: "preinit",
|
|
190
190
|
// Build-captured shells honor the explicit outlining budget, or the
|
|
191
|
-
// ssr:
|
|
191
|
+
// ssr: "await" auto-raise without one (createShellCaptureHandler): the
|
|
192
192
|
// capture value rides the postponed state into every runtime resume().
|
|
193
193
|
...(s.opts?.progressiveChunkSize !== undefined && {
|
|
194
194
|
progressiveChunkSize: s.opts.progressiveChunkSize,
|
package/src/vite/plugin-types.ts
CHANGED
|
@@ -190,7 +190,7 @@ interface RangoBaseOptions {
|
|
|
190
190
|
* which is why React outlines by default.
|
|
191
191
|
*
|
|
192
192
|
* When UNSET, document renders and PPR shell captures whose matched chain
|
|
193
|
-
* has a `loader(Def, { ssr:
|
|
193
|
+
* has a `loader(Def, { ssr: "await" })` entry auto-raise to MAX_SAFE_INTEGER —
|
|
194
194
|
* the loader was awaited before first flush precisely so its content ships
|
|
195
195
|
* in-place, and outlining the boundary it feeds would defeat that. A shell
|
|
196
196
|
* HIT inherits the captured value, so it matches the live render. Setting
|