@rangojs/router 0.20.0 → 0.22.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/dist/bin/rango.js +39 -15
- package/dist/types/browser/event-controller.d.ts +49 -0
- package/dist/types/browser/history-state.d.ts +16 -4
- package/dist/types/browser/navigation-store.d.ts +9 -0
- package/dist/types/browser/navigation-transaction.d.ts +7 -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/rango-state.d.ts +3 -1
- package/dist/types/browser/react/NavigationProvider.d.ts +14 -1
- package/dist/types/browser/react/context.d.ts +25 -0
- package/dist/types/browser/react/location-state-shared.d.ts +84 -10
- package/dist/types/browser/react/location-state.d.ts +7 -2
- 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 +5 -6
- package/dist/types/cache/cf/cf-cache-store.d.ts +34 -7
- package/dist/types/cache/cf/cf-cache-types.d.ts +12 -4
- package/dist/types/cache/document-cache.d.ts +8 -5
- package/dist/types/cache/handle-snapshot.d.ts +59 -50
- package/dist/types/cache/index.d.ts +3 -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 +29 -4
- 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 +84 -24
- package/dist/types/cache/vercel/vercel-cache-store.d.ts +35 -17
- package/dist/types/client-urls/navigation.d.ts +7 -1
- package/dist/types/client-urls/optimistic-location.d.ts +10 -4
- package/dist/types/errors.d.ts +6 -0
- package/dist/types/handles/deferred-resolution.d.ts +18 -1
- 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/build-shell-capture.d.ts +8 -6
- 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 +15 -1
- package/dist/types/router/navigation-snapshot.d.ts +8 -1
- 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 +32 -1
- package/dist/types/router/router-options.d.ts +39 -5
- package/dist/types/router/segment-resolution/fresh.d.ts +7 -0
- package/dist/types/router/segment-resolution/loader-cache.d.ts +23 -10
- 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/router-versions.d.ts +39 -0
- package/dist/types/rsc/handler-context.d.ts +5 -0
- package/dist/types/rsc/shell-build-manifest.d.ts +9 -6
- 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 +12 -6
- 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 +53 -0
- package/dist/types/server/context.d.ts +12 -4
- package/dist/types/server/handle-store.d.ts +89 -46
- package/dist/types/server/request-context.d.ts +84 -9
- 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/build-versions.d.ts +32 -0
- package/dist/types/testing/dom.entry.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +3 -1
- package/dist/types/testing/index.d.ts +6 -0
- package/dist/types/testing/internal/seed-vars.d.ts +7 -2
- package/dist/types/testing/internal/server-modules.d.ts +8 -0
- package/dist/types/testing/location-state-key.d.ts +5 -1
- package/dist/types/testing/render-route.d.ts +77 -6
- package/dist/types/testing/serve-shell-request.d.ts +55 -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/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/thenable-status.d.ts +6 -0
- package/dist/types/types/handler-context.d.ts +15 -5
- 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/build-versions.d.ts +393 -0
- package/dist/types/vite/discovery/installed-packages.d.ts +26 -0
- package/dist/types/vite/discovery/router-versions-phase.d.ts +52 -0
- package/dist/types/vite/discovery/shell-prerender-phase.d.ts +7 -17
- package/dist/types/vite/discovery/state.d.ts +25 -0
- package/dist/types/vite/encryption-key.d.ts +18 -0
- package/dist/types/vite/inject-client-debug.d.ts +6 -25
- package/dist/types/vite/plugin-types.d.ts +27 -0
- package/dist/types/vite/plugins/{version-injector.d.ts → entry-bootstrap-injector.d.ts} +4 -6
- package/dist/types/vite/plugins/expose-ids/export-analysis.d.ts +1 -0
- package/dist/types/vite/plugins/expose-ids/router-transform.d.ts +14 -0
- package/dist/types/vite/plugins/stable-rsc-output.d.ts +51 -0
- package/dist/types/vite/plugins/version-plugin.d.ts +9 -11
- package/dist/types/vite/plugins/virtual-entries.d.ts +18 -1
- package/dist/types/vite/router-discovery.d.ts +6 -0
- package/dist/types/vite/utils/bundle-analysis.d.ts +6 -2
- package/dist/types/vite/utils/client-chunks.d.ts +2 -0
- package/dist/types/vite/utils/compare-strings.d.ts +7 -0
- package/dist/types/vite/utils/package-resolution.d.ts +8 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +2 -0
- package/dist/vite/index.js +1707 -931
- package/package.json +12 -3
- package/skills/cache-guide/SKILL.md +102 -37
- package/skills/caching/SKILL.md +56 -9
- package/skills/catalog.json +1 -1
- package/skills/client-urls/SKILL.md +16 -0
- package/skills/cloudflare/SKILL.md +133 -1
- package/skills/comparison/references/framework-comparison.md +17 -13
- package/skills/deployment-caching/SKILL.md +33 -12
- package/skills/document-cache/SKILL.md +16 -14
- package/skills/hooks/SKILL.md +25 -0
- package/skills/hooks/handle-and-actions.md +5 -0
- package/skills/hooks/navigation.md +38 -0
- package/skills/hooks/state.md +213 -11
- package/skills/hooks/urls.md +40 -1
- package/skills/host-router/SKILL.md +31 -0
- package/skills/intercept/SKILL.md +6 -0
- package/skills/loader/SKILL.md +25 -5
- package/skills/middleware/SKILL.md +2 -0
- package/skills/migrate-nextjs/SKILL.md +82 -9
- package/skills/ppr/SKILL.md +150 -48
- package/skills/prerender/SKILL.md +651 -10
- package/skills/rango/SKILL.md +9 -7
- package/skills/response-routes/SKILL.md +5 -5
- package/skills/route/SKILL.md +29 -0
- package/skills/router-setup/SKILL.md +15 -1
- package/skills/testing/SKILL.md +32 -27
- package/skills/testing/cache-prerender.md +18 -17
- package/skills/testing/client-components.md +193 -8
- package/skills/testing/handles.md +2 -0
- package/skills/testing/loader.md +1 -1
- package/skills/testing/middleware.md +1 -1
- package/skills/testing/render-handler.md +18 -18
- package/skills/testing/serve-shell-request.md +167 -22
- package/skills/testing/server-actions.md +17 -17
- package/skills/testing/server-tree.md +1 -1
- package/skills/typesafety/generated-files-and-cli.md +1 -1
- package/skills/use-cache/SKILL.md +25 -10
- package/skills/vercel/SKILL.md +5 -3
- package/skills/view-transitions/SKILL.md +9 -4
- package/src/bin/rango.ts +1 -1
- package/src/browser/event-controller.ts +119 -2
- package/src/browser/history-state.ts +39 -17
- package/src/browser/link-interceptor.ts +2 -2
- package/src/browser/navigation-bridge.ts +104 -41
- package/src/browser/navigation-store.ts +26 -0
- package/src/browser/navigation-transaction.ts +24 -12
- package/src/browser/network-error-handler.ts +2 -0
- package/src/browser/partial-update.ts +58 -14
- package/src/browser/prefetch/default-strategy.ts +22 -42
- package/src/browser/rango-state.ts +3 -1
- package/src/browser/react/Link.tsx +37 -43
- package/src/browser/react/NavigationProvider.tsx +85 -1
- package/src/browser/react/context.ts +30 -0
- package/src/browser/react/location-state-shared.ts +200 -34
- package/src/browser/react/location-state.ts +28 -77
- package/src/browser/react/use-action.ts +4 -1
- package/src/browser/react/use-handle.ts +3 -0
- 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 +93 -31
- package/src/browser/segment-reconciler.ts +3 -3
- package/src/browser/server-action-bridge.ts +43 -7
- 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 +48 -36
- package/src/cache/cf/cf-cache-store.ts +91 -66
- package/src/cache/cf/cf-cache-types.ts +12 -4
- package/src/cache/document-cache.ts +35 -14
- package/src/cache/handle-snapshot.ts +118 -86
- package/src/cache/index.ts +5 -0
- package/src/cache/invalidation-order.ts +53 -0
- package/src/cache/memory-segment-store.ts +52 -1
- package/src/cache/shell-snapshot.ts +52 -5
- package/src/cache/store-scope.ts +36 -0
- package/src/cache/tag-invalidation.ts +7 -5
- package/src/cache/types.ts +90 -24
- package/src/cache/vercel/vercel-cache-store.ts +68 -26
- package/src/client-urls/client-root.tsx +1 -0
- package/src/client-urls/navigation.ts +10 -0
- package/src/client-urls/optimistic-location.ts +10 -4
- package/src/client.tsx +40 -3
- package/src/errors.ts +13 -6
- package/src/handles/deferred-resolution.ts +36 -0
- 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/build-shell-capture.ts +11 -9
- 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/manifest.ts +2 -0
- package/src/router/match-middleware/background-revalidation.ts +2 -0
- package/src/router/match-middleware/cache-lookup.ts +239 -54
- package/src/router/navigation-snapshot.ts +25 -6
- 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/request-classification.ts +15 -12
- package/src/router/route-trie-builder.ts +9 -0
- package/src/router/router-context.ts +1 -0
- package/src/router/router-interfaces.ts +35 -1
- package/src/router/router-options.ts +45 -5
- package/src/router/segment-resolution/fresh.ts +20 -19
- package/src/router/segment-resolution/loader-cache.ts +110 -77
- 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-versions.ts +60 -0
- package/src/router.ts +107 -1
- package/src/rsc/full-payload.ts +6 -2
- package/src/rsc/handler-context.ts +5 -0
- package/src/rsc/handler.ts +64 -7
- package/src/rsc/progressive-enhancement.ts +5 -1
- package/src/rsc/response-cache-serve.ts +10 -4
- package/src/rsc/rsc-rendering.ts +65 -12
- package/src/rsc/shell-build-manifest.ts +17 -12
- package/src/rsc/shell-capture-constants.ts +39 -7
- package/src/rsc/shell-capture.ts +144 -45
- package/src/rsc/shell-serve.ts +12 -6
- package/src/rsc/ssr-module-loader.ts +26 -0
- package/src/rsc/types.ts +12 -6
- 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 +130 -0
- package/src/server/context.ts +40 -17
- package/src/server/cookie-store.ts +5 -0
- package/src/server/handle-store.ts +357 -127
- package/src/server/request-context.ts +149 -12
- package/src/ssr/ssr-root.tsx +32 -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/build-versions.ts +64 -0
- package/src/testing/dispatch.ts +6 -0
- package/src/testing/dom.entry.ts +1 -0
- package/src/testing/flight-runtime.d.ts +27 -0
- package/src/testing/flight.entry.ts +4 -0
- package/src/testing/index.ts +22 -0
- package/src/testing/internal/context.ts +2 -1
- package/src/testing/internal/seed-vars.ts +14 -2
- package/src/testing/internal/server-modules.ts +32 -0
- package/src/testing/location-state-key.ts +18 -8
- package/src/testing/render-handler.ts +2 -1
- package/src/testing/render-route.tsx +293 -46
- package/src/testing/serve-shell-request.ts +262 -37
- package/src/testing/shell-status.ts +17 -6
- package/src/testing/vitest-stubs/plugin-rsc.ts +37 -11
- package/src/testing/vitest-stubs/version.ts +4 -1
- package/src/thenable-status.ts +10 -0
- package/src/types/handler-context.ts +15 -5
- 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/build-versions.ts +1281 -0
- package/src/vite/discovery/bundle-postprocess.ts +4 -0
- package/src/vite/discovery/discover-routers.ts +15 -0
- package/src/vite/discovery/installed-packages.ts +159 -0
- package/src/vite/discovery/prerender-collection.ts +38 -1
- package/src/vite/discovery/router-versions-phase.ts +336 -0
- package/src/vite/discovery/shell-prerender-phase.ts +33 -43
- package/src/vite/discovery/state.ts +36 -1
- package/src/vite/discovery/virtual-module-codegen.ts +7 -2
- package/src/vite/encryption-key.ts +101 -9
- package/src/vite/inject-client-debug.ts +42 -20
- package/src/vite/plugin-types.ts +28 -0
- package/src/vite/plugins/{version-injector.ts → entry-bootstrap-injector.ts} +7 -22
- package/src/vite/plugins/expose-ids/export-analysis.ts +1 -1
- package/src/vite/plugins/expose-ids/router-transform.ts +36 -15
- package/src/vite/plugins/expose-internal-ids.ts +12 -3
- package/src/vite/plugins/stable-rsc-output.ts +147 -0
- package/src/vite/plugins/version-plugin.ts +19 -24
- package/src/vite/plugins/version.d.ts +17 -2
- package/src/vite/plugins/virtual-entries.ts +39 -6
- package/src/vite/rango.ts +28 -3
- package/src/vite/router-discovery.ts +96 -13
- package/src/vite/utils/bundle-analysis.ts +39 -7
- package/src/vite/utils/client-chunks.ts +5 -1
- package/src/vite/utils/compare-strings.ts +9 -0
- package/src/vite/utils/package-resolution.ts +9 -0
- package/src/vite/utils/prerender-utils.ts +4 -1
- package/src/vite/utils/shared-utils.ts +1 -1
- package/dist/types/segment-content-promise.d.ts +0 -13
- package/src/segment-content-promise.ts +0 -67
|
@@ -4,7 +4,10 @@ import type {
|
|
|
4
4
|
ResolvedSegment,
|
|
5
5
|
StreamingToken,
|
|
6
6
|
} from "./types.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
generateHistoryKey,
|
|
9
|
+
liveHandleDataForCache,
|
|
10
|
+
} from "./navigation-store.js";
|
|
8
11
|
import {
|
|
9
12
|
handleNavigationStart,
|
|
10
13
|
ensureHistoryKey,
|
|
@@ -13,7 +16,6 @@ import type { EventController, NavigationHandle } from "./event-controller.js";
|
|
|
13
16
|
import { debugLog } from "./logging.js";
|
|
14
17
|
import {
|
|
15
18
|
buildHistoryState,
|
|
16
|
-
hasLocationState,
|
|
17
19
|
mergeLocationState,
|
|
18
20
|
pushHistoryWithIdx,
|
|
19
21
|
} from "./history-state.js";
|
|
@@ -59,6 +61,11 @@ interface CommitOptions {
|
|
|
59
61
|
* partial updater reuses it instead of deciding again.
|
|
60
62
|
*/
|
|
61
63
|
transitionGatedOff?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* No payload follows this commit: every segment is kept and the tree on
|
|
66
|
+
* screen stays (EventController.commitLocationState).
|
|
67
|
+
*/
|
|
68
|
+
treeless?: boolean;
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
/**
|
|
@@ -81,6 +88,8 @@ interface BoundCommitOverrides {
|
|
|
81
88
|
serverState?: Record<string, unknown>;
|
|
82
89
|
/** The committed route's name (payload metadata), remembered per history entry. */
|
|
83
90
|
routeName?: string;
|
|
91
|
+
/** No payload follows this commit (CommitOptions.treeless). */
|
|
92
|
+
treeless?: boolean;
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
/**
|
|
@@ -174,7 +183,11 @@ export function createNavigationTransaction(
|
|
|
174
183
|
|
|
175
184
|
store.setHistoryKey(historyKey);
|
|
176
185
|
|
|
177
|
-
|
|
186
|
+
// storeOnly re-caches the page on screen (an action refetch), which can
|
|
187
|
+
// commit with no tree and so never release the hydration window.
|
|
188
|
+
const currentHandleData = storeOnly
|
|
189
|
+
? liveHandleDataForCache(eventController, store, historyKey)
|
|
190
|
+
: eventController.getHandleState().data;
|
|
178
191
|
store.cacheSegmentsForHistory(historyKey, segments, currentHandleData);
|
|
179
192
|
|
|
180
193
|
if (storeOnly) {
|
|
@@ -187,10 +200,13 @@ export function createNavigationTransaction(
|
|
|
187
200
|
}
|
|
188
201
|
|
|
189
202
|
if (traversal) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
203
|
+
// The entry as history restored it, plus what the server adds.
|
|
204
|
+
const entryState: unknown =
|
|
205
|
+
serverState && Object.keys(serverState).length > 0
|
|
206
|
+
? mergeLocationState(serverState)
|
|
207
|
+
: window.history.state;
|
|
193
208
|
store.rememberDisplayedEntry(opts.routeName);
|
|
209
|
+
eventController.commitLocationState(entryState, opts.treeless);
|
|
194
210
|
handle.complete(parsedUrl);
|
|
195
211
|
debugLog("[Browser] Traversal committed, historyKey:", historyKey);
|
|
196
212
|
return { scroll };
|
|
@@ -202,15 +218,10 @@ export function createNavigationTransaction(
|
|
|
202
218
|
serverState,
|
|
203
219
|
);
|
|
204
220
|
|
|
205
|
-
const oldState = window.history.state;
|
|
206
|
-
|
|
207
221
|
pushHistoryWithIdx(historyState, url, replace ?? false);
|
|
208
222
|
ensureHistoryKey();
|
|
209
223
|
store.rememberDisplayedEntry(opts.routeName);
|
|
210
|
-
|
|
211
|
-
if (hasLocationState(oldState) || hasLocationState(historyState)) {
|
|
212
|
-
window.dispatchEvent(new Event("__rsc_locationstate"));
|
|
213
|
-
}
|
|
224
|
+
eventController.commitLocationState(historyState, opts.treeless);
|
|
214
225
|
|
|
215
226
|
handle.complete(parsedUrl);
|
|
216
227
|
|
|
@@ -269,6 +280,7 @@ export function createNavigationTransaction(
|
|
|
269
280
|
cacheOnly,
|
|
270
281
|
serverState,
|
|
271
282
|
routeName: overrides?.routeName ?? opts.routeName,
|
|
283
|
+
treeless: overrides?.treeless,
|
|
272
284
|
});
|
|
273
285
|
},
|
|
274
286
|
};
|
|
@@ -2,6 +2,7 @@ import { NetworkError, isNetworkError } from "../errors.js";
|
|
|
2
2
|
import { RenderErrorThrower } from "../render-error-thrower.js";
|
|
3
3
|
import type { UpdateSubscriber } from "./types.js";
|
|
4
4
|
import { createElement, startTransition } from "react";
|
|
5
|
+
import { auditTreeCause } from "../suspense-audit.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Convert an unknown error to a NetworkError, or return null if not network-related.
|
|
@@ -33,6 +34,7 @@ function emitErrorToBoundary(
|
|
|
33
34
|
error: unknown,
|
|
34
35
|
pathname: string,
|
|
35
36
|
): void {
|
|
37
|
+
if (process.env.NODE_ENV !== "production") auditTreeCause("error");
|
|
36
38
|
startTransition(() => {
|
|
37
39
|
onUpdate({
|
|
38
40
|
root: createElement(RenderErrorThrower, { error }),
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
} from "./validate-redirect-origin.js";
|
|
32
32
|
import type { NavigationUpdate } from "./types.js";
|
|
33
33
|
import { OPTIMISTIC_COMMIT_TRANSITION_TYPE } from "./optimistic-commit.js";
|
|
34
|
-
import {
|
|
34
|
+
import type { LoaderStore } from "../loader-store.js";
|
|
35
35
|
import {
|
|
36
36
|
collectClientRevalidationDecisions,
|
|
37
37
|
setActiveInterceptTargets,
|
|
@@ -42,7 +42,9 @@ import {
|
|
|
42
42
|
type TransitionWhenActionInput,
|
|
43
43
|
} from "./transition-when.js";
|
|
44
44
|
import { buildHistoryState } from "./history-state.js";
|
|
45
|
+
import { addLocationState } from "./react/location-state-shared.js";
|
|
45
46
|
import type { TransitionWhenKind } from "../types/segments.js";
|
|
47
|
+
import { auditTreeCause, type TreeUpdateCause } from "../suspense-audit.js";
|
|
46
48
|
|
|
47
49
|
function toScrollPayload(
|
|
48
50
|
scroll: boolean | undefined,
|
|
@@ -69,6 +71,13 @@ export function shouldStartViewTransition(
|
|
|
69
71
|
return !hasIntercept && hasTransition;
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
// Dev only (suspense-audit.ts I6): what this updater's commit is.
|
|
75
|
+
function treeCause(mode: UpdateMode, traversal?: boolean): TreeUpdateCause {
|
|
76
|
+
if (mode.type === "action") return "action";
|
|
77
|
+
if (mode.type === "stale-revalidation") return "stale-revalidation";
|
|
78
|
+
return traversal ? "popstate" : "navigation";
|
|
79
|
+
}
|
|
80
|
+
|
|
72
81
|
/**
|
|
73
82
|
* Transition commit. Every held commit announces the loader streams the
|
|
74
83
|
* committed tree is still receiving (loader-store.ts announcePendingStreams)
|
|
@@ -78,13 +87,14 @@ export function shouldStartViewTransition(
|
|
|
78
87
|
* its fallback. Also used by renderRoute's navigate() (testing/render-route.tsx).
|
|
79
88
|
*/
|
|
80
89
|
export function commitInTransition(
|
|
90
|
+
loaders: LoaderStore,
|
|
81
91
|
onUpdate: UpdateSubscriber,
|
|
82
92
|
segments: readonly ResolvedSegment[],
|
|
83
93
|
update: NavigationUpdate,
|
|
84
94
|
transitionTypes: readonly string[],
|
|
85
95
|
): void {
|
|
86
96
|
startTransition(() => {
|
|
87
|
-
|
|
97
|
+
loaders.announcePendingStreams(segments);
|
|
88
98
|
if (addTransitionType) {
|
|
89
99
|
for (const type of transitionTypes) addTransitionType(type);
|
|
90
100
|
}
|
|
@@ -225,8 +235,14 @@ export function createPartialUpdater(
|
|
|
225
235
|
segments = segmentIds ?? segmentState.currentSegmentIds;
|
|
226
236
|
}
|
|
227
237
|
|
|
238
|
+
// The page the client is on, which the server diffs the target against.
|
|
239
|
+
// tx.currentUrl is window.location when the transaction was created: on
|
|
240
|
+
// a back/forward the popstate event had already moved it to the target,
|
|
241
|
+
// and a server told the target is also the source revalidates nothing on
|
|
242
|
+
// the same route, so the page being left stayed on screen (#1030). The
|
|
243
|
+
// store's URL is the committed entry's until tx.commit().
|
|
228
244
|
const previousUrl =
|
|
229
|
-
mode.type === "leave-intercept"
|
|
245
|
+
mode.type === "leave-intercept" || (tx.traversal && !interceptSourceUrl)
|
|
230
246
|
? segmentState.currentUrl || tx.currentUrl
|
|
231
247
|
: interceptSourceUrl || tx.currentUrl || segmentState.currentUrl;
|
|
232
248
|
|
|
@@ -279,7 +295,7 @@ export function createPartialUpdater(
|
|
|
279
295
|
params: metadata.params ?? mergeSegmentParams(segmentsToCommit),
|
|
280
296
|
routeName: metadata.routeName,
|
|
281
297
|
state: tx.traversal
|
|
282
|
-
?
|
|
298
|
+
? addLocationState(window.history.state, metadata.locationState)
|
|
283
299
|
: buildHistoryState(tx.state, undefined, metadata.locationState),
|
|
284
300
|
}),
|
|
285
301
|
action:
|
|
@@ -457,10 +473,17 @@ export function createPartialUpdater(
|
|
|
457
473
|
scroll: toScrollPayload(commitScroll),
|
|
458
474
|
};
|
|
459
475
|
|
|
476
|
+
if (process.env.NODE_ENV !== "production") {
|
|
477
|
+
auditTreeCause(treeCause(mode, tx.traversal));
|
|
478
|
+
}
|
|
460
479
|
if (shouldStartViewTransition(existingSegments, cachedGatedOff)) {
|
|
461
|
-
commitInTransition(
|
|
462
|
-
|
|
463
|
-
|
|
480
|
+
commitInTransition(
|
|
481
|
+
store.loaders,
|
|
482
|
+
onUpdate,
|
|
483
|
+
existingSegments,
|
|
484
|
+
cachedUpdate,
|
|
485
|
+
["navigation"],
|
|
486
|
+
);
|
|
464
487
|
} else {
|
|
465
488
|
onUpdate(cachedUpdate);
|
|
466
489
|
}
|
|
@@ -484,6 +507,9 @@ export function createPartialUpdater(
|
|
|
484
507
|
{ routeName: payload.metadata.routeName },
|
|
485
508
|
);
|
|
486
509
|
|
|
510
|
+
if (process.env.NODE_ENV !== "production") {
|
|
511
|
+
auditTreeCause(treeCause(mode, tx.traversal));
|
|
512
|
+
}
|
|
487
513
|
onUpdate({
|
|
488
514
|
root: newTree,
|
|
489
515
|
metadata: payload.metadata,
|
|
@@ -499,6 +525,7 @@ export function createPartialUpdater(
|
|
|
499
525
|
);
|
|
500
526
|
tx.commit(matchedIds, existingSegments, {
|
|
501
527
|
routeName: payload.metadata.routeName,
|
|
528
|
+
treeless: true,
|
|
502
529
|
});
|
|
503
530
|
debugLog("[Browser] Navigation complete (no re-render)");
|
|
504
531
|
return;
|
|
@@ -710,11 +737,15 @@ export function createPartialUpdater(
|
|
|
710
737
|
metadata: payload.metadata!,
|
|
711
738
|
scroll: scrollPayload,
|
|
712
739
|
};
|
|
740
|
+
if (process.env.NODE_ENV !== "production") {
|
|
741
|
+
auditTreeCause(treeCause(mode, tx.traversal));
|
|
742
|
+
}
|
|
713
743
|
if (
|
|
714
744
|
!gatedOff &&
|
|
715
745
|
(mode.type === "action" || mode.type === "stale-revalidation")
|
|
716
746
|
) {
|
|
717
747
|
commitInTransition(
|
|
748
|
+
store.loaders,
|
|
718
749
|
onUpdate,
|
|
719
750
|
reconciled.mainSegments,
|
|
720
751
|
update,
|
|
@@ -722,6 +753,7 @@ export function createPartialUpdater(
|
|
|
722
753
|
);
|
|
723
754
|
} else if (hasTransition) {
|
|
724
755
|
commitInTransition(
|
|
756
|
+
store.loaders,
|
|
725
757
|
onUpdate,
|
|
726
758
|
reconciled.mainSegments,
|
|
727
759
|
update,
|
|
@@ -756,6 +788,7 @@ export function createPartialUpdater(
|
|
|
756
788
|
// segment reconciles in place (clientGroup key), so a read that still
|
|
757
789
|
// suspends must hold the presented content, not flash a fallback.
|
|
758
790
|
commitInTransition(
|
|
791
|
+
store.loaders,
|
|
759
792
|
onUpdate,
|
|
760
793
|
reconciled.mainSegments,
|
|
761
794
|
update,
|
|
@@ -764,12 +797,13 @@ export function createPartialUpdater(
|
|
|
764
797
|
} else {
|
|
765
798
|
// Cold/partially-prefetched nav that mounts NEW segments, or any
|
|
766
799
|
// commit transition({ when }) gated off (navigation, action refetch,
|
|
767
|
-
// stale revalidation): normal commit
|
|
768
|
-
//
|
|
769
|
-
//
|
|
770
|
-
//
|
|
771
|
-
//
|
|
772
|
-
//
|
|
800
|
+
// stale revalidation): normal, unanimated commit. A segment with work
|
|
801
|
+
// still pending shows its loading() fallback like a first load; one
|
|
802
|
+
// whose data is already in hand shows none. A gated-off segment keeps
|
|
803
|
+
// its key, so a fallback comes from its boundary suspending on pending
|
|
804
|
+
// work in this urgent commit, not from a remount (#995). Explicit
|
|
805
|
+
// transition() routes keep the content-hold via the hasTransition
|
|
806
|
+
// branch above (the opt-in).
|
|
773
807
|
onUpdate(update);
|
|
774
808
|
}
|
|
775
809
|
|
|
@@ -814,6 +848,9 @@ export function createPartialUpdater(
|
|
|
814
848
|
scroll: fullScrollPayload,
|
|
815
849
|
};
|
|
816
850
|
|
|
851
|
+
if (process.env.NODE_ENV !== "production") {
|
|
852
|
+
auditTreeCause(treeCause(mode, tx.traversal));
|
|
853
|
+
}
|
|
817
854
|
if (mode.type === "stale-revalidation") {
|
|
818
855
|
await rawStreamComplete;
|
|
819
856
|
// Mirror the partial branch's history-key staleness guard (above): the
|
|
@@ -828,9 +865,13 @@ export function createPartialUpdater(
|
|
|
828
865
|
);
|
|
829
866
|
return;
|
|
830
867
|
}
|
|
868
|
+
if (process.env.NODE_ENV !== "production") {
|
|
869
|
+
auditTreeCause("stale-revalidation");
|
|
870
|
+
}
|
|
831
871
|
if (fullGatedOff) onUpdate(fullUpdate);
|
|
832
872
|
else {
|
|
833
873
|
commitInTransition(
|
|
874
|
+
store.loaders,
|
|
834
875
|
onUpdate,
|
|
835
876
|
segments,
|
|
836
877
|
fullUpdate,
|
|
@@ -839,13 +880,16 @@ export function createPartialUpdater(
|
|
|
839
880
|
}
|
|
840
881
|
} else if (mode.type === "action" && !fullGatedOff) {
|
|
841
882
|
commitInTransition(
|
|
883
|
+
store.loaders,
|
|
842
884
|
onUpdate,
|
|
843
885
|
segments,
|
|
844
886
|
fullUpdate,
|
|
845
887
|
fullHasTransition ? ["action"] : [],
|
|
846
888
|
);
|
|
847
889
|
} else if (fullHasTransition) {
|
|
848
|
-
commitInTransition(onUpdate, segments, fullUpdate, [
|
|
890
|
+
commitInTransition(store.loaders, onUpdate, segments, fullUpdate, [
|
|
891
|
+
"navigation",
|
|
892
|
+
]);
|
|
849
893
|
} else {
|
|
850
894
|
onUpdate(fullUpdate);
|
|
851
895
|
}
|
|
@@ -2,68 +2,48 @@
|
|
|
2
2
|
* Router-wide default prefetch strategy (client seat).
|
|
3
3
|
*
|
|
4
4
|
* The server resolves `createRouter({ defaultPrefetch })` once at router init
|
|
5
|
-
* (router/prefetch-default.ts) and ships it in initial payload metadata
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* `data-prefetch-scope`.
|
|
12
|
-
*
|
|
13
|
-
* The module initial value must equal the server resolver's environment default:
|
|
14
|
-
* `"none"` in development and `"viewport"` in production. During SSR this
|
|
15
|
-
* module is never initialized from metadata, so keeping both seats aligned also
|
|
16
|
-
* gives metadata-less payloads the documented behavior.
|
|
5
|
+
* (router/prefetch-default.ts) and ships it in initial payload metadata. The
|
|
6
|
+
* router store carries it to its readers: `<Link>` reads
|
|
7
|
+
* `NavigationStoreContext.defaultPrefetch`, and delegated plain anchors get it
|
|
8
|
+
* from the navigation bridge. Every `<Link>` without an explicit `prefetch`
|
|
9
|
+
* prop and every eligible intercepted plain anchor that has not opted out with
|
|
10
|
+
* `data-prefetch="false"` or `data-prefetch="none"` uses it. Containers use the
|
|
11
|
+
* same `false`/`none` vocabulary via `data-prefetch-scope`.
|
|
17
12
|
*/
|
|
18
13
|
|
|
19
14
|
import type { PrefetchStrategy } from "../../router/prefetch-default.js";
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The default for a payload without `defaultPrefetch`: the server resolver's
|
|
18
|
+
* environment default (`"none"` in development, `"viewport"` in production),
|
|
19
|
+
* mirrored without pulling router-layer code into the client bundle. NODE_ENV
|
|
20
|
+
* is folded by the app build.
|
|
21
|
+
*/
|
|
22
|
+
export const ENVIRONMENT_DEFAULT_PREFETCH: PrefetchStrategy =
|
|
26
23
|
process.env.NODE_ENV === "production" ? "viewport" : "none";
|
|
27
24
|
|
|
28
|
-
function
|
|
29
|
-
if (typeof window === "undefined"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
return hoverNoneQuery;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Reset module state between tests that replace browser media globals. */
|
|
37
|
-
export function resetAdaptiveStrategyForTesting(): void {
|
|
38
|
-
hoverNoneQuery = null;
|
|
25
|
+
function hoverNoneQuery(): MediaQueryList | null {
|
|
26
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function")
|
|
27
|
+
return null;
|
|
28
|
+
return window.matchMedia("(hover: none)");
|
|
39
29
|
}
|
|
40
30
|
|
|
41
31
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
32
|
+
* Resolve adaptive to the strategy for the current input capability. Called
|
|
33
|
+
* when a prefetch is armed or triggered, never during render.
|
|
44
34
|
*/
|
|
45
|
-
export function setDefaultPrefetchStrategy(strategy: PrefetchStrategy): void {
|
|
46
|
-
defaultStrategy = strategy;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Current default strategy for Links and delegated plain anchors. */
|
|
50
|
-
export function getDefaultPrefetchStrategy(): PrefetchStrategy {
|
|
51
|
-
return defaultStrategy;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Resolve adaptive to the strategy for the current input capability. */
|
|
55
35
|
export function resolveAdaptiveStrategy(
|
|
56
36
|
strategy: PrefetchStrategy,
|
|
57
37
|
): PrefetchStrategy {
|
|
58
38
|
if (strategy !== "adaptive") return strategy;
|
|
59
|
-
return
|
|
39
|
+
return hoverNoneQuery()?.matches ? "viewport" : "hover";
|
|
60
40
|
}
|
|
61
41
|
|
|
62
42
|
/** Subscribe to changes in the input capability used by adaptive prefetch. */
|
|
63
43
|
export function subscribeToAdaptiveStrategyChange(
|
|
64
44
|
listener: () => void,
|
|
65
45
|
): () => void {
|
|
66
|
-
const query =
|
|
46
|
+
const query = hoverNoneQuery();
|
|
67
47
|
if (!query) return () => {};
|
|
68
48
|
if (typeof query.addEventListener === "function") {
|
|
69
49
|
query.addEventListener("change", listener);
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* cache keys responses by (URL, X-Rango-State value).
|
|
8
8
|
*
|
|
9
9
|
* Value format: `{buildVersion}:{invalidationTimestamp}`
|
|
10
|
-
* - Build version
|
|
10
|
+
* - Build version: the router's document version. It changes when a deploy
|
|
11
|
+
* changes the router's server code or the client assets, busting all cached
|
|
12
|
+
* prefetches at boot; a deploy that changes neither keeps them.
|
|
11
13
|
* - Timestamp rotates on invalidation (server action, invalidateClientCache).
|
|
12
14
|
*
|
|
13
15
|
* Storage is a session cookie named by the server-resolved name passed to
|
|
@@ -7,7 +7,6 @@ import React, {
|
|
|
7
7
|
useEffect,
|
|
8
8
|
useMemo,
|
|
9
9
|
useRef,
|
|
10
|
-
useSyncExternalStore,
|
|
11
10
|
type ForwardRefExoticComponent,
|
|
12
11
|
type RefAttributes,
|
|
13
12
|
} from "react";
|
|
@@ -38,7 +37,7 @@ import {
|
|
|
38
37
|
} from "../prefetch/loader.js";
|
|
39
38
|
import { observeForPrefetch } from "../prefetch/observer.js";
|
|
40
39
|
import {
|
|
41
|
-
|
|
40
|
+
ENVIRONMENT_DEFAULT_PREFETCH,
|
|
42
41
|
resolveAdaptiveStrategy,
|
|
43
42
|
subscribeToAdaptiveStrategyChange,
|
|
44
43
|
} from "../prefetch/default-strategy.js";
|
|
@@ -51,8 +50,6 @@ import type { PrefetchStrategy } from "../../router/prefetch-default.js";
|
|
|
51
50
|
export type { PrefetchStrategy } from "../../router/prefetch-default.js";
|
|
52
51
|
export { resolveAdaptiveStrategy } from "../prefetch/default-strategy.js";
|
|
53
52
|
|
|
54
|
-
const IGNORE_STRATEGY_CHANGES = (_listener: () => void) => () => {};
|
|
55
|
-
|
|
56
53
|
/**
|
|
57
54
|
* Link component props
|
|
58
55
|
*/
|
|
@@ -241,19 +238,11 @@ export const Link: ForwardRefExoticComponent<
|
|
|
241
238
|
ref,
|
|
242
239
|
) {
|
|
243
240
|
const ctx = useContext(NavigationStoreContext);
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
// the app root); provider-less SSR has no origin and keeps links internal.
|
|
250
|
-
const storeLocation = ctx?.eventController.getState().location as
|
|
251
|
-
| URL
|
|
252
|
-
| undefined;
|
|
253
|
-
const origin =
|
|
254
|
-
storeLocation?.origin ??
|
|
255
|
-
(typeof window !== "undefined" ? window.location.origin : undefined);
|
|
256
|
-
const isExternal = isExternalUrl(to, origin);
|
|
241
|
+
// The document's origin from the router store, the same on both sides
|
|
242
|
+
// (SSR: the live request's URL; browser: the store location), so
|
|
243
|
+
// data-external agrees across hydration. Without a provider there is no
|
|
244
|
+
// store and no origin: links stay internal.
|
|
245
|
+
const isExternal = isExternalUrl(to, ctx?.origin);
|
|
257
246
|
|
|
258
247
|
// Auto-prefix with basename for app-local paths.
|
|
259
248
|
// Skip if external, already prefixed, or not a root-relative path.
|
|
@@ -265,19 +254,11 @@ export const Link: ForwardRefExoticComponent<
|
|
|
265
254
|
return to === "/" ? bn : bn + to;
|
|
266
255
|
}, [to, isExternal, ctx?.basename]);
|
|
267
256
|
|
|
268
|
-
// No explicit `prefetch` prop: fall back to the router-wide default
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
// input capability rather than a module-load snapshot.
|
|
257
|
+
// No explicit `prefetch` prop: fall back to the router-wide default from
|
|
258
|
+
// the router store. Adaptive is resolved against the input capability when a
|
|
259
|
+
// prefetch is armed or triggered, never during render.
|
|
272
260
|
const configuredStrategy =
|
|
273
|
-
prefetch ?? ctx?.defaultPrefetch ??
|
|
274
|
-
const resolvedStrategy = useSyncExternalStore(
|
|
275
|
-
configuredStrategy === "adaptive"
|
|
276
|
-
? subscribeToAdaptiveStrategyChange
|
|
277
|
-
: IGNORE_STRATEGY_CHANGES,
|
|
278
|
-
() => resolveAdaptiveStrategy(configuredStrategy),
|
|
279
|
-
() => (configuredStrategy === "adaptive" ? "hover" : configuredStrategy),
|
|
280
|
-
);
|
|
261
|
+
prefetch ?? ctx?.defaultPrefetch ?? ENVIRONMENT_DEFAULT_PREFETCH;
|
|
281
262
|
|
|
282
263
|
// Internal ref for viewport observation; merge with forwarded ref
|
|
283
264
|
const internalRef = useRef<HTMLAnchorElement | null>(null);
|
|
@@ -376,8 +357,9 @@ export const Link: ForwardRefExoticComponent<
|
|
|
376
357
|
|
|
377
358
|
const handleMouseEnter = useCallback(() => {
|
|
378
359
|
const element = internalRef.current;
|
|
360
|
+
const strategy = resolveAdaptiveStrategy(configuredStrategy);
|
|
379
361
|
if (
|
|
380
|
-
(
|
|
362
|
+
(strategy === "hover" || strategy === "viewport") &&
|
|
381
363
|
!isExternal &&
|
|
382
364
|
ctx?.store &&
|
|
383
365
|
(!element ||
|
|
@@ -396,17 +378,26 @@ export const Link: ForwardRefExoticComponent<
|
|
|
396
378
|
prefetchKey,
|
|
397
379
|
);
|
|
398
380
|
}
|
|
399
|
-
}, [
|
|
381
|
+
}, [configuredStrategy, resolvedTo, isExternal, ctx, prefetchKey]);
|
|
400
382
|
|
|
401
383
|
// Viewport/render prefetch: waits for idle before starting,
|
|
402
384
|
// uses concurrency-limited queue to avoid flooding.
|
|
403
385
|
useEffect(() => {
|
|
404
386
|
if (isExternal || !ctx?.store) return;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
387
|
+
if (
|
|
388
|
+
configuredStrategy !== "viewport" &&
|
|
389
|
+
configuredStrategy !== "render" &&
|
|
390
|
+
configuredStrategy !== "adaptive"
|
|
391
|
+
) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
408
394
|
|
|
409
395
|
const armPrefetch = (): (() => void) => {
|
|
396
|
+
const strategy = resolveAdaptiveStrategy(configuredStrategy);
|
|
397
|
+
const isViewport = strategy === "viewport";
|
|
398
|
+
const isRender = strategy === "render";
|
|
399
|
+
if (!isViewport && !isRender) return () => {};
|
|
400
|
+
|
|
410
401
|
const element = internalRef.current;
|
|
411
402
|
if (
|
|
412
403
|
element &&
|
|
@@ -458,27 +449,30 @@ export const Link: ForwardRefExoticComponent<
|
|
|
458
449
|
};
|
|
459
450
|
|
|
460
451
|
let disarmPrefetch = armPrefetch();
|
|
452
|
+
const rearm = () => {
|
|
453
|
+
disarmPrefetch();
|
|
454
|
+
disarmPrefetch = armPrefetch();
|
|
455
|
+
};
|
|
461
456
|
const element = internalRef.current;
|
|
462
457
|
const unsubscribeScope = element
|
|
463
|
-
? subscribeToPrefetchScopeChange(element,
|
|
464
|
-
disarmPrefetch();
|
|
465
|
-
disarmPrefetch = armPrefetch();
|
|
466
|
-
})
|
|
458
|
+
? subscribeToPrefetchScopeChange(element, rearm)
|
|
467
459
|
: undefined;
|
|
468
460
|
const unsubscribeLocation = subscribeToLocationChange(
|
|
469
461
|
ctx.eventController,
|
|
470
|
-
|
|
471
|
-
disarmPrefetch();
|
|
472
|
-
disarmPrefetch = armPrefetch();
|
|
473
|
-
},
|
|
462
|
+
rearm,
|
|
474
463
|
);
|
|
464
|
+
const unsubscribeAdaptive =
|
|
465
|
+
configuredStrategy === "adaptive"
|
|
466
|
+
? subscribeToAdaptiveStrategyChange(rearm)
|
|
467
|
+
: undefined;
|
|
475
468
|
|
|
476
469
|
return () => {
|
|
477
470
|
unsubscribeScope?.();
|
|
478
471
|
unsubscribeLocation();
|
|
472
|
+
unsubscribeAdaptive?.();
|
|
479
473
|
disarmPrefetch();
|
|
480
474
|
};
|
|
481
|
-
}, [
|
|
475
|
+
}, [configuredStrategy, resolvedTo, isExternal, ctx, prefetchKey]);
|
|
482
476
|
|
|
483
477
|
return (
|
|
484
478
|
<a
|