@rangojs/router 0.0.0-experimental.10 → 0.0.0-experimental.100
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/AGENTS.md +9 -0
- package/README.md +1037 -4
- package/dist/bin/rango.js +1619 -157
- package/dist/vite/index.js +5762 -2301
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +71 -63
- package/skills/breadcrumbs/SKILL.md +252 -0
- package/skills/cache-guide/SKILL.md +294 -0
- package/skills/caching/SKILL.md +93 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +6 -4
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +367 -71
- package/skills/host-router/SKILL.md +218 -0
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +176 -8
- package/skills/layout/SKILL.md +124 -3
- package/skills/links/SKILL.md +304 -25
- package/skills/loader/SKILL.md +474 -47
- package/skills/middleware/SKILL.md +207 -37
- package/skills/migrate-nextjs/SKILL.md +562 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +15 -11
- package/skills/parallel/SKILL.md +272 -1
- package/skills/prerender/SKILL.md +467 -65
- package/skills/rango/SKILL.md +89 -21
- package/skills/response-routes/SKILL.md +152 -91
- package/skills/route/SKILL.md +305 -14
- package/skills/router-setup/SKILL.md +210 -32
- package/skills/server-actions/SKILL.md +739 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +333 -86
- package/skills/use-cache/SKILL.md +324 -0
- package/skills/view-transitions/SKILL.md +212 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +312 -15
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/app-shell.ts +52 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/event-controller.ts +136 -68
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +374 -561
- package/src/browser/navigation-client.ts +228 -70
- package/src/browser/navigation-store.ts +97 -55
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +376 -315
- package/src/browser/prefetch/cache.ts +314 -0
- package/src/browser/prefetch/fetch.ts +282 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +191 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +152 -0
- package/src/browser/react/Link.tsx +255 -71
- package/src/browser/react/NavigationProvider.tsx +152 -24
- package/src/browser/react/context.ts +11 -0
- package/src/browser/react/filter-segment-order.ts +55 -0
- package/src/browser/react/index.ts +15 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +30 -120
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +44 -65
- package/src/browser/react/use-params.ts +78 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-reverse.ts +99 -0
- package/src/browser/react/use-router.ts +83 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +85 -99
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +246 -64
- package/src/browser/scroll-restoration.ts +127 -52
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +510 -603
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +158 -48
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +84 -23
- package/src/build/generate-route-types.ts +39 -828
- package/src/build/index.ts +4 -5
- package/src/build/route-trie.ts +85 -32
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +418 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +618 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +342 -0
- package/src/cache/cache-scope.ts +167 -307
- package/src/cache/cf/cf-cache-store.ts +573 -21
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +6 -1
- package/src/client.tsx +118 -302
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +156 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +77 -7
- package/src/handle.ts +55 -10
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +65 -45
- package/src/index.rsc.ts +138 -21
- package/src/index.ts +206 -51
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +25 -143
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +4 -2
- package/src/prerender/store.ts +159 -13
- package/src/prerender.ts +397 -29
- package/src/response-utils.ts +28 -0
- package/src/reverse.ts +231 -121
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +1134 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +483 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +101 -0
- package/src/route-definition/resolve-handler-use.ts +155 -0
- package/src/route-definition.ts +1 -1431
- package/src/route-map-builder.ts +162 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +66 -9
- package/src/router/content-negotiation.ts +215 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +418 -86
- package/src/router/intercept-resolution.ts +35 -20
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +359 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +98 -32
- package/src/router/match-api.ts +196 -261
- package/src/router/match-context.ts +4 -2
- package/src/router/match-handlers.ts +441 -0
- package/src/router/match-middleware/background-revalidation.ts +108 -93
- package/src/router/match-middleware/cache-lookup.ts +415 -86
- package/src/router/match-middleware/cache-store.ts +91 -29
- package/src/router/match-middleware/intercept-resolution.ts +48 -21
- package/src/router/match-middleware/segment-resolution.ts +73 -9
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +154 -35
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +209 -0
- package/src/router/middleware.ts +373 -371
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +292 -52
- package/src/router/prerender-match.ts +502 -0
- package/src/router/preview-match.ts +98 -0
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +152 -39
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +41 -21
- package/src/router/router-interfaces.ts +484 -0
- package/src/router/router-options.ts +618 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +756 -0
- package/src/router/segment-resolution/helpers.ts +268 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1407 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -1315
- package/src/router/segment-wrappers.ts +291 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +111 -39
- package/src/router/types.ts +17 -9
- package/src/router/url-params.ts +49 -0
- package/src/router.ts +642 -2011
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +864 -1114
- package/src/rsc/helpers.ts +181 -19
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +229 -0
- package/src/rsc/manifest-init.ts +90 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +395 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +360 -0
- package/src/rsc/rsc-rendering.ts +256 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +360 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +52 -11
- package/src/search-params.ts +230 -0
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +187 -38
- package/src/server/context.ts +333 -59
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +113 -15
- package/src/server/loader-registry.ts +24 -64
- package/src/server/request-context.ts +603 -109
- package/src/server.ts +35 -155
- package/src/ssr/index.tsx +107 -30
- package/src/static-handler.ts +126 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +764 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +209 -0
- package/src/types/request-scope.ts +126 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +120 -0
- package/src/types/segments.ts +167 -0
- package/src/types.ts +1 -1757
- package/src/urls/include-helper.ts +207 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +372 -0
- package/src/urls/path-helper.ts +364 -0
- package/src/urls/pattern-types.ts +107 -0
- package/src/urls/response-types.ts +108 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -1282
- package/src/use-loader.tsx +161 -81
- package/src/vite/debug.ts +184 -0
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +376 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +486 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +73 -0
- package/src/vite/discovery/state.ts +117 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +15 -2063
- package/src/vite/plugin-types.ts +103 -0
- package/src/vite/plugins/cjs-to-esm.ts +98 -0
- package/src/vite/plugins/client-ref-dedup.ts +131 -0
- package/src/vite/plugins/client-ref-hashing.ts +117 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +214 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +107 -64
- package/src/vite/plugins/expose-id-utils.ts +299 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +127 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +816 -0
- package/src/vite/plugins/performance-tracks.ts +96 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -0
- package/src/vite/plugins/use-cache-transform.ts +336 -0
- package/src/vite/plugins/version-injector.ts +109 -0
- package/src/vite/plugins/version-plugin.ts +266 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +497 -0
- package/src/vite/router-discovery.ts +1423 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/utils/package-resolution.ts +161 -0
- package/src/vite/utils/prerender-utils.ts +222 -0
- package/src/vite/utils/shared-utils.ts +170 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/router.gen.ts +0 -6
- package/src/urls.gen.ts +0 -8
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- package/src/vite/expose-prerender-handler-id.ts +0 -429
- package/src/vite/package-resolution.ts +0 -125
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
package/src/segment-system.tsx
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
1
2
|
import { createElement, type ReactNode, type ComponentType } from "react";
|
|
2
3
|
import { OutletProvider } from "./client.js";
|
|
3
4
|
import { MountContextProvider } from "./browser/react/mount-context.js";
|
|
4
|
-
import type {
|
|
5
|
-
ResolvedSegment,
|
|
6
|
-
LoaderDataResult,
|
|
7
|
-
RootLayoutProps,
|
|
8
|
-
} from "./types.js";
|
|
5
|
+
import type { ResolvedSegment, RootLayoutProps } from "./types.js";
|
|
9
6
|
import { isLoaderDataResult } from "./types.js";
|
|
10
7
|
import { invariant } from "./errors.js";
|
|
11
8
|
import {
|
|
@@ -13,6 +10,54 @@ import {
|
|
|
13
10
|
LoaderBoundary,
|
|
14
11
|
} from "./route-content-wrapper.js";
|
|
15
12
|
import { RootErrorBoundary } from "./root-error-boundary.js";
|
|
13
|
+
import { getMemoizedContentPromise } from "./segment-content-promise.js";
|
|
14
|
+
import { getMemoizedLoaderPromise } from "./segment-loader-promise.js";
|
|
15
|
+
|
|
16
|
+
// ViewTransition is only available in React experimental.
|
|
17
|
+
// Access via namespace import to avoid compile-time errors on stable React.
|
|
18
|
+
const ReactViewTransition: any =
|
|
19
|
+
"ViewTransition" in React ? (React as any).ViewTransition : null;
|
|
20
|
+
|
|
21
|
+
function restoreParallelLoaderMarkers(
|
|
22
|
+
segments: ResolvedSegment[],
|
|
23
|
+
): ResolvedSegment[] {
|
|
24
|
+
const parallelLoadingByNamespace = new Map<string, ReactNode>();
|
|
25
|
+
let nextSegments: ResolvedSegment[] | null = null;
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < segments.length; i++) {
|
|
28
|
+
const segment = segments[i];
|
|
29
|
+
|
|
30
|
+
if (segment.type === "parallel") {
|
|
31
|
+
if (
|
|
32
|
+
segment.namespace &&
|
|
33
|
+
segment.loading !== undefined &&
|
|
34
|
+
segment.loading !== null &&
|
|
35
|
+
segment.loading !== false
|
|
36
|
+
) {
|
|
37
|
+
parallelLoadingByNamespace.set(segment.namespace, segment.loading);
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (segment.type !== "loader" || segment.parallelLoading !== undefined) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const parallelLoading = segment.namespace
|
|
47
|
+
? parallelLoadingByNamespace.get(segment.namespace)
|
|
48
|
+
: undefined;
|
|
49
|
+
if (parallelLoading === undefined) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!nextSegments) {
|
|
54
|
+
nextSegments = segments.slice();
|
|
55
|
+
}
|
|
56
|
+
nextSegments[i] = { ...segment, parallelLoading };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return nextSegments ?? segments;
|
|
60
|
+
}
|
|
16
61
|
|
|
17
62
|
/**
|
|
18
63
|
* Resolve loader data from raw results, unwrapping LoaderDataResult wrappers
|
|
@@ -86,6 +131,47 @@ export interface RenderSegmentsOptions {
|
|
|
86
131
|
rootLayout?: ComponentType<RootLayoutProps>;
|
|
87
132
|
}
|
|
88
133
|
|
|
134
|
+
function createViewTransitionBoundary(
|
|
135
|
+
transition: NonNullable<ResolvedSegment["transition"]>,
|
|
136
|
+
children: ReactNode,
|
|
137
|
+
): ReactNode {
|
|
138
|
+
return createElement(ReactViewTransition, {
|
|
139
|
+
...transition,
|
|
140
|
+
children,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function wrapDefaultOutletContent(
|
|
145
|
+
content: ReactNode,
|
|
146
|
+
transition: NonNullable<ResolvedSegment["transition"]>,
|
|
147
|
+
): ReactNode {
|
|
148
|
+
if (!React.isValidElement(content)) {
|
|
149
|
+
return createViewTransitionBoundary(transition, content);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const props = content.props as any;
|
|
153
|
+
|
|
154
|
+
if (content.type === MountContextProvider) {
|
|
155
|
+
return React.cloneElement(content, {
|
|
156
|
+
children: wrapDefaultOutletContent(props.children, transition),
|
|
157
|
+
} as any);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (content.type === OutletProvider && props.segment?.type === "layout") {
|
|
161
|
+
return React.cloneElement(content, {
|
|
162
|
+
content: wrapDefaultOutletContent(props.content, transition),
|
|
163
|
+
} as any);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (content.type === LoaderBoundary && props.segment?.type === "layout") {
|
|
167
|
+
return React.cloneElement(content, {
|
|
168
|
+
outletContent: wrapDefaultOutletContent(props.outletContent, transition),
|
|
169
|
+
} as any);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return createViewTransitionBoundary(transition, content);
|
|
173
|
+
}
|
|
174
|
+
|
|
89
175
|
/**
|
|
90
176
|
* Render segments into a React tree with proper layout nesting
|
|
91
177
|
*
|
|
@@ -137,6 +223,10 @@ export async function renderSegments(
|
|
|
137
223
|
} = options || {};
|
|
138
224
|
|
|
139
225
|
const temporalLazyRefs: Promise<any>[] = [];
|
|
226
|
+
const normalizedSegments = restoreParallelLoaderMarkers(segments);
|
|
227
|
+
const normalizedInterceptSegments = interceptSegments
|
|
228
|
+
? restoreParallelLoaderMarkers(interceptSegments)
|
|
229
|
+
: undefined;
|
|
140
230
|
|
|
141
231
|
/**
|
|
142
232
|
* Registers promises from lazy/async components for awaiting.
|
|
@@ -161,7 +251,7 @@ export async function renderSegments(
|
|
|
161
251
|
);
|
|
162
252
|
}
|
|
163
253
|
// Separate segments by type, passing intercept segments for explicit injection
|
|
164
|
-
const tree = segmentTreeWalk(
|
|
254
|
+
const tree = segmentTreeWalk(normalizedSegments, normalizedInterceptSegments);
|
|
165
255
|
// Render content segments as siblings
|
|
166
256
|
let content: ReactNode = null;
|
|
167
257
|
for (const node of tree) {
|
|
@@ -210,33 +300,44 @@ export async function renderSegments(
|
|
|
210
300
|
}
|
|
211
301
|
|
|
212
302
|
let nodeContent: ReactNode =
|
|
213
|
-
loading !== null && loading
|
|
303
|
+
loading !== null && loading !== undefined && loading !== false
|
|
214
304
|
? createElement(RouteContentWrapper, {
|
|
215
305
|
key: `suspense-loading-${id}`,
|
|
216
|
-
content:
|
|
217
|
-
resolvedComponent instanceof Promise
|
|
218
|
-
? resolvedComponent
|
|
219
|
-
: Promise.resolve(resolvedComponent),
|
|
306
|
+
content: getMemoizedContentPromise(resolvedComponent),
|
|
220
307
|
fallback: loading,
|
|
221
308
|
segmentId: id,
|
|
222
309
|
})
|
|
223
310
|
: registerLazyRef(resolvedComponent);
|
|
224
|
-
|
|
225
|
-
|
|
311
|
+
|
|
312
|
+
// Wrap with <ViewTransition> if transition config exists (React experimental only).
|
|
313
|
+
// An empty config ({}) creates a bare <ViewTransition> boundary that participates
|
|
314
|
+
// in transitions without adding custom animation classes. Named element-level
|
|
315
|
+
// <ViewTransition> components inside (with name/share props) morph independently
|
|
316
|
+
// from the parent's default cross-fade.
|
|
317
|
+
//
|
|
318
|
+
// For layouts, wrap the outlet content (what `<Outlet />` renders) rather
|
|
319
|
+
// than the layout component itself. Parallel slots like `<ParallelOutlet
|
|
320
|
+
// name="@modal" />` read from a separate context channel and end up as
|
|
321
|
+
// siblings of the VT in the rendered tree, so modal mounts don't trigger a
|
|
322
|
+
// subtree update on the layout-level VT — which would otherwise make
|
|
323
|
+
// React's commit walker fire `document.startViewTransition` and apply
|
|
324
|
+
// view-transition-names to the underlying main subtree (cover/title/etc.).
|
|
325
|
+
let outletContent: ReactNode =
|
|
226
326
|
node.segment.type === "layout" ? content : null;
|
|
227
327
|
|
|
328
|
+
const transition = node.segment.transition;
|
|
329
|
+
|
|
330
|
+
if (ReactViewTransition && transition) {
|
|
331
|
+
if (node.segment.type === "layout") {
|
|
332
|
+
outletContent = wrapDefaultOutletContent(outletContent, transition);
|
|
333
|
+
} else {
|
|
334
|
+
nodeContent = createViewTransitionBoundary(transition, nodeContent);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
228
338
|
// Prepare loader data if there are loaders
|
|
229
339
|
const loaderIds = loaderEntries.map((loader) => loader.loaderId!);
|
|
230
|
-
const loaderDataPromise =
|
|
231
|
-
loaderEntries.length > 0
|
|
232
|
-
? Promise.all(
|
|
233
|
-
loaderEntries.map((loader) =>
|
|
234
|
-
loader.loaderData instanceof Promise
|
|
235
|
-
? loader.loaderData
|
|
236
|
-
: Promise.resolve(loader.loaderData),
|
|
237
|
-
),
|
|
238
|
-
)
|
|
239
|
-
: Promise.resolve([]);
|
|
340
|
+
const loaderDataPromise = getMemoizedLoaderPromise(loaderEntries);
|
|
240
341
|
|
|
241
342
|
// Use LoaderBoundary when loading is defined to maintain consistent tree structure
|
|
242
343
|
// This ensures cached segments (which may not have loader segments) have the same
|
|
@@ -265,13 +366,68 @@ export async function renderSegments(
|
|
|
265
366
|
children: nodeContent,
|
|
266
367
|
});
|
|
267
368
|
} else {
|
|
268
|
-
// Has loaders but no loading skeleton
|
|
269
|
-
|
|
369
|
+
// Has loaders but no loading skeleton.
|
|
370
|
+
// Split: parallel-owned loaders stream (their parallel has loading()),
|
|
371
|
+
// layout-owned loaders are awaited (they gate the layout content).
|
|
372
|
+
const layoutLoaders = loaderEntries.filter((l) => !l.parallelLoading);
|
|
373
|
+
const parallelOwnedLoaders = loaderEntries.filter(
|
|
374
|
+
(l) => !!l.parallelLoading,
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
// Await only layout-owned loaders
|
|
378
|
+
const layoutLoaderIds = layoutLoaders.map((l) => l.loaderId!);
|
|
379
|
+
const layoutLoaderDataPromise =
|
|
380
|
+
layoutLoaders.length > 0
|
|
381
|
+
? Promise.all(
|
|
382
|
+
layoutLoaders.map((l) =>
|
|
383
|
+
l.loaderData instanceof Promise
|
|
384
|
+
? l.loaderData
|
|
385
|
+
: Promise.resolve(l.loaderData),
|
|
386
|
+
),
|
|
387
|
+
)
|
|
388
|
+
: Promise.resolve([]);
|
|
389
|
+
const resolvedData = await layoutLoaderDataPromise;
|
|
270
390
|
const { loaderData, errorFallback } = resolveLoaderData(
|
|
271
391
|
resolvedData,
|
|
272
|
-
|
|
392
|
+
layoutLoaderIds,
|
|
273
393
|
);
|
|
274
394
|
|
|
395
|
+
// Parallel-owned loaders: attach to their owning parallel segment
|
|
396
|
+
// as loaderDataPromise so ParallelOutlet wraps in LoaderBoundary
|
|
397
|
+
if (parallelOwnedLoaders.length > 0) {
|
|
398
|
+
const loadersByParallelNamespace = new Map<string, ResolvedSegment[]>();
|
|
399
|
+
|
|
400
|
+
for (const loader of parallelOwnedLoaders) {
|
|
401
|
+
if (!loader.namespace) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const existing = loadersByParallelNamespace.get(loader.namespace);
|
|
405
|
+
if (existing) {
|
|
406
|
+
existing.push(loader);
|
|
407
|
+
} else {
|
|
408
|
+
loadersByParallelNamespace.set(loader.namespace, [loader]);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
for (const p of node.parallel) {
|
|
413
|
+
if (!p.loading || !p.namespace) {
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const ownedLoaders = loadersByParallelNamespace.get(p.namespace);
|
|
418
|
+
if (!ownedLoaders || ownedLoaders.length === 0) {
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
p.loaderIds = ownedLoaders.map((l) => l.loaderId!);
|
|
423
|
+
const aggregated = getMemoizedLoaderPromise(ownedLoaders);
|
|
424
|
+
p.loaderDataPromise =
|
|
425
|
+
(forceAwait || isAction) && aggregated instanceof Promise
|
|
426
|
+
? await aggregated
|
|
427
|
+
: aggregated;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
275
431
|
content = createElement(OutletProvider, {
|
|
276
432
|
key,
|
|
277
433
|
content: outletContent,
|
|
@@ -407,20 +563,13 @@ function* segmentTreeWalk(
|
|
|
407
563
|
}
|
|
408
564
|
}
|
|
409
565
|
|
|
410
|
-
//
|
|
411
|
-
//
|
|
412
|
-
//
|
|
413
|
-
//
|
|
414
|
-
nonParallels.sort((a, b) => {
|
|
415
|
-
if (a.id.length !== b.id.length) {
|
|
416
|
-
return a.id.length - b.id.length;
|
|
417
|
-
}
|
|
418
|
-
return a.id.localeCompare(b.id);
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
// Iterate bottom-to-top using reverse() to process leaf segments first
|
|
566
|
+
// Segments arrive in root-to-leaf order from the server (resolveSegment
|
|
567
|
+
// and resolveSegmentWithRevalidation push segments in this order).
|
|
568
|
+
// All consumers (reconcileSegments, cache) preserve this order.
|
|
569
|
+
// No sorting needed — iterate bottom-to-top to process leaf segments first.
|
|
422
570
|
// This processes route/leaf layouts first, then parent layouts
|
|
423
571
|
// Note: We reverse the array to iterate from end to start (bottom-to-top)
|
|
572
|
+
|
|
424
573
|
for (let i = nonParallels.length - 1; i >= 0; i--) {
|
|
425
574
|
const segment = nonParallels[i];
|
|
426
575
|
|