@rangojs/router 0.0.0-experimental.77 → 0.0.0-experimental.78
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/vite/index.js +1 -1
- package/package.json +1 -1
- package/skills/middleware/SKILL.md +32 -3
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +764 -0
- package/skills/rango/SKILL.md +24 -22
- package/src/browser/navigation-bridge.ts +14 -1
- package/src/browser/partial-update.ts +9 -2
- package/src/browser/segment-reconciler.ts +10 -14
- package/src/client.tsx +82 -174
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +11 -61
- package/src/types/segments.ts +0 -1
package/src/segment-system.tsx
CHANGED
|
@@ -2,11 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { createElement, type ReactNode, type ComponentType } from "react";
|
|
3
3
|
import { OutletProvider } from "./client.js";
|
|
4
4
|
import { MountContextProvider } from "./browser/react/mount-context.js";
|
|
5
|
-
import type {
|
|
6
|
-
ResolvedSegment,
|
|
7
|
-
LoaderDataResult,
|
|
8
|
-
RootLayoutProps,
|
|
9
|
-
} from "./types.js";
|
|
5
|
+
import type { ResolvedSegment, RootLayoutProps } from "./types.js";
|
|
10
6
|
import { isLoaderDataResult } from "./types.js";
|
|
11
7
|
import { invariant } from "./errors.js";
|
|
12
8
|
import {
|
|
@@ -14,6 +10,8 @@ import {
|
|
|
14
10
|
LoaderBoundary,
|
|
15
11
|
} from "./route-content-wrapper.js";
|
|
16
12
|
import { RootErrorBoundary } from "./root-error-boundary.js";
|
|
13
|
+
import { getMemoizedContentPromise } from "./segment-content-promise.js";
|
|
14
|
+
import { getMemoizedLoaderPromise } from "./segment-loader-promise.js";
|
|
17
15
|
|
|
18
16
|
// ViewTransition is only available in React experimental.
|
|
19
17
|
// Access via namespace import to avoid compile-time errors on stable React.
|
|
@@ -61,20 +59,6 @@ function restoreParallelLoaderMarkers(
|
|
|
61
59
|
return nextSegments ?? segments;
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
function hasSameReferences(a: unknown[] | undefined, b: unknown[]): boolean {
|
|
65
|
-
if (!a || a.length !== b.length) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
for (let i = 0; i < a.length; i++) {
|
|
70
|
-
if (a[i] !== b[i]) {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
62
|
/**
|
|
79
63
|
* Resolve loader data from raw results, unwrapping LoaderDataResult wrappers
|
|
80
64
|
*/
|
|
@@ -278,10 +262,7 @@ export async function renderSegments(
|
|
|
278
262
|
loading !== null && loading !== undefined && loading !== false
|
|
279
263
|
? createElement(RouteContentWrapper, {
|
|
280
264
|
key: `suspense-loading-${id}`,
|
|
281
|
-
content:
|
|
282
|
-
resolvedComponent instanceof Promise
|
|
283
|
-
? resolvedComponent
|
|
284
|
-
: Promise.resolve(resolvedComponent),
|
|
265
|
+
content: getMemoizedContentPromise(resolvedComponent),
|
|
285
266
|
fallback: loading,
|
|
286
267
|
segmentId: id,
|
|
287
268
|
})
|
|
@@ -305,16 +286,7 @@ export async function renderSegments(
|
|
|
305
286
|
|
|
306
287
|
// Prepare loader data if there are loaders
|
|
307
288
|
const loaderIds = loaderEntries.map((loader) => loader.loaderId!);
|
|
308
|
-
const loaderDataPromise =
|
|
309
|
-
loaderEntries.length > 0
|
|
310
|
-
? Promise.all(
|
|
311
|
-
loaderEntries.map((loader) =>
|
|
312
|
-
loader.loaderData instanceof Promise
|
|
313
|
-
? loader.loaderData
|
|
314
|
-
: Promise.resolve(loader.loaderData),
|
|
315
|
-
),
|
|
316
|
-
)
|
|
317
|
-
: Promise.resolve([]);
|
|
289
|
+
const loaderDataPromise = getMemoizedLoaderPromise(loaderEntries);
|
|
318
290
|
|
|
319
291
|
// Use LoaderBoundary when loading is defined to maintain consistent tree structure
|
|
320
292
|
// This ensures cached segments (which may not have loader segments) have the same
|
|
@@ -396,34 +368,12 @@ export async function renderSegments(
|
|
|
396
368
|
continue;
|
|
397
369
|
}
|
|
398
370
|
|
|
399
|
-
|
|
400
|
-
const
|
|
401
|
-
p.
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
hasSameReferences(p.parallelLoaderSources, parallelLoaderSources);
|
|
406
|
-
|
|
407
|
-
const parallelLoaderDataPromise = shouldReuseParallelPromise
|
|
408
|
-
? p.loaderDataPromise
|
|
409
|
-
: forceAwait || isAction
|
|
410
|
-
? await Promise.all(
|
|
411
|
-
ownedLoaders.map((l) =>
|
|
412
|
-
l.loaderData instanceof Promise
|
|
413
|
-
? l.loaderData
|
|
414
|
-
: Promise.resolve(l.loaderData),
|
|
415
|
-
),
|
|
416
|
-
)
|
|
417
|
-
: Promise.all(
|
|
418
|
-
ownedLoaders.map((l) =>
|
|
419
|
-
l.loaderData instanceof Promise
|
|
420
|
-
? l.loaderData
|
|
421
|
-
: Promise.resolve(l.loaderData),
|
|
422
|
-
),
|
|
423
|
-
);
|
|
424
|
-
|
|
425
|
-
p.loaderDataPromise = parallelLoaderDataPromise;
|
|
426
|
-
p.parallelLoaderSources = parallelLoaderSources;
|
|
371
|
+
p.loaderIds = ownedLoaders.map((l) => l.loaderId!);
|
|
372
|
+
const aggregated = getMemoizedLoaderPromise(ownedLoaders);
|
|
373
|
+
p.loaderDataPromise =
|
|
374
|
+
(forceAwait || isAction) && aggregated instanceof Promise
|
|
375
|
+
? await aggregated
|
|
376
|
+
: aggregated;
|
|
427
377
|
}
|
|
428
378
|
}
|
|
429
379
|
|
package/src/types/segments.ts
CHANGED
|
@@ -56,7 +56,6 @@ export interface ResolvedSegment {
|
|
|
56
56
|
// Intercept loader fields (for streaming loader data in parallel segments)
|
|
57
57
|
loaderDataPromise?: Promise<any[]> | any[]; // Loader data promise or resolved array
|
|
58
58
|
loaderIds?: string[]; // IDs ($$id) of loaders for this segment
|
|
59
|
-
parallelLoaderSources?: any[]; // Internal: preserves stable aggregate promise across renders
|
|
60
59
|
// Error-specific fields
|
|
61
60
|
error?: ErrorInfo; // For error segments: the error information
|
|
62
61
|
// NotFound-specific fields
|