@rangojs/router 0.24.3 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/bin/rango.js +363 -39
- package/dist/testing/vitest.js +37 -4
- package/dist/types/browser/event-controller.d.ts +24 -5
- package/dist/types/browser/intercept-utils.d.ts +5 -2
- package/dist/types/browser/merge-segment-loaders.d.ts +0 -23
- package/dist/types/browser/navigation-transaction.d.ts +5 -5
- package/dist/types/browser/partial-update.d.ts +21 -13
- package/dist/types/browser/prefetch/cache.d.ts +8 -0
- package/dist/types/browser/rango-marker.d.ts +7 -0
- package/dist/types/browser/react/filter-segment-order.d.ts +10 -0
- package/dist/types/browser/react/use-handle.d.ts +20 -0
- package/dist/types/browser/react/use-href.d.ts +6 -0
- package/dist/types/browser/react/use-router.d.ts +6 -1
- package/dist/types/browser/response-adapter.d.ts +5 -3
- package/dist/types/browser/scroll-restoration.d.ts +9 -3
- package/dist/types/browser/segment-reconciler.d.ts +10 -13
- package/dist/types/browser/types.d.ts +38 -8
- package/dist/types/build/route-types/per-module-writer.d.ts +12 -0
- package/dist/types/cache/cf/cf-shell-frame.d.ts +2 -0
- package/dist/types/cache/types.d.ts +8 -0
- package/dist/types/client-urls/client-root.d.ts +4 -1
- package/dist/types/client-urls/client-urls.d.ts +28 -2
- package/dist/types/client-urls/navigation.d.ts +6 -8
- package/dist/types/client-urls/revalidate-registry.d.ts +1 -1
- package/dist/types/client-urls/server-projection.d.ts +20 -5
- package/dist/types/client-urls/types.d.ts +35 -17
- package/dist/types/client.d.ts +2 -2
- package/dist/types/client.rsc.d.ts +2 -2
- package/dist/types/decode-loader-results.d.ts +28 -7
- package/dist/types/href-client.d.ts +3 -1
- package/dist/types/index.rsc.d.ts +1 -1
- package/dist/types/loader-redirect.d.ts +2 -3
- package/dist/types/outlet-context.d.ts +7 -6
- package/dist/types/prefetch-markers.d.ts +14 -5
- package/dist/types/route-content-wrapper.d.ts +17 -14
- package/dist/types/route-definition/helpers-types.d.ts +7 -2
- package/dist/types/route-definition/resolve-handler-use.d.ts +6 -1
- package/dist/types/route-definition/rewrite.d.ts +48 -5
- package/dist/types/route-types.d.ts +2 -2
- package/dist/types/router/handler-context.d.ts +14 -2
- package/dist/types/router/intercept-resolution.d.ts +19 -46
- package/dist/types/router/lazy-includes.d.ts +7 -0
- package/dist/types/router/match-middleware/intercept-resolution.d.ts +2 -2
- package/dist/types/router/middleware.d.ts +0 -16
- package/dist/types/router/navigation-snapshot.d.ts +2 -0
- package/dist/types/router/prefetch-cache-ttl.d.ts +8 -11
- package/dist/types/router/revalidation.d.ts +8 -1
- package/dist/types/router/router-context.d.ts +4 -16
- package/dist/types/router/router-interfaces.d.ts +0 -6
- package/dist/types/router/router-options.d.ts +4 -7
- package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +31 -8
- package/dist/types/router/segment-resolution/revalidation.d.ts +38 -4
- package/dist/types/router/segment-resolution.d.ts +1 -1
- package/dist/types/router/segment-wrappers.d.ts +3 -5
- package/dist/types/router/substitute-pattern-params.d.ts +19 -2
- package/dist/types/router/tracing.d.ts +2 -2
- package/dist/types/rsc/full-payload.d.ts +14 -2
- package/dist/types/rsc/helpers.d.ts +8 -0
- package/dist/types/rsc/manifest-init.d.ts +20 -0
- package/dist/types/rsc/prefetch-render-error.d.ts +22 -0
- package/dist/types/rsc/progressive-enhancement.d.ts +20 -0
- package/dist/types/rsc/rewrite-passes.d.ts +12 -2
- package/dist/types/rsc/server-action.d.ts +6 -0
- package/dist/types/rsc/shell-capture-constants.d.ts +10 -1
- package/dist/types/rsc/shell-capture.d.ts +7 -0
- package/dist/types/rsc/types.d.ts +5 -0
- package/dist/types/segment-system.d.ts +15 -0
- package/dist/types/server/context.d.ts +64 -4
- package/dist/types/server/request-context.d.ts +41 -4
- package/dist/types/server/request-headers.d.ts +12 -0
- package/dist/types/server/rewrite-trail.d.ts +8 -1
- package/dist/types/testing/e2e/index.d.ts +1 -1
- package/dist/types/testing/flight.entry.d.ts +1 -1
- package/dist/types/testing/index.d.ts +1 -1
- package/dist/types/testing/internal/client-urls-projection.d.ts +4 -3
- package/dist/types/testing/render-route.d.ts +21 -11
- package/dist/types/testing/run-loader.d.ts +7 -0
- package/dist/types/testing/run-middleware.d.ts +7 -0
- package/dist/types/testing/run-revalidate.d.ts +5 -4
- package/dist/types/testing/serve-shell-request.d.ts +41 -4
- package/dist/types/testing/shell-status.d.ts +17 -0
- package/dist/types/testing/vitest-stubs/version.d.ts +1 -0
- package/dist/types/testing/vitest.d.ts +10 -1
- package/dist/types/thenable-status.d.ts +0 -6
- package/dist/types/types/handler-context.d.ts +12 -1
- package/dist/types/types/loader-types.d.ts +4 -3
- package/dist/types/types/route-entry.d.ts +2 -1
- package/dist/types/urls/path-helper-types.d.ts +4 -2
- package/dist/types/urls/path-helper.d.ts +5 -0
- package/dist/types/vite/discovery/client-urls-projection.d.ts +55 -5
- package/dist/types/vite/discovery/state.d.ts +20 -0
- package/dist/types/vite/plugins/client-urls-revalidate-hoist.d.ts +28 -16
- package/dist/types/vite/plugins/hoist/source.d.ts +8 -7
- package/dist/types/vite/plugins/virtual-entries.d.ts +6 -0
- package/dist/types/vite/utils/prerender-utils.d.ts +7 -0
- package/dist/vite/index.js +6816 -6547
- package/package.json +1 -1
- package/skills/app-structure/SKILL.md +255 -0
- package/skills/app-structure/content-site.md +333 -0
- package/skills/app-structure/e-commerce.md +435 -0
- package/skills/app-structure/large-app.md +885 -0
- package/skills/app-structure/multi-app.md +280 -0
- package/skills/breadcrumbs/SKILL.md +6 -1
- package/skills/caching/SKILL.md +3 -1
- package/skills/catalog.json +12 -0
- package/skills/client-urls/SKILL.md +195 -32
- package/skills/composability/SKILL.md +10 -8
- package/skills/handler-use/SKILL.md +48 -9
- package/skills/hooks/handle-and-actions.md +104 -0
- package/skills/hooks/navigation.md +24 -10
- package/skills/hooks/urls.md +1 -1
- package/skills/i18n/SKILL.md +2 -1
- package/skills/intercept/SKILL.md +60 -29
- package/skills/layout/SKILL.md +6 -3
- package/skills/links/SKILL.md +151 -17
- package/skills/loader/SKILL.md +32 -10
- package/skills/middleware/SKILL.md +111 -15
- package/skills/observability/SKILL.md +11 -0
- package/skills/parallel/SKILL.md +5 -5
- package/skills/ppr/SKILL.md +43 -8
- package/skills/prerender/SKILL.md +1 -2
- package/skills/rango/SKILL.md +3 -0
- package/skills/response-routes/SKILL.md +4 -1
- package/skills/scripts/SKILL.md +12 -1
- package/skills/server-actions/SKILL.md +60 -20
- package/skills/testing/SKILL.md +1 -0
- package/skills/testing/client-components.md +13 -10
- package/skills/testing/loader.md +25 -24
- package/skills/testing/middleware.md +11 -11
- package/skills/testing/response-routes.md +4 -1
- package/skills/testing/serve-shell-request.md +85 -21
- package/skills/ux-architecture/SKILL.md +980 -0
- package/skills/view-transitions/SKILL.md +43 -10
- package/src/__augment-tests__/augmented.check.ts +28 -0
- package/src/browser/event-controller.ts +44 -18
- package/src/browser/intercept-utils.ts +3 -2
- package/src/browser/merge-segment-loaders.ts +0 -85
- package/src/browser/navigation-bridge.ts +119 -98
- package/src/browser/navigation-client.ts +20 -15
- package/src/browser/navigation-store.ts +4 -2
- package/src/browser/navigation-transaction.ts +9 -8
- package/src/browser/partial-update.ts +90 -32
- package/src/browser/prefetch/cache.ts +8 -0
- package/src/browser/prefetch/fetch.ts +13 -3
- package/src/browser/rango-marker.ts +13 -0
- package/src/browser/react/NavigationProvider.tsx +25 -7
- package/src/browser/react/filter-segment-order.ts +13 -0
- package/src/browser/react/use-action.ts +9 -15
- package/src/browser/react/use-handle.ts +63 -71
- package/src/browser/react/use-href.tsx +24 -5
- package/src/browser/react/use-link-status.ts +1 -1
- package/src/browser/react/use-navigation.ts +30 -40
- package/src/browser/react/use-reverse.ts +4 -17
- package/src/browser/react/use-router.ts +37 -6
- package/src/browser/react/use-segments.ts +8 -12
- package/src/browser/response-adapter.ts +11 -5
- package/src/browser/rsc-router.tsx +3 -1
- package/src/browser/scroll-restoration.ts +34 -20
- package/src/browser/segment-reconciler.ts +11 -29
- package/src/browser/server-action-bridge.ts +52 -16
- package/src/browser/types.ts +40 -8
- package/src/build/generate-manifest.ts +12 -1
- package/src/build/route-types/codegen.ts +6 -2
- package/src/build/route-types/per-module-writer.ts +94 -61
- package/src/cache/cache-runtime.ts +9 -0
- package/src/cache/cache-scope.ts +2 -1
- package/src/cache/cf/cf-cache-store.ts +2 -0
- package/src/cache/cf/cf-shell-frame.ts +3 -0
- package/src/cache/types.ts +8 -0
- package/src/cache/vercel/vercel-cache-store.ts +6 -1
- package/src/client-urls/client-root.tsx +10 -5
- package/src/client-urls/client-urls.ts +246 -166
- package/src/client-urls/navigation.ts +45 -38
- package/src/client-urls/revalidate-registry.ts +12 -3
- package/src/client-urls/server-projection.ts +286 -75
- package/src/client-urls/types.ts +40 -16
- package/src/client.rsc.tsx +11 -1
- package/src/client.tsx +9 -1
- package/src/decode-loader-results.ts +64 -31
- package/src/href-client.ts +3 -1
- package/src/index.rsc.ts +1 -0
- package/src/index.ts +12 -4
- package/src/loader-redirect.tsx +2 -3
- package/src/outlet-context.ts +7 -6
- package/src/prefetch-markers.ts +15 -5
- package/src/reverse.ts +3 -3
- package/src/route-content-wrapper.tsx +19 -17
- package/src/route-definition/dsl-helpers.ts +27 -7
- package/src/route-definition/helpers-types.ts +7 -2
- package/src/route-definition/resolve-handler-use.ts +23 -10
- package/src/route-definition/rewrite.ts +86 -19
- package/src/route-types.ts +1 -2
- package/src/router/find-match.ts +37 -1
- package/src/router/handler-context.ts +85 -40
- package/src/router/intercept-resolution.ts +161 -307
- package/src/router/lazy-includes.ts +43 -27
- package/src/router/loader-resolution.ts +21 -1
- package/src/router/manifest.ts +6 -8
- package/src/router/match-api.ts +11 -1
- package/src/router/match-middleware/background-revalidation.ts +2 -4
- package/src/router/match-middleware/cache-lookup.ts +16 -20
- package/src/router/match-middleware/intercept-resolution.ts +41 -60
- package/src/router/match-result.ts +31 -2
- package/src/router/middleware.ts +6 -147
- package/src/router/navigation-snapshot.ts +38 -2
- package/src/router/prefetch-cache-ttl.ts +10 -18
- package/src/router/prerender-match.ts +2 -1
- package/src/router/revalidation.ts +24 -3
- package/src/router/router-context.ts +5 -18
- package/src/router/router-interfaces.ts +0 -7
- package/src/router/router-options.ts +4 -7
- package/src/router/segment-resolution/fresh.ts +6 -2
- package/src/router/segment-resolution/helpers.ts +7 -1
- package/src/router/segment-resolution/prefetch-deferral.ts +62 -12
- package/src/router/segment-resolution/revalidation.ts +75 -35
- package/src/router/segment-resolution.ts +0 -1
- package/src/router/segment-wrappers.ts +8 -13
- package/src/router/substitute-pattern-params.ts +37 -2
- package/src/router/tracing.ts +2 -2
- package/src/router.ts +2 -9
- package/src/rsc/full-payload.ts +26 -4
- package/src/rsc/handler.ts +83 -41
- package/src/rsc/helpers.ts +13 -0
- package/src/rsc/manifest-init.ts +56 -3
- package/src/rsc/prefetch-render-error.ts +38 -0
- package/src/rsc/progressive-enhancement.ts +161 -211
- package/src/rsc/rewrite-passes.ts +56 -9
- package/src/rsc/rsc-rendering.ts +79 -23
- package/src/rsc/server-action.ts +25 -2
- package/src/rsc/shell-capture-constants.ts +22 -0
- package/src/rsc/shell-capture.ts +11 -0
- package/src/rsc/types.ts +5 -0
- package/src/segment-system.tsx +125 -119
- package/src/server/context.ts +96 -5
- package/src/server/handle-store.ts +3 -2
- package/src/server/request-context.ts +42 -3
- package/src/server/request-headers.ts +32 -0
- package/src/server/rewrite-trail.ts +55 -9
- package/src/ssr/ssr-root.tsx +6 -10
- package/src/testing/dispatch.ts +4 -5
- package/src/testing/e2e/index.ts +1 -0
- package/src/testing/flight.entry.ts +1 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/internal/client-urls-projection.ts +31 -11
- package/src/testing/render-route.tsx +83 -40
- package/src/testing/run-loader.ts +26 -2
- package/src/testing/run-middleware.ts +10 -0
- package/src/testing/run-revalidate.ts +13 -6
- package/src/testing/serve-shell-request.ts +77 -4
- package/src/testing/shell-status.ts +40 -0
- package/src/testing/vitest-stubs/version.ts +1 -0
- package/src/testing/vitest.ts +74 -7
- package/src/thenable-status.ts +0 -11
- package/src/types/handler-context.ts +12 -1
- package/src/types/loader-types.ts +4 -3
- package/src/types/route-entry.ts +2 -1
- package/src/urls/include-helper.ts +38 -11
- package/src/urls/path-helper-types.ts +4 -2
- package/src/urls/path-helper.ts +16 -3
- package/src/vite/discovery/client-urls-projection.ts +205 -16
- package/src/vite/discovery/discover-routers.ts +2 -2
- package/src/vite/discovery/prerender-collection.ts +2 -6
- package/src/vite/discovery/state.ts +26 -0
- package/src/vite/plugins/client-urls-revalidate-hoist.ts +190 -77
- package/src/vite/plugins/expose-internal-ids.ts +46 -40
- package/src/vite/plugins/hoist/source.ts +8 -7
- package/src/vite/plugins/transition-when-hoist.ts +1 -0
- package/src/vite/plugins/version-plugin.ts +7 -0
- package/src/vite/plugins/version.d.ts +7 -0
- package/src/vite/plugins/virtual-entries.ts +20 -0
- package/src/vite/rango.ts +4 -1
- package/src/vite/router-discovery.ts +39 -7
- package/src/vite/utils/prerender-utils.ts +17 -0
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import type { Plugin } from "vite";
|
|
1
|
+
import type { EnvironmentModuleNode, Plugin } from "vite";
|
|
2
2
|
import { normalizePath, parseAst } from "vite";
|
|
3
3
|
import MagicString from "magic-string";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { relative } from "node:path";
|
|
6
6
|
import { hasDirective } from "@vitejs/plugin-rsc/transforms";
|
|
7
7
|
import { HOISTED_REVALIDATE_KEY } from "../../client-urls/hoisted-revalidate.js";
|
|
8
|
+
import {
|
|
9
|
+
CLIENT_IMPORT_RE,
|
|
10
|
+
CLIENT_URLS_REVALIDATE_QUERY,
|
|
11
|
+
componentUseSignature,
|
|
12
|
+
hoistedRevalidateId,
|
|
13
|
+
} from "../discovery/client-urls-projection.js";
|
|
14
|
+
import type { ClientUrlRevalidateIndex } from "../discovery/state.js";
|
|
8
15
|
import { hasUseClientDirective } from "../utils/directive-prologue.js";
|
|
9
16
|
import { offsetToLineColumn } from "./expose-ids/export-analysis.js";
|
|
10
17
|
import {
|
|
@@ -31,13 +38,15 @@ import {
|
|
|
31
38
|
resolveSourceTarget,
|
|
32
39
|
SOURCE_FILE_RE,
|
|
33
40
|
type EmittedEntry,
|
|
41
|
+
type SourceResolver,
|
|
34
42
|
} from "./hoist/source.js";
|
|
35
43
|
|
|
36
44
|
/**
|
|
37
45
|
* clientUrls() loader `revalidate()` runs on the server, with the arguments a
|
|
38
|
-
* urls() loader's predicate gets. The predicate is declared in a
|
|
39
|
-
* "use client"
|
|
40
|
-
* reverse of
|
|
46
|
+
* urls() loader's predicate gets. The predicate is declared in client code (a
|
|
47
|
+
* "use client" group, or a component's `.use` in any module the group
|
|
48
|
+
* imports), so the build moves it into a server module (the reverse of
|
|
49
|
+
* transition-when-hoist.ts):
|
|
41
50
|
*
|
|
42
51
|
* loader(CartLoader, () => [
|
|
43
52
|
* revalidate((ctx) => ctx.isAction(Cart) ? ctx.actionResult?.ok : undefined),
|
|
@@ -56,31 +65,47 @@ import {
|
|
|
56
65
|
*
|
|
57
66
|
* plugin-rsc replaces the RSC copy of a "use client" module with client
|
|
58
67
|
* reference proxies and drops everything else, so a post transform appends
|
|
59
|
-
* `import "<file>?rango-revalidate"` to the proxy
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
68
|
+
* `import "<file>?rango-revalidate"` to the proxy of every group (a
|
|
69
|
+
* "use client" module calling clientUrls()). The proxy has none of the
|
|
70
|
+
* group's imports, and a component's `.use` may sit in any module the group
|
|
71
|
+
* reaches. Route discovery serializes the group's SSR copy, so its projection
|
|
72
|
+
* carries every key the group reads, and the transform records each key's
|
|
73
|
+
* file in every environment (ClientUrlRevalidateIndex): discovery assigns
|
|
74
|
+
* the group the files of its keys as it installs the projection
|
|
75
|
+
* (discovery/client-urls-projection.ts), and the group's `?rango-revalidate`
|
|
76
|
+
* module imports theirs. Their registrations load with the group and nothing
|
|
77
|
+
* else of those files does, so no client code loads on the server and a lazy
|
|
78
|
+
* include stays lazy, wherever the file sits: behind barrels or in another
|
|
79
|
+
* workspace package. Materialization
|
|
80
|
+
* (client-urls/server-projection.ts) attaches the registered predicates to
|
|
81
|
+
* the loader stubs; a key nothing registered fails loudly there.
|
|
64
82
|
*
|
|
65
83
|
* A key hashes the project-relative file and the predicate's syntax tree
|
|
66
84
|
* (formatting, comments and TypeScript excluded, so a re-printing transform
|
|
67
85
|
* in one environment keeps it): two environments that saw a different
|
|
68
86
|
* predicate fail loudly at materialization instead of pairing a loader with
|
|
69
|
-
* the wrong one.
|
|
87
|
+
* the wrong one. A module several groups import registers once.
|
|
88
|
+
*
|
|
89
|
+
* Keyed on calls of the `revalidate` helper from "@rangojs/router/client":
|
|
90
|
+
* imported directly (a component's `.use`), or handed out by a clientUrls()
|
|
91
|
+
* builder callback (destructured, renamed, or as `helpers.revalidate`). The
|
|
92
|
+
* argument may reference imports and globals only: a binding of the module
|
|
93
|
+
* or of an enclosing function, `this`/`arguments`/`super`/`new.target`,
|
|
94
|
+
* `import()`, `import.meta` other than `import.meta.env`, a browser-only
|
|
95
|
+
* global, an `async` or generator function, or an import of a "use client"
|
|
96
|
+
* module is a LOUD error naming file:line. Imports stay in the client module
|
|
97
|
+
* too (they are not pruned). Vitest does not run the plugin, so in unit
|
|
98
|
+
* tests the predicate stays a plain function.
|
|
70
99
|
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* `
|
|
78
|
-
* LOUD error naming file:line. Imports stay in the "use client" module too
|
|
79
|
-
* (they are not pruned). Vitest does not run the plugin, so in unit tests the
|
|
80
|
-
* predicate stays a plain function.
|
|
100
|
+
* `revalidate(true)` / `revalidate(false)` LITERALS stay in place: the
|
|
101
|
+
* projection carries the boolean and materialization turns it into the
|
|
102
|
+
* constant predicate. Any other argument is hoisted whatever it evaluates
|
|
103
|
+
* to, because an imported boolean and an imported predicate are both
|
|
104
|
+
* identifiers to the build: the server evaluates the expression, and a
|
|
105
|
+
* boolean result means the same constant answer (`revalidate(FLAG)` with an
|
|
106
|
+
* imported `FLAG`). Materialization rejects a value that is neither.
|
|
81
107
|
*/
|
|
82
108
|
|
|
83
|
-
const CLIENT_URLS_REVALIDATE_QUERY = "rango-revalidate";
|
|
84
109
|
const REGISTER = "__rango_registerClientUrlRevalidators";
|
|
85
110
|
|
|
86
111
|
const CLIENT_SOURCES: ReadonlySet<string> = new Set(["@rangojs/router/client"]);
|
|
@@ -120,19 +145,24 @@ const CAPTURE_MESSAGES: LexicalCaptureMessages = {
|
|
|
120
145
|
"loads a module at run time, which the build cannot check is server-safe.",
|
|
121
146
|
};
|
|
122
147
|
|
|
123
|
-
// Cheap pre-
|
|
124
|
-
//
|
|
125
|
-
//
|
|
148
|
+
// Cheap pre-filters: a site imports the router's client entry and names a
|
|
149
|
+
// `revalidate` helper; a group also names clientUrls. The AST walk is the
|
|
150
|
+
// authority.
|
|
126
151
|
const CLIENT_URLS_RE = /\bclientUrls\b/;
|
|
127
|
-
const CLIENT_IMPORT_RE = /["']@rangojs\/router\/client["']/;
|
|
128
152
|
const REVALIDATE_RE = /\brevalidate\b/;
|
|
153
|
+
const CANDIDATE_RE = /\b(?:clientUrls|revalidate)\b/;
|
|
129
154
|
|
|
130
155
|
function mayHoist(code: string): boolean {
|
|
156
|
+
return CLIENT_IMPORT_RE.test(code) && REVALIDATE_RE.test(code);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** A clientUrls() group: its RSC proxy imports the registrations. */
|
|
160
|
+
function isGroupModule(code: string): boolean {
|
|
131
161
|
return (
|
|
132
162
|
code.includes("use client") &&
|
|
133
163
|
CLIENT_URLS_RE.test(code) &&
|
|
134
164
|
CLIENT_IMPORT_RE.test(code) &&
|
|
135
|
-
|
|
165
|
+
hasUseClientDirective(code)
|
|
136
166
|
);
|
|
137
167
|
}
|
|
138
168
|
|
|
@@ -253,9 +283,9 @@ interface HoistClientUrlsRevalidateResult {
|
|
|
253
283
|
}
|
|
254
284
|
|
|
255
285
|
/**
|
|
256
|
-
* Hoist every clientUrls() `revalidate()` predicate of a
|
|
257
|
-
*
|
|
258
|
-
* predicate that is not pure.
|
|
286
|
+
* Hoist every clientUrls() `revalidate()` predicate of a module. Returns null
|
|
287
|
+
* when there is none (boolean literals stay in place). Throws, naming
|
|
288
|
+
* file:line, for a predicate that is not pure.
|
|
259
289
|
*/
|
|
260
290
|
export async function hoistClientUrlsRevalidates(
|
|
261
291
|
code: string,
|
|
@@ -264,21 +294,15 @@ export async function hoistClientUrlsRevalidates(
|
|
|
264
294
|
): Promise<HoistClientUrlsRevalidateResult | null> {
|
|
265
295
|
if (!mayHoist(code)) return null;
|
|
266
296
|
const file = normalizePath(id.split("?", 1)[0]!);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
program = parseAst(code, { lang: parseLang(file) });
|
|
270
|
-
} catch {
|
|
271
|
-
return null;
|
|
272
|
-
}
|
|
273
|
-
if (!hasDirective(program.body, "use client")) return null;
|
|
274
|
-
|
|
297
|
+
const program = parseProgram(code, file);
|
|
298
|
+
if (!program) return null;
|
|
275
299
|
const { moduleScope, references, scopeOf } = analyzeScopes(program);
|
|
276
300
|
const imports = collectImports(program);
|
|
277
301
|
const calls = findHelperCalls(program, scopeOf, moduleScope, imports, {
|
|
278
302
|
sources: CLIENT_SOURCES,
|
|
279
303
|
builder: "clientUrls",
|
|
280
304
|
helper: "revalidate",
|
|
281
|
-
directImport:
|
|
305
|
+
directImport: true,
|
|
282
306
|
});
|
|
283
307
|
if (calls.length === 0) return null;
|
|
284
308
|
|
|
@@ -294,16 +318,18 @@ export async function hoistClientUrlsRevalidates(
|
|
|
294
318
|
file,
|
|
295
319
|
code,
|
|
296
320
|
call,
|
|
297
|
-
"`revalidate()` takes exactly one predicate.",
|
|
321
|
+
"`revalidate()` takes exactly one predicate or boolean.",
|
|
298
322
|
);
|
|
299
323
|
}
|
|
300
324
|
const value = unwrapExpression(arg);
|
|
325
|
+
// The same constant in every environment: nothing to move.
|
|
326
|
+
if (value.type === "Literal" && typeof value.value === "boolean") continue;
|
|
301
327
|
if (NOT_A_FUNCTION.has(value.type)) {
|
|
302
328
|
throw revalidateError(
|
|
303
329
|
file,
|
|
304
330
|
code,
|
|
305
331
|
value,
|
|
306
|
-
"`revalidate()` expects a predicate function.",
|
|
332
|
+
"`revalidate()` expects a predicate function or a boolean.",
|
|
307
333
|
);
|
|
308
334
|
}
|
|
309
335
|
if (isFunctionLiteral(value) && (value.async || value.generator)) {
|
|
@@ -336,9 +362,12 @@ export async function hoistClientUrlsRevalidates(
|
|
|
336
362
|
code,
|
|
337
363
|
binding.node,
|
|
338
364
|
binding.scope.lookup(name) === moduleScope
|
|
339
|
-
? `\`${name}\` is declared in this
|
|
340
|
-
|
|
341
|
-
|
|
365
|
+
? `\`${name}\` is declared in this ` +
|
|
366
|
+
(hasDirective(program.body, "use client")
|
|
367
|
+
? '"use client" module'
|
|
368
|
+
: "module") +
|
|
369
|
+
". Move the predicate to its own module (without " +
|
|
370
|
+
'"use client") and import it, or write it inline.'
|
|
342
371
|
: `\`${name}\` is a binding of the enclosing function. Read what ` +
|
|
343
372
|
"you need from the predicate's argument (`currentParams`, " +
|
|
344
373
|
"`nextUrl`, `context`, `actionResult`, ...).",
|
|
@@ -391,6 +420,8 @@ export async function hoistClientUrlsRevalidates(
|
|
|
391
420
|
);
|
|
392
421
|
}
|
|
393
422
|
|
|
423
|
+
if (entries.size === 0) return null;
|
|
424
|
+
|
|
394
425
|
const importLines = await emitImports(used, imports, () => {});
|
|
395
426
|
const module = [
|
|
396
427
|
`import { registerClientUrlRevalidators as ${REGISTER} } from "@rangojs/router/server";`,
|
|
@@ -421,6 +452,14 @@ async function isClientOnly(
|
|
|
421
452
|
);
|
|
422
453
|
}
|
|
423
454
|
|
|
455
|
+
function parseProgram(code: string, file: string): Node | null {
|
|
456
|
+
try {
|
|
457
|
+
return parseAst(code, { lang: parseLang(file) });
|
|
458
|
+
} catch {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
424
463
|
/** The file a `?rango-revalidate` id names, or null. */
|
|
425
464
|
export function parseHoistedRevalidateId(id: string): string | null {
|
|
426
465
|
const q = id.indexOf("?");
|
|
@@ -436,27 +475,43 @@ const HOISTED_ID_RE = new RegExp(
|
|
|
436
475
|
);
|
|
437
476
|
const SOURCE_ID_RE = /\.[cm]?[jt]sx?(?:\?|$)/;
|
|
438
477
|
const NODE_MODULES_RE = /\/node_modules\//;
|
|
478
|
+
const USE_ASSIGNMENT_RE = /\.use\s*=/;
|
|
439
479
|
|
|
440
480
|
/**
|
|
441
481
|
* The plugins: a pre transform that hoists in every environment (markers in
|
|
442
|
-
* the client and SSR copies,
|
|
443
|
-
*
|
|
444
|
-
* appends its import to the RSC
|
|
482
|
+
* the client and SSR copies, each key's file in `index`, the server module
|
|
483
|
+
* recorded from the RSC transform, the groups noted) and serves
|
|
484
|
+
* `?rango-revalidate`, a post transform that appends its import to the RSC
|
|
485
|
+
* client-reference proxy of each group, and in dev the client's `.use`
|
|
486
|
+
* update propagation. Pass one `index` to every instance of one rango():
|
|
487
|
+
* discovery's temp server records keys the dev server or build reads.
|
|
488
|
+
*
|
|
489
|
+
* `load` serves the registrations the RSC transform emitted, which hoisted
|
|
490
|
+
* the pipeline code; the disk source is re-hoisted when the transform has not
|
|
491
|
+
* seen the current file (loadEmittedOrDisk), which is always the case for a
|
|
492
|
+
* component module: the RSC environment never transforms a module only a
|
|
493
|
+
* group imports. A group's module also imports the registrations of the
|
|
494
|
+
* files discovery assigned it. A file with neither serves an empty module.
|
|
445
495
|
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
496
|
+
* A component module that exports only components is a Fast Refresh
|
|
497
|
+
* boundary, so a `.use` edit would leave the browser's group records stale
|
|
498
|
+
* (the group never re-evaluates). In dev, an update that changes a module's
|
|
499
|
+
* componentUseSignature also updates its importers, as a group edit does;
|
|
500
|
+
* any other edit keeps Fast Refresh.
|
|
450
501
|
*
|
|
451
|
-
* The transform's code filter skips a module that
|
|
452
|
-
* so a file that stops doing so would keep its `emitted`
|
|
453
|
-
* drops it,
|
|
454
|
-
* dependency (isClientModule memoizes per resolved
|
|
455
|
-
* it).
|
|
502
|
+
* The transform's code filter skips a module that names neither clientUrls
|
|
503
|
+
* nor revalidate, so a file that stops doing so would keep its `emitted`
|
|
504
|
+
* entry: watchChange drops it, its group mark, and the cached "use client"
|
|
505
|
+
* answer for an edited dependency (isClientModule memoizes per resolved
|
|
506
|
+
* file; buildStart resets it).
|
|
456
507
|
*/
|
|
457
|
-
export function clientUrlsRevalidateHoistPlugin(
|
|
508
|
+
export function clientUrlsRevalidateHoistPlugin(
|
|
509
|
+
index: ClientUrlRevalidateIndex,
|
|
510
|
+
): Plugin[] {
|
|
458
511
|
const emitted = new Map<string, EmittedEntry<string>>();
|
|
512
|
+
const groups = new Set<string>();
|
|
459
513
|
const clientModules = new Map<string, Promise<boolean>>();
|
|
514
|
+
const useSignatures = new Map<string, string>();
|
|
460
515
|
let root = process.cwd();
|
|
461
516
|
|
|
462
517
|
const isClientFile = (file: string): Promise<boolean> => {
|
|
@@ -472,6 +527,14 @@ export function clientUrlsRevalidateHoistPlugin(): Plugin[] {
|
|
|
472
527
|
}
|
|
473
528
|
return known;
|
|
474
529
|
};
|
|
530
|
+
const clientModuleCheck =
|
|
531
|
+
(ctx: SourceResolver, importer: string) =>
|
|
532
|
+
async (source: string): Promise<boolean> => {
|
|
533
|
+
const target = await resolveSourceTarget(ctx, source, importer, {
|
|
534
|
+
skipNodeModules: false,
|
|
535
|
+
});
|
|
536
|
+
return target !== null && (await isClientFile(target));
|
|
537
|
+
};
|
|
475
538
|
|
|
476
539
|
return [
|
|
477
540
|
{
|
|
@@ -479,7 +542,7 @@ export function clientUrlsRevalidateHoistPlugin(): Plugin[] {
|
|
|
479
542
|
enforce: "pre",
|
|
480
543
|
|
|
481
544
|
configResolved(config) {
|
|
482
|
-
root = config.root;
|
|
545
|
+
root = normalizePath(config.root);
|
|
483
546
|
},
|
|
484
547
|
|
|
485
548
|
buildStart() {
|
|
@@ -490,6 +553,7 @@ export function clientUrlsRevalidateHoistPlugin(): Plugin[] {
|
|
|
490
553
|
const file = normalizePath(id);
|
|
491
554
|
clientModules.delete(file);
|
|
492
555
|
emitted.delete(file);
|
|
556
|
+
groups.delete(file);
|
|
493
557
|
},
|
|
494
558
|
|
|
495
559
|
load: {
|
|
@@ -497,14 +561,34 @@ export function clientUrlsRevalidateHoistPlugin(): Plugin[] {
|
|
|
497
561
|
async handler(id) {
|
|
498
562
|
const hoistedFile = parseHoistedRevalidateId(id);
|
|
499
563
|
if (hoistedFile === null) return;
|
|
500
|
-
const
|
|
564
|
+
const file = normalizePath(hoistedFile);
|
|
565
|
+
const registrations = await loadEmittedOrDisk(
|
|
501
566
|
emitted,
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
567
|
+
file,
|
|
568
|
+
await readSource(file),
|
|
569
|
+
async (source) =>
|
|
570
|
+
(
|
|
571
|
+
await hoistClientUrlsRevalidates(source, file, {
|
|
572
|
+
root,
|
|
573
|
+
isClientModule: clientModuleCheck(this, file),
|
|
574
|
+
})
|
|
575
|
+
)?.module,
|
|
506
576
|
);
|
|
507
|
-
|
|
577
|
+
const assigned = index.filesByGroup.get(file) ?? [];
|
|
578
|
+
const code =
|
|
579
|
+
registrations === undefined && assigned.length === 0
|
|
580
|
+
? "export {};\n"
|
|
581
|
+
: [
|
|
582
|
+
registrations ?? "",
|
|
583
|
+
...assigned.map(
|
|
584
|
+
(target) =>
|
|
585
|
+
`import ${JSON.stringify(hoistedRevalidateId(target))};\n`,
|
|
586
|
+
),
|
|
587
|
+
].join("");
|
|
588
|
+
// Reached only through bare imports, and the id names an app file,
|
|
589
|
+
// so the app's package.json `"sideEffects": false` would let the
|
|
590
|
+
// build drop the registrations (#1149). load outranks that field.
|
|
591
|
+
return { code, moduleSideEffects: "no-treeshake" };
|
|
508
592
|
},
|
|
509
593
|
},
|
|
510
594
|
|
|
@@ -514,7 +598,7 @@ export function clientUrlsRevalidateHoistPlugin(): Plugin[] {
|
|
|
514
598
|
include: SOURCE_ID_RE,
|
|
515
599
|
exclude: [NODE_MODULES_RE, HOISTED_ID_RE],
|
|
516
600
|
},
|
|
517
|
-
code:
|
|
601
|
+
code: CANDIDATE_RE,
|
|
518
602
|
},
|
|
519
603
|
async handler(code, id) {
|
|
520
604
|
if (id.includes("/node_modules/") || parseHoistedRevalidateId(id)) {
|
|
@@ -523,19 +607,17 @@ export function clientUrlsRevalidateHoistPlugin(): Plugin[] {
|
|
|
523
607
|
const file = normalizePath(id.split("?", 1)[0]!);
|
|
524
608
|
if (!SOURCE_FILE_RE.test(file)) return;
|
|
525
609
|
const rsc = this.environment?.name === "rsc";
|
|
526
|
-
if (rsc)
|
|
610
|
+
if (rsc) {
|
|
611
|
+
emitted.delete(file);
|
|
612
|
+
if (isGroupModule(code)) groups.add(file);
|
|
613
|
+
else groups.delete(file);
|
|
614
|
+
}
|
|
527
615
|
const result = await hoistClientUrlsRevalidates(code, id, {
|
|
528
616
|
root,
|
|
529
|
-
isClientModule: rsc
|
|
530
|
-
? async (source) => {
|
|
531
|
-
const target = await resolveSourceTarget(this, source, id, {
|
|
532
|
-
skipNodeModules: false,
|
|
533
|
-
});
|
|
534
|
-
return target !== null && (await isClientFile(target));
|
|
535
|
-
}
|
|
536
|
-
: undefined,
|
|
617
|
+
isClientModule: rsc ? clientModuleCheck(this, id) : undefined,
|
|
537
618
|
});
|
|
538
619
|
if (!result) return;
|
|
620
|
+
for (const key of result.keys) index.fileByKey.set(key, file);
|
|
539
621
|
if (rsc) await recordEmitted(emitted, file, result.module);
|
|
540
622
|
return { code: result.code, map: result.map };
|
|
541
623
|
},
|
|
@@ -551,14 +633,45 @@ export function clientUrlsRevalidateHoistPlugin(): Plugin[] {
|
|
|
551
633
|
handler(code, id) {
|
|
552
634
|
if (parseHoistedRevalidateId(id)) return;
|
|
553
635
|
const file = normalizePath(id.split("?", 1)[0]!);
|
|
554
|
-
if (!
|
|
636
|
+
if (!groups.has(file)) return;
|
|
555
637
|
const s = new MagicString(code);
|
|
556
|
-
s.append(
|
|
557
|
-
`\nimport ${JSON.stringify(`${file}?${CLIENT_URLS_REVALIDATE_QUERY}`)};\n`,
|
|
558
|
-
);
|
|
638
|
+
s.append(`\nimport ${JSON.stringify(hoistedRevalidateId(file))};\n`);
|
|
559
639
|
return { code: s.toString(), map: s.generateMap({ hires: true }) };
|
|
560
640
|
},
|
|
561
641
|
},
|
|
562
642
|
},
|
|
643
|
+
{
|
|
644
|
+
name: "@rangojs/router:client-urls-component-use-hmr",
|
|
645
|
+
apply: "serve",
|
|
646
|
+
applyToEnvironment: (env) => env.name === "client",
|
|
647
|
+
|
|
648
|
+
transform: {
|
|
649
|
+
filter: {
|
|
650
|
+
id: { include: SOURCE_ID_RE, exclude: [NODE_MODULES_RE] },
|
|
651
|
+
code: USE_ASSIGNMENT_RE,
|
|
652
|
+
},
|
|
653
|
+
async handler(_code, id) {
|
|
654
|
+
// The disk source, as hotUpdate reads it: an earlier transform may
|
|
655
|
+
// re-print the module.
|
|
656
|
+
const file = normalizePath(id.split("?", 1)[0]!);
|
|
657
|
+
const disk = await readSource(file);
|
|
658
|
+
const signature = disk && componentUseSignature(disk, file);
|
|
659
|
+
if (signature) useSignatures.set(file, signature);
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
|
|
663
|
+
async hotUpdate({ file, modules, read }) {
|
|
664
|
+
if (modules.length === 0 || !SOURCE_FILE_RE.test(file)) return;
|
|
665
|
+
const next = componentUseSignature(await read(), file);
|
|
666
|
+
if (next === useSignatures.get(file)) return;
|
|
667
|
+
if (next === undefined) useSignatures.delete(file);
|
|
668
|
+
else useSignatures.set(file, next);
|
|
669
|
+
const updated = new Set<EnvironmentModuleNode>(modules);
|
|
670
|
+
for (const mod of modules) {
|
|
671
|
+
for (const importer of mod.importers) updated.add(importer);
|
|
672
|
+
}
|
|
673
|
+
return [...updated];
|
|
674
|
+
},
|
|
675
|
+
},
|
|
563
676
|
];
|
|
564
677
|
}
|
|
@@ -187,6 +187,49 @@ export function exposeInternalIds(options?: { forceBuild?: boolean }): Plugin {
|
|
|
187
187
|
|
|
188
188
|
const counter = createCounter(debug, "expose-internal-ids");
|
|
189
189
|
|
|
190
|
+
/** The virtual:rsc-router/loader-manifest module. */
|
|
191
|
+
function loaderManifestCode(): string {
|
|
192
|
+
if (!isBuild) {
|
|
193
|
+
return `import { setLoaderImports } from "@rangojs/router/server";
|
|
194
|
+
|
|
195
|
+
// Dev mode: empty map, loaders are resolved dynamically via path parsing
|
|
196
|
+
setLoaderImports({});
|
|
197
|
+
`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Build mode: generate lazy import map. Sorted by id: the registry fills
|
|
201
|
+
// in directory-scan order (the pre-scan below) and transform order, both
|
|
202
|
+
// of which vary between machines and runs, and this module's bytes feed
|
|
203
|
+
// the cache version of every router bundled with it
|
|
204
|
+
// (discovery/build-versions.ts).
|
|
205
|
+
const lazyImports: string[] = [];
|
|
206
|
+
const sortedLoaders = [...loaderRegistry].sort(([a], [b]) =>
|
|
207
|
+
compareStrings(a, b),
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
for (const [hashedId, { filePath, exportName }] of sortedLoaders) {
|
|
211
|
+
lazyImports.push(
|
|
212
|
+
` "${hashedId}": () => import("/${filePath}").then(m => m.${exportName})`,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (lazyImports.length === 0) {
|
|
217
|
+
return `import { setLoaderImports } from "@rangojs/router/server";
|
|
218
|
+
|
|
219
|
+
// No fetchable loaders discovered during build
|
|
220
|
+
setLoaderImports({});
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return `import { setLoaderImports } from "@rangojs/router/server";
|
|
225
|
+
|
|
226
|
+
// Lazy import map - loaders are loaded on-demand when first requested
|
|
227
|
+
setLoaderImports({
|
|
228
|
+
${lazyImports.join(",\n")}
|
|
229
|
+
});
|
|
230
|
+
`;
|
|
231
|
+
}
|
|
232
|
+
|
|
190
233
|
return {
|
|
191
234
|
name: "@rangojs/router:expose-internal-ids",
|
|
192
235
|
enforce: "post",
|
|
@@ -239,46 +282,9 @@ export function exposeInternalIds(options?: { forceBuild?: boolean }): Plugin {
|
|
|
239
282
|
}
|
|
240
283
|
|
|
241
284
|
if (id !== RESOLVED_VIRTUAL_LOADER_MANIFEST) return;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// Dev mode: empty map, loaders are resolved dynamically via path parsing
|
|
247
|
-
setLoaderImports({});
|
|
248
|
-
`;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Build mode: generate lazy import map. Sorted by id: the registry fills
|
|
252
|
-
// in directory-scan order (the pre-scan below) and transform order, both
|
|
253
|
-
// of which vary between machines and runs, and this module's bytes feed
|
|
254
|
-
// the cache version of every router bundled with it
|
|
255
|
-
// (discovery/build-versions.ts).
|
|
256
|
-
const lazyImports: string[] = [];
|
|
257
|
-
const sortedLoaders = [...loaderRegistry].sort(([a], [b]) =>
|
|
258
|
-
compareStrings(a, b),
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
for (const [hashedId, { filePath, exportName }] of sortedLoaders) {
|
|
262
|
-
lazyImports.push(
|
|
263
|
-
` "${hashedId}": () => import("/${filePath}").then(m => m.${exportName})`,
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (lazyImports.length === 0) {
|
|
268
|
-
return `import { setLoaderImports } from "@rangojs/router/server";
|
|
269
|
-
|
|
270
|
-
// No fetchable loaders discovered during build
|
|
271
|
-
setLoaderImports({});
|
|
272
|
-
`;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return `import { setLoaderImports } from "@rangojs/router/server";
|
|
276
|
-
|
|
277
|
-
// Lazy import map - loaders are loaded on-demand when first requested
|
|
278
|
-
setLoaderImports({
|
|
279
|
-
${lazyImports.join(",\n")}
|
|
280
|
-
});
|
|
281
|
-
`;
|
|
285
|
+
// Only ever a bare import (the RSC entry's), so a build whose
|
|
286
|
+
// treeshake.moduleSideEffects is false would drop it; load outranks it.
|
|
287
|
+
return { code: loaderManifestCode(), moduleSideEffects: "no-treeshake" };
|
|
282
288
|
},
|
|
283
289
|
|
|
284
290
|
// --------------- Loader pre-scan (build mode) ---------------
|
|
@@ -65,19 +65,20 @@ export async function recordEmitted<T>(
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
|
-
* What a `?rango-*` load serves for `hoistedFile
|
|
69
|
-
* when it saw
|
|
70
|
-
* `rehoist(disk)`. The transform hoists the pipeline
|
|
71
|
-
* plugin may have changed, so re-hoisting the disk
|
|
72
|
-
* for an environment loading before the RSC
|
|
73
|
-
* RSC environment has not re-transformed
|
|
68
|
+
* What a `?rango-*` load serves for `hoistedFile`, whose source on disk is
|
|
69
|
+
* `disk` (readSource): the transform's emission when it saw that source (or
|
|
70
|
+
* the file is gone), else `rehoist(disk)`. The transform hoists the pipeline
|
|
71
|
+
* code, which an earlier plugin may have changed, so re-hoisting the disk
|
|
72
|
+
* source is the fallback only for an environment loading before the RSC
|
|
73
|
+
* transform ran or for an edit the RSC environment has not re-transformed
|
|
74
|
+
* yet. Undefined when neither exists.
|
|
74
75
|
*/
|
|
75
76
|
export async function loadEmittedOrDisk<T>(
|
|
76
77
|
emitted: ReadonlyMap<string, EmittedEntry<T>>,
|
|
77
78
|
hoistedFile: string,
|
|
79
|
+
disk: string | null,
|
|
78
80
|
rehoist: (disk: string) => Promise<T | undefined>,
|
|
79
81
|
): Promise<T | undefined> {
|
|
80
|
-
const disk = await readSource(hoistedFile);
|
|
81
82
|
const entry = emitted.get(normalizePath(hoistedFile));
|
|
82
83
|
if (entry && (disk === null || entry.disk === disk)) return entry.value;
|
|
83
84
|
return disk === null ? undefined : rehoist(disk);
|
|
@@ -362,6 +362,7 @@ export function transitionWhenHoistPlugin(): Plugin {
|
|
|
362
362
|
const modules = await loadEmittedOrDisk(
|
|
363
363
|
emitted,
|
|
364
364
|
hoisted.file,
|
|
365
|
+
await readSource(hoisted.file),
|
|
365
366
|
async (disk) =>
|
|
366
367
|
(await hoistTransitionWhens(disk, hoisted.file))?.modules,
|
|
367
368
|
);
|
|
@@ -2,6 +2,7 @@ import { parseAst, type Plugin } from "vite";
|
|
|
2
2
|
import {
|
|
3
3
|
VIRTUAL_IDS,
|
|
4
4
|
getVirtualBuildVersionContent,
|
|
5
|
+
getVirtualPackageVersionContent,
|
|
5
6
|
getVirtualVersionContent,
|
|
6
7
|
} from "./virtual-entries.js";
|
|
7
8
|
import { hasUseClientDirective } from "../utils/directive-prologue.js";
|
|
@@ -170,6 +171,12 @@ export function createVersionPlugin(): Plugin {
|
|
|
170
171
|
|
|
171
172
|
load(id) {
|
|
172
173
|
if (id === "\0" + VIRTUAL_IDS.version) {
|
|
174
|
+
const environment = this?.environment?.name;
|
|
175
|
+
// The browser gets PACKAGE_VERSION only (ROUTER_VERSIONS is filled in
|
|
176
|
+
// server chunks); every other environment keeps the full module.
|
|
177
|
+
if (environment === "client") {
|
|
178
|
+
return getVirtualPackageVersionContent();
|
|
179
|
+
}
|
|
173
180
|
return isDev
|
|
174
181
|
? getVirtualVersionContent(currentVersion)
|
|
175
182
|
: getVirtualBuildVersionContent();
|
|
@@ -16,6 +16,13 @@ declare module "@rangojs/router:version" {
|
|
|
16
16
|
*/
|
|
17
17
|
export const VERSION: string;
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The npm semver of @rangojs/router (`1.2.3`). Informational: the browser
|
|
21
|
+
* entry publishes it as `window.__rango`. Every environment exports it; only
|
|
22
|
+
* the RSC environment also exports `VERSION` and `ROUTER_VERSIONS`.
|
|
23
|
+
*/
|
|
24
|
+
export const PACKAGE_VERSION: string;
|
|
25
|
+
|
|
19
26
|
/**
|
|
20
27
|
* Per-router cache versions computed at build time: router id to
|
|
21
28
|
* `[data, document]`, with `"*"` holding the whole-build pair.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HeadScriptsOption } from "../plugin-types.js";
|
|
2
2
|
import { DEFAULT_ROUTER_VERSIONS_KEY } from "../../router-versions.js";
|
|
3
|
+
import { rangoVersion } from "../utils/banner.js";
|
|
3
4
|
|
|
4
5
|
export const VIRTUAL_ENTRY_BROWSER: string = `
|
|
5
6
|
import {
|
|
@@ -320,9 +321,27 @@ export const VIRTUAL_IDS = {
|
|
|
320
321
|
version: "@rangojs/router:version",
|
|
321
322
|
} as const;
|
|
322
323
|
|
|
324
|
+
/**
|
|
325
|
+
* The npm semver of @rangojs/router, for the informational `window.__rango`
|
|
326
|
+
* marker (browser/rsc-router.tsx). Not a cache or build version.
|
|
327
|
+
*/
|
|
328
|
+
function getPackageVersionExport(): string {
|
|
329
|
+
return `export const PACKAGE_VERSION = ${JSON.stringify(rangoVersion)};`;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Non-RSC environments (client, ssr) get only PACKAGE_VERSION: the build
|
|
334
|
+
* module's ROUTER_VERSIONS token is replaced in server chunks only, so a
|
|
335
|
+
* client import of the full module would throw a ReferenceError.
|
|
336
|
+
*/
|
|
337
|
+
export function getVirtualPackageVersionContent(): string {
|
|
338
|
+
return getPackageVersionExport();
|
|
339
|
+
}
|
|
340
|
+
|
|
323
341
|
/** Dev: one stamp for both versions of every router, bumped on RSC edits. */
|
|
324
342
|
export function getVirtualVersionContent(version: string): string {
|
|
325
343
|
return [
|
|
344
|
+
getPackageVersionExport(),
|
|
326
345
|
`export const VERSION = ${JSON.stringify(version)};`,
|
|
327
346
|
`export const ROUTER_VERSIONS = undefined;`,
|
|
328
347
|
].join("\n");
|
|
@@ -346,6 +365,7 @@ export const ROUTER_VERSIONS_PLACEHOLDER = "__RANGO_ROUTER_VERSIONS__";
|
|
|
346
365
|
*/
|
|
347
366
|
export function getVirtualBuildVersionContent(): string {
|
|
348
367
|
return [
|
|
368
|
+
getPackageVersionExport(),
|
|
349
369
|
`export const ROUTER_VERSIONS = ${ROUTER_VERSIONS_PLACEHOLDER};`,
|
|
350
370
|
`export const VERSION = ROUTER_VERSIONS[${JSON.stringify(DEFAULT_ROUTER_VERSIONS_KEY)}][1];`,
|
|
351
371
|
].join("\n");
|