@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
|
@@ -8,10 +8,11 @@ import {
|
|
|
8
8
|
findCallParenAfterGenerics,
|
|
9
9
|
skipStringOrComment,
|
|
10
10
|
} from "../expose-id-utils.js";
|
|
11
|
-
import { escapeRegExp } from "../../../regex-escape.js";
|
|
12
11
|
import {
|
|
13
12
|
getImportedFnNames,
|
|
14
13
|
buildUnsupportedShapeWarning,
|
|
14
|
+
createCallPattern,
|
|
15
|
+
offsetToLineColumn,
|
|
15
16
|
} from "./export-analysis.js";
|
|
16
17
|
import { codeMatchIndices } from "../../../build/route-types/source-scan.js";
|
|
17
18
|
import { createRangoDebugger, createCounter, NS } from "../../debug.js";
|
|
@@ -42,6 +43,26 @@ function skipLeadingTrivia(code: string, start: number, end: number): number {
|
|
|
42
43
|
return i;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* A router's `$$id`: a hash of its root-relative file and of its position
|
|
48
|
+
* among the file's createRouter() calls.
|
|
49
|
+
*
|
|
50
|
+
* Not of the call's line. `code` is TS-transformed, and a dev server keeps
|
|
51
|
+
* comments there that a build drops, so a line of `code` gave build-time
|
|
52
|
+
* discovery and the bundle different ids for any router with a comment above
|
|
53
|
+
* it (e2e/test-app, tests/cloudflare-basic): the build registered the lazy
|
|
54
|
+
* route manifest under an id no running router had. And a line of the file as
|
|
55
|
+
* written changes with every blank line or comment added above the call,
|
|
56
|
+
* which renamed the state cookie, the route manifest chunk and the router's
|
|
57
|
+
* cache versions for an edit that changed nothing.
|
|
58
|
+
*/
|
|
59
|
+
export function routerId(filePath: string, callIndex: number): string {
|
|
60
|
+
return createHash("sha256")
|
|
61
|
+
.update(`${filePath}#${callIndex}`)
|
|
62
|
+
.digest("hex")
|
|
63
|
+
.slice(0, 8);
|
|
64
|
+
}
|
|
65
|
+
|
|
45
66
|
export function transformRouter(
|
|
46
67
|
code: string,
|
|
47
68
|
filePath: string,
|
|
@@ -53,14 +74,12 @@ export function transformRouter(
|
|
|
53
74
|
// e.g. createRouter<Config<Env>>(...)) and the opening paren are located
|
|
54
75
|
// separately via findCallParenAfterGenerics so a nested `>` does not defeat
|
|
55
76
|
// the scan (a `<[^>]*>` regex stopped at the first `>`).
|
|
56
|
-
const pat =
|
|
57
|
-
`\\b(?:${routerFnNames.map(escapeRegExp).join("|")})\\b`,
|
|
58
|
-
"g",
|
|
59
|
-
);
|
|
77
|
+
const pat = createCallPattern(routerFnNames);
|
|
60
78
|
let match: RegExpExecArray | null;
|
|
61
79
|
const s = new MagicString(code);
|
|
62
80
|
let changed = false;
|
|
63
81
|
const unsupportedSites: Array<{ line: number; column: number }> = [];
|
|
82
|
+
let callIndex = -1;
|
|
64
83
|
|
|
65
84
|
// Compute the import path for the generated route names file.
|
|
66
85
|
// filePath is relative to project root (e.g., "src/router.tsx")
|
|
@@ -86,6 +105,7 @@ export function transformRouter(
|
|
|
86
105
|
// type position) yields -1 and is skipped.
|
|
87
106
|
const parenPos = findCallParenAfterGenerics(code, calleeEnd);
|
|
88
107
|
if (parenPos === -1) continue;
|
|
108
|
+
callIndex++;
|
|
89
109
|
|
|
90
110
|
const closeParen = findMatchingParen(code, parenPos + 1);
|
|
91
111
|
const callArgs = code.slice(parenPos + 1, closeParen);
|
|
@@ -98,12 +118,7 @@ export function transformRouter(
|
|
|
98
118
|
if (callArgs.includes(`$$routeNames: ${routeNamesVar}`)) continue;
|
|
99
119
|
|
|
100
120
|
const sourceFilePath = absolutePath ?? filePath;
|
|
101
|
-
const
|
|
102
|
-
const hash = createHash("sha256")
|
|
103
|
-
.update(`${filePath}:${lineNumber}`)
|
|
104
|
-
.digest("hex")
|
|
105
|
-
.slice(0, 8);
|
|
106
|
-
const injected = ` $$id: "${hash}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
|
|
121
|
+
const injected = ` $$id: "${routerId(filePath, callIndex)}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
|
|
107
122
|
|
|
108
123
|
// Skip a leading comment/whitespace run so `createRouter(/* c *\/ {...})`
|
|
109
124
|
// and a newline-then-comment prefix still resolve to the object literal.
|
|
@@ -124,9 +139,7 @@ export function transformRouter(
|
|
|
124
139
|
// stable $$id can be injected here. Record it so the plugin can warn —
|
|
125
140
|
// and crucially do NOT mark changed, so a dead named-routes.gen import is
|
|
126
141
|
// not prepended for a call we never touched.
|
|
127
|
-
|
|
128
|
-
const column = callStart - (lastNl + 1) + 1;
|
|
129
|
-
unsupportedSites.push({ line: lineNumber, column });
|
|
142
|
+
unsupportedSites.push(offsetToLineColumn(code, callStart));
|
|
130
143
|
}
|
|
131
144
|
}
|
|
132
145
|
|
|
@@ -156,11 +169,19 @@ export function transformRouter(
|
|
|
156
169
|
*/
|
|
157
170
|
export function exposeRouterId(): Plugin {
|
|
158
171
|
let projectRoot = "";
|
|
172
|
+
// $$sourceFile is read by route discovery and the CLI, which run on a dev
|
|
173
|
+
// server (the build's discovery temp server included) and need the absolute
|
|
174
|
+
// path. Nothing reads it when serving, so a production build ships the
|
|
175
|
+
// root-relative path: an absolute one would put the build machine's checkout
|
|
176
|
+
// directory in every router's chunk and give the same source a different
|
|
177
|
+
// cache version per directory (discovery/build-versions.ts hashes the chunk).
|
|
178
|
+
let rootRelativeSourceFile = false;
|
|
159
179
|
const counter = createCounter(debug, "expose-router-id");
|
|
160
180
|
return {
|
|
161
181
|
name: "@rangojs/router:expose-router-id",
|
|
162
182
|
configResolved(config) {
|
|
163
183
|
projectRoot = config.root;
|
|
184
|
+
rootRelativeSourceFile = config.command === "build";
|
|
164
185
|
},
|
|
165
186
|
buildEnd() {
|
|
166
187
|
counter?.flush();
|
|
@@ -188,7 +209,7 @@ export function exposeRouterId(): Plugin {
|
|
|
188
209
|
code,
|
|
189
210
|
filePath,
|
|
190
211
|
routerFnNames,
|
|
191
|
-
normalizePath(id),
|
|
212
|
+
rootRelativeSourceFile ? undefined : normalizePath(id),
|
|
192
213
|
warn,
|
|
193
214
|
);
|
|
194
215
|
} finally {
|
|
@@ -45,6 +45,8 @@ import {
|
|
|
45
45
|
transformHandlerIds,
|
|
46
46
|
} from "./expose-ids/handler-transform.js";
|
|
47
47
|
import { createRangoDebugger, createCounter, NS } from "../debug.js";
|
|
48
|
+
import { compareStrings } from "../utils/compare-strings.js";
|
|
49
|
+
import { VIRTUAL_LOADER_MANIFEST_ID } from "../discovery/state.js";
|
|
48
50
|
|
|
49
51
|
const debug = createRangoDebugger(NS.transform);
|
|
50
52
|
|
|
@@ -56,7 +58,7 @@ export type { ExposeInternalIdsApi } from "./expose-ids/types.js";
|
|
|
56
58
|
// Virtual module for loader manifest
|
|
57
59
|
// ---------------------------------------------------------------------------
|
|
58
60
|
|
|
59
|
-
const VIRTUAL_LOADER_MANIFEST =
|
|
61
|
+
const VIRTUAL_LOADER_MANIFEST = VIRTUAL_LOADER_MANIFEST_ID;
|
|
60
62
|
const RESOLVED_VIRTUAL_LOADER_MANIFEST = "\0" + VIRTUAL_LOADER_MANIFEST;
|
|
61
63
|
|
|
62
64
|
// ---------------------------------------------------------------------------
|
|
@@ -245,10 +247,17 @@ setLoaderImports({});
|
|
|
245
247
|
`;
|
|
246
248
|
}
|
|
247
249
|
|
|
248
|
-
// Build mode: generate lazy import map
|
|
250
|
+
// Build mode: generate lazy import map. Sorted by id: the registry fills
|
|
251
|
+
// in directory-scan order (the pre-scan below) and transform order, both
|
|
252
|
+
// of which vary between machines and runs, and this module's bytes feed
|
|
253
|
+
// the cache version of every router bundled with it
|
|
254
|
+
// (discovery/build-versions.ts).
|
|
249
255
|
const lazyImports: string[] = [];
|
|
256
|
+
const sortedLoaders = [...loaderRegistry].sort(([a], [b]) =>
|
|
257
|
+
compareStrings(a, b),
|
|
258
|
+
);
|
|
250
259
|
|
|
251
|
-
for (const [hashedId, { filePath, exportName }] of
|
|
260
|
+
for (const [hashedId, { filePath, exportName }] of sortedLoaders) {
|
|
252
261
|
lazyImports.push(
|
|
253
262
|
` "${hashedId}": () => import("/${filePath}").then(m => m.${exportName})`,
|
|
254
263
|
);
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { parseAst, type Plugin } from "vite";
|
|
2
|
+
import { escapeRegExp } from "../../regex-escape.js";
|
|
3
|
+
import { compareStrings } from "../utils/compare-strings.js";
|
|
4
|
+
import { SERVER_REFERENCES_MODULE_ID } from "../discovery/build-versions.js";
|
|
5
|
+
|
|
6
|
+
/** One property of an object literal, by its position in the source. */
|
|
7
|
+
export interface LiteralProperty {
|
|
8
|
+
readonly key: string;
|
|
9
|
+
/** Range of the whole property, key included. */
|
|
10
|
+
readonly start: number;
|
|
11
|
+
readonly end: number;
|
|
12
|
+
/** The value's AST node. */
|
|
13
|
+
readonly value: any;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The properties of an object-literal AST node, or undefined when it is not an
|
|
18
|
+
* object literal of plain keys (a spread, a computed key).
|
|
19
|
+
*/
|
|
20
|
+
export function literalProperties(object: any): LiteralProperty[] | undefined {
|
|
21
|
+
if (object?.type !== "ObjectExpression") return undefined;
|
|
22
|
+
const properties: LiteralProperty[] = [];
|
|
23
|
+
for (const property of object.properties ?? []) {
|
|
24
|
+
const key =
|
|
25
|
+
property?.type === "Property" && !property.computed
|
|
26
|
+
? (property.key?.value ?? property.key?.name)
|
|
27
|
+
: undefined;
|
|
28
|
+
if (typeof key !== "string") return undefined;
|
|
29
|
+
properties.push({
|
|
30
|
+
key,
|
|
31
|
+
start: property.start,
|
|
32
|
+
end: property.end,
|
|
33
|
+
value: property.value,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return properties;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The properties of a module's `export default { ... }`, or undefined when
|
|
41
|
+
* the module does not parse or is not that shape. plugin-rsc generates its
|
|
42
|
+
* registries (the server-reference map, the assets manifest) in this form.
|
|
43
|
+
*/
|
|
44
|
+
export function defaultExportProperties(
|
|
45
|
+
code: string,
|
|
46
|
+
): LiteralProperty[] | undefined {
|
|
47
|
+
let program: any;
|
|
48
|
+
try {
|
|
49
|
+
program = parseAst(code);
|
|
50
|
+
} catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
return literalProperties(
|
|
54
|
+
(program.body ?? []).find(
|
|
55
|
+
(node: any) => node?.type === "ExportDefaultDeclaration",
|
|
56
|
+
)?.declaration,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Return `code` with the properties of its default-exported object literal
|
|
62
|
+
* sorted by key, or undefined when there is nothing to reorder (or the module
|
|
63
|
+
* is not that shape).
|
|
64
|
+
*/
|
|
65
|
+
export function sortDefaultExportProperties(code: string): string | undefined {
|
|
66
|
+
const properties = defaultExportProperties(code);
|
|
67
|
+
if (!properties || properties.length < 2) return undefined;
|
|
68
|
+
const sorted = [...properties].sort((a, b) => compareStrings(a.key, b.key));
|
|
69
|
+
if (sorted.every((property, index) => property === properties[index])) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return (
|
|
73
|
+
code.slice(0, properties[0]!.start) +
|
|
74
|
+
sorted
|
|
75
|
+
.map((property) => code.slice(property.start, property.end))
|
|
76
|
+
.join(",\n") +
|
|
77
|
+
code.slice(properties[properties.length - 1]!.end)
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const ASSETS_MANIFEST_ID = "virtual:vite-rsc/assets-manifest";
|
|
82
|
+
const ASSETS_MANIFEST_IMPORT =
|
|
83
|
+
/import\s+([A-Za-z_$][\w$]*)\s+from\s*["']virtual:vite-rsc\/assets-manifest["']/;
|
|
84
|
+
/** The local name plugin-rsc's own runtime modules import the manifest under. */
|
|
85
|
+
const ASSETS_MANIFEST_BINDING = "assetsManifest";
|
|
86
|
+
/**
|
|
87
|
+
* The names plugin-rsc's GENERATED code imports it under. Only these are
|
|
88
|
+
* renamed: the rename is textual, and a name an app author picked
|
|
89
|
+
* (`import manifest from ...`) can also be a word in that module's strings.
|
|
90
|
+
*/
|
|
91
|
+
const GENERATED_BINDINGS: ReadonlySet<string> = new Set([
|
|
92
|
+
"__vite_rsc_assets_manifest__",
|
|
93
|
+
"__vite_rsc_assets_manifest",
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
function identifier(name: string): RegExp {
|
|
97
|
+
return new RegExp(`(?<![\\w$.])${escapeRegExp(name)}(?![\\w$])`, "g");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Return `code` with its default import of plugin-rsc's assets manifest
|
|
102
|
+
* renamed to {@link ASSETS_MANIFEST_BINDING}, or undefined when there is
|
|
103
|
+
* nothing to rename (no such import under a generated name, or the module
|
|
104
|
+
* uses the canonical name for something else).
|
|
105
|
+
*/
|
|
106
|
+
export function canonicalAssetsManifestBinding(
|
|
107
|
+
code: string,
|
|
108
|
+
): string | undefined {
|
|
109
|
+
const local = code.match(ASSETS_MANIFEST_IMPORT)?.[1];
|
|
110
|
+
if (local === undefined || !GENERATED_BINDINGS.has(local)) return undefined;
|
|
111
|
+
if (identifier(ASSETS_MANIFEST_BINDING).test(code)) return undefined;
|
|
112
|
+
return code.replace(identifier(local), ASSETS_MANIFEST_BINDING);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Removes two run-to-run differences from plugin-rsc 0.5.35's build output.
|
|
117
|
+
* The cache versions hash these bytes (discovery/build-versions.ts).
|
|
118
|
+
*
|
|
119
|
+
* 1. Property order of the server-reference map. plugin-rsc writes it in the
|
|
120
|
+
* order its transforms first saw each `"use server"` module
|
|
121
|
+
* (`ServerReferencesManager.claimMap`), which varies with the concurrent
|
|
122
|
+
* scan builds (e2e/test-app: 2 of 2 consecutive builds differed). Sorted
|
|
123
|
+
* here so a minified server build, where stripServerReferenceMap finds no
|
|
124
|
+
* region comments, still hashes the same bytes.
|
|
125
|
+
* 2. Local name of the assets-manifest import. plugin-rsc imports the manifest
|
|
126
|
+
* under three names; the bundler merges them into one import per chunk and
|
|
127
|
+
* keeps a different one from build to build (the cache-versions fixture:
|
|
128
|
+
* 1 of 10 concurrent builds). One name in, one name out.
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
131
|
+
export function stableRscOutput(): Plugin {
|
|
132
|
+
return {
|
|
133
|
+
name: "@rangojs/router:stable-rsc-output",
|
|
134
|
+
apply: "build",
|
|
135
|
+
// After plugin-rsc's transforms, which add the manifest import.
|
|
136
|
+
enforce: "post",
|
|
137
|
+
transform(code, id) {
|
|
138
|
+
const stable =
|
|
139
|
+
id === SERVER_REFERENCES_MODULE_ID
|
|
140
|
+
? sortDefaultExportProperties(code)
|
|
141
|
+
: code.includes(ASSETS_MANIFEST_ID)
|
|
142
|
+
? canonicalAssetsManifestBinding(code)
|
|
143
|
+
: undefined;
|
|
144
|
+
return stable === undefined ? null : { code: stable, map: null };
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { parseAst, type Plugin } from "vite";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
VIRTUAL_IDS,
|
|
4
|
+
getVirtualBuildVersionContent,
|
|
5
|
+
getVirtualVersionContent,
|
|
6
|
+
} from "./virtual-entries.js";
|
|
3
7
|
import { hasUseClientDirective } from "../utils/directive-prologue.js";
|
|
4
8
|
|
|
5
9
|
interface ClientModuleSignature {
|
|
@@ -100,25 +104,22 @@ function getClientModuleSignature(
|
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
/**
|
|
103
|
-
* Plugin providing
|
|
104
|
-
* Exports VERSION that changes when RSC modules change (dev) or at build time (production).
|
|
107
|
+
* Plugin providing the `@rangojs/router:version` virtual module.
|
|
105
108
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
+
* Dev: exports a VERSION stamp used for both versions of every router. It
|
|
110
|
+
* updates when the server starts and when an RSC module changes via HMR (the
|
|
111
|
+
* version module is invalidated). Client-only HMR changes do not update it:
|
|
112
|
+
* they do not affect server-rendered content or cached RSC payloads.
|
|
109
113
|
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* Client-only HMR changes don't update the version since they don't affect
|
|
115
|
-
* server-rendered content or cached RSC payloads.
|
|
114
|
+
* Build: exports a placeholder for the per-router versions table. The module
|
|
115
|
+
* holds nothing that varies between builds; the table is written into the
|
|
116
|
+
* built chunk after the server output is hashed (the buildApp post hook in
|
|
117
|
+
* router-discovery.ts). See docs/design/per-app-cache-version.md.
|
|
116
118
|
* @internal
|
|
117
119
|
*/
|
|
118
120
|
export function createVersionPlugin(): Plugin {
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
let currentVersion = buildVersion;
|
|
121
|
+
// Dev stamp, generated at plugin creation (server start).
|
|
122
|
+
let currentVersion = Date.now().toString(16);
|
|
122
123
|
let isDev = false;
|
|
123
124
|
let server: any = null;
|
|
124
125
|
let resolvedCacheDir: string | undefined;
|
|
@@ -142,14 +143,6 @@ export function createVersionPlugin(): Plugin {
|
|
|
142
143
|
name: "@rangojs/router:version",
|
|
143
144
|
enforce: "pre",
|
|
144
145
|
|
|
145
|
-
// The build-time shell capture phase (producer B, #699) stamps entries
|
|
146
|
-
// with THIS instance's version — the value folded into the shipped worker
|
|
147
|
-
// — never the discovery temp server's own version-plugin value (a
|
|
148
|
-
// different Date.now() stamp that would fail the serve-side gate).
|
|
149
|
-
api: {
|
|
150
|
-
getBuildVersion: (): string => currentVersion,
|
|
151
|
-
},
|
|
152
|
-
|
|
153
146
|
configResolved(config) {
|
|
154
147
|
isDev = config.command === "serve";
|
|
155
148
|
resolvedCacheDir = config.cacheDir
|
|
@@ -177,7 +170,9 @@ export function createVersionPlugin(): Plugin {
|
|
|
177
170
|
|
|
178
171
|
load(id) {
|
|
179
172
|
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
180
|
-
return
|
|
173
|
+
return isDev
|
|
174
|
+
? getVirtualVersionContent(currentVersion)
|
|
175
|
+
: getVirtualBuildVersionContent();
|
|
181
176
|
}
|
|
182
177
|
return null;
|
|
183
178
|
},
|
|
@@ -5,8 +5,23 @@
|
|
|
5
5
|
|
|
6
6
|
declare module "@rangojs/router:version" {
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* The build's version string.
|
|
9
|
+
*
|
|
10
|
+
* - Dev: a stamp that changes on server start and on every RSC module edit.
|
|
11
|
+
* - Production: the whole-build document version, a hash of the server
|
|
12
|
+
* output and the client asset names. The same source builds to the same
|
|
13
|
+
* value; any change to any router changes it.
|
|
14
|
+
*
|
|
15
|
+
* A router serves with its own versions (`ROUTER_VERSIONS`), not this one.
|
|
10
16
|
*/
|
|
11
17
|
export const VERSION: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Per-router cache versions computed at build time: router id to
|
|
21
|
+
* `[data, document]`, with `"*"` holding the whole-build pair.
|
|
22
|
+
* `undefined` in dev, where `VERSION` is used for both.
|
|
23
|
+
*/
|
|
24
|
+
export const ROUTER_VERSIONS:
|
|
25
|
+
| Readonly<Record<string, readonly [data: string, document: string]>>
|
|
26
|
+
| undefined;
|
|
12
27
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { HeadScriptsOption } from "../plugin-types.js";
|
|
2
|
+
import { DEFAULT_ROUTER_VERSIONS_KEY } from "../../router-versions.js";
|
|
2
3
|
|
|
3
4
|
export const VIRTUAL_ENTRY_BROWSER: string = `
|
|
4
5
|
import {
|
|
@@ -27,6 +28,12 @@ async function initializeApp() {
|
|
|
27
28
|
// is the default; createRouter({ strictMode: false }) ships the opt-out in the
|
|
28
29
|
// payload metadata. StrictMode emits no DOM, so toggling never changes markup.
|
|
29
30
|
const { strictMode, initialPayload } = await initBrowserApp({ rscStream, deps });
|
|
31
|
+
// Set only on a document a no-JS useActionState POST rendered: React needs
|
|
32
|
+
// the server's form state to hydrate the hook without resetting it. A state
|
|
33
|
+
// Flight could not carry rejects: hydrate without it, as before.
|
|
34
|
+
const formState = await Promise.resolve(initialPayload.formState).catch(
|
|
35
|
+
() => undefined
|
|
36
|
+
);
|
|
30
37
|
|
|
31
38
|
if (import.meta.hot) {
|
|
32
39
|
const { startDevDiscoveryHandshake } = await import(
|
|
@@ -41,7 +48,8 @@ async function initializeApp() {
|
|
|
41
48
|
const app = createElement(Rango);
|
|
42
49
|
hydrateRoot(
|
|
43
50
|
document,
|
|
44
|
-
strictMode === false ? app : createElement(StrictMode, null, app)
|
|
51
|
+
strictMode === false ? app : createElement(StrictMode, null, app),
|
|
52
|
+
formState ? { formState } : undefined
|
|
45
53
|
);
|
|
46
54
|
}
|
|
47
55
|
|
|
@@ -164,7 +172,7 @@ export const resumeShellHTML = createShellResumeHandler({
|
|
|
164
172
|
* registered for the _rsc_loader endpoint and fail in production.
|
|
165
173
|
*
|
|
166
174
|
* Single source of truth: both the generated virtual RSC entry below and the
|
|
167
|
-
* custom-entry injector (
|
|
175
|
+
* custom-entry injector (entry-bootstrap-injector) consume this list, so a new
|
|
168
176
|
* bootstrap manifest cannot be added to one path and forgotten on the other.
|
|
169
177
|
* That exact drift (loader-manifest present here but missing from the injector)
|
|
170
178
|
* is what left fetchable loaders unresolved on custom worker entries.
|
|
@@ -197,12 +205,11 @@ import {
|
|
|
197
205
|
// consults them at router-module evaluation. Router-first would silently push
|
|
198
206
|
// every clientUrls() app onto the deferred-subscription path and change mount
|
|
199
207
|
// registration order with no error. The custom-entry injector keeps the same
|
|
200
|
-
// guarantee by PREPENDING this list at file top (
|
|
208
|
+
// guarantee by PREPENDING this list at file top (entry-bootstrap-injector.ts).
|
|
201
209
|
${bootstrapImports}
|
|
202
210
|
|
|
203
211
|
import { router } from "${routerPath}";
|
|
204
212
|
import { createRSCHandler } from "@rangojs/router/internal/rsc-handler";
|
|
205
|
-
import { VERSION } from "@rangojs/router:version";
|
|
206
213
|
|
|
207
214
|
// Lazily create the handler on first request so that ESM live bindings
|
|
208
215
|
// have resolved by the time we read \`router\`. During HMR the module may
|
|
@@ -212,7 +219,6 @@ export default function handler(request, env) {
|
|
|
212
219
|
if (!_handler) {
|
|
213
220
|
_handler = createRSCHandler({
|
|
214
221
|
router,
|
|
215
|
-
version: VERSION,
|
|
216
222
|
// Forward the router's CSP nonce provider. createRSCHandler reads the
|
|
217
223
|
// provider only from options.nonce; without this, createRouter({ nonce })
|
|
218
224
|
// is silently dropped on the Node preset (the Cloudflare path wires it via
|
|
@@ -314,6 +320,33 @@ export const VIRTUAL_IDS = {
|
|
|
314
320
|
version: "@rangojs/router:version",
|
|
315
321
|
} as const;
|
|
316
322
|
|
|
323
|
+
/** Dev: one stamp for both versions of every router, bumped on RSC edits. */
|
|
317
324
|
export function getVirtualVersionContent(version: string): string {
|
|
318
|
-
return
|
|
325
|
+
return [
|
|
326
|
+
`export const VERSION = ${JSON.stringify(version)};`,
|
|
327
|
+
`export const ROUTER_VERSIONS = undefined;`,
|
|
328
|
+
].join("\n");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Free identifier the production version module ships in place of the table.
|
|
333
|
+
* The versions are hashes of the built server code, so they cannot be part of
|
|
334
|
+
* it: the buildApp post hook (router-discovery.ts) replaces this token in the
|
|
335
|
+
* written chunk once the hashes are final (runRouterVersionsPhase,
|
|
336
|
+
* discovery/router-versions-phase.ts). An unreplaced token throws a ReferenceError
|
|
337
|
+
* when the module evaluates, so a build that skipped the step cannot serve
|
|
338
|
+
* with a constant version.
|
|
339
|
+
*/
|
|
340
|
+
export const ROUTER_VERSIONS_PLACEHOLDER = "__RANGO_ROUTER_VERSIONS__";
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Production: byte-identical in every build, so it never moves the hashes it
|
|
344
|
+
* is later filled with. VERSION is the whole-build document version (the
|
|
345
|
+
* table's "*" entry).
|
|
346
|
+
*/
|
|
347
|
+
export function getVirtualBuildVersionContent(): string {
|
|
348
|
+
return [
|
|
349
|
+
`export const ROUTER_VERSIONS = ${ROUTER_VERSIONS_PLACEHOLDER};`,
|
|
350
|
+
`export const VERSION = ROUTER_VERSIONS[${JSON.stringify(DEFAULT_ROUTER_VERSIONS_KEY)}][1];`,
|
|
351
|
+
].join("\n");
|
|
319
352
|
}
|
package/src/vite/rango.ts
CHANGED
|
@@ -2,7 +2,10 @@ import { type PluginOption } from "vite";
|
|
|
2
2
|
import { readFileSync, existsSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { exposeActionId } from "./plugins/expose-action-id.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
configureEncryptionKey,
|
|
7
|
+
defineEncryptionKeyExpr,
|
|
8
|
+
} from "./encryption-key.js";
|
|
6
9
|
import {
|
|
7
10
|
createLoaderDirectiveGuardPlugin,
|
|
8
11
|
createLoaderScanStubPlugin,
|
|
@@ -12,6 +15,7 @@ import {
|
|
|
12
15
|
import { useCacheTransform } from "./plugins/use-cache-transform.js";
|
|
13
16
|
import { transitionWhenHoistPlugin } from "./plugins/transition-when-hoist.js";
|
|
14
17
|
import { clientRefDedup } from "./plugins/client-ref-dedup.js";
|
|
18
|
+
import { stableRscOutput } from "./plugins/stable-rsc-output.js";
|
|
15
19
|
import { VIRTUAL_IDS } from "./plugins/virtual-entries.js";
|
|
16
20
|
import {
|
|
17
21
|
getExcludeDeps,
|
|
@@ -43,7 +47,7 @@ import type {
|
|
|
43
47
|
} from "./plugin-types.js";
|
|
44
48
|
import { createVercelOutputPlugin } from "./plugins/vercel-output.js";
|
|
45
49
|
import { printBanner, rangoVersion } from "./utils/banner.js";
|
|
46
|
-
import {
|
|
50
|
+
import { createEntryBootstrapInjectorPlugin } from "./plugins/entry-bootstrap-injector.js";
|
|
47
51
|
import { createCjsToEsmPlugin } from "./plugins/cjs-to-esm.js";
|
|
48
52
|
import { createRouterDiscoveryPlugin } from "./router-discovery.js";
|
|
49
53
|
import { performanceTracksPlugin } from "./plugins/performance-tracks.js";
|
|
@@ -76,6 +80,20 @@ const debugConfig = createRangoDebugger(NS.config);
|
|
|
76
80
|
*/
|
|
77
81
|
const SERVER_BUILD_TARGET = "esnext";
|
|
78
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Entry-signature mode for the node/vercel RSC build, the one
|
|
85
|
+
* `@cloudflare/vite-plugin` forces on its worker entry.
|
|
86
|
+
*
|
|
87
|
+
* Vite's default for a server build, "allow-extension", lets the bundler park
|
|
88
|
+
* modules shared with lazy chunks in the entry chunk. Under a host router that
|
|
89
|
+
* put the router runtime (80 modules, measured on e2e/test-app/.host-fixture
|
|
90
|
+
* and examples/vercel-multi-router) and every sub-app's route names into
|
|
91
|
+
* `index.js`, which every sub-app chunk imported back and which names each
|
|
92
|
+
* sub-app chunk by its content hash: no router's cache version was independent
|
|
93
|
+
* of the others (discovery/build-versions.ts hashes a router's chunks).
|
|
94
|
+
*/
|
|
95
|
+
const RSC_ENTRY_SIGNATURES = "strict";
|
|
96
|
+
|
|
79
97
|
// The leading-directive 'use client' sniff is shared with version-plugin's
|
|
80
98
|
// getClientModuleSignature so the two cannot drift. Imported for local use by the
|
|
81
99
|
// HMR transform below and re-exported because the E8 sniff test imports it from
|
|
@@ -111,6 +129,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
111
129
|
const rangoStart = performance.now();
|
|
112
130
|
const resolvedOptions: RangoOptions = options ?? { preset: "node" };
|
|
113
131
|
const preset = resolvedOptions.preset ?? "node";
|
|
132
|
+
// Before any plugin-rsc instance (this build's, the discovery temp server's)
|
|
133
|
+
// reads the key, and so an invalid key fails the config load.
|
|
134
|
+
configureEncryptionKey(resolvedOptions.encryptionKey);
|
|
114
135
|
const showBanner = resolvedOptions.banner ?? true;
|
|
115
136
|
const clientChunksOption = resolvedOptions.clientChunks ?? true;
|
|
116
137
|
const useBuiltInClientChunks = clientChunksOption === true;
|
|
@@ -467,6 +488,9 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
467
488
|
...(vercelServerEnv ?? {}),
|
|
468
489
|
build: {
|
|
469
490
|
target: SERVER_BUILD_TARGET,
|
|
491
|
+
rollupOptions: {
|
|
492
|
+
preserveEntrySignatures: RSC_ENTRY_SIGNATURES,
|
|
493
|
+
},
|
|
470
494
|
},
|
|
471
495
|
optimizeDeps: {
|
|
472
496
|
entries: [VIRTUAL_IDS.rsc],
|
|
@@ -539,6 +563,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
539
563
|
plugins.push(clientRefDedup());
|
|
540
564
|
}
|
|
541
565
|
plugins.push(clientChunksReport());
|
|
566
|
+
plugins.push(stableRscOutput());
|
|
542
567
|
|
|
543
568
|
plugins.push({
|
|
544
569
|
name: "@rangojs/router:client-component-hmr",
|
|
@@ -583,7 +608,7 @@ export async function rango(options?: RangoOptions): Promise<PluginOption[]> {
|
|
|
583
608
|
const discoveryRouterRef = preset !== "cloudflare" ? routerRef : undefined;
|
|
584
609
|
|
|
585
610
|
if (preset === "cloudflare") {
|
|
586
|
-
plugins.push(
|
|
611
|
+
plugins.push(createEntryBootstrapInjectorPlugin(undefined));
|
|
587
612
|
}
|
|
588
613
|
|
|
589
614
|
plugins.push(createCjsToEsmPlugin());
|