@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.8a4d0430
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -0
- package/README.md +884 -4
- package/dist/bin/rango.js +1601 -0
- package/dist/vite/index.js +4474 -867
- package/package.json +60 -51
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +262 -0
- package/skills/caching/SKILL.md +50 -21
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +167 -0
- package/skills/hooks/SKILL.md +334 -72
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +131 -8
- package/skills/layout/SKILL.md +100 -3
- package/skills/links/SKILL.md +89 -30
- package/skills/loader/SKILL.md +388 -38
- package/skills/middleware/SKILL.md +171 -34
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +78 -1
- package/skills/prerender/SKILL.md +643 -0
- package/skills/rango/SKILL.md +85 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +226 -14
- package/skills/router-setup/SKILL.md +123 -30
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +318 -89
- package/skills/use-cache/SKILL.md +324 -0
- package/src/__internal.ts +102 -4
- package/src/bin/rango.ts +321 -0
- package/src/browser/action-coordinator.ts +97 -0
- package/src/browser/action-response-classifier.ts +99 -0
- package/src/browser/event-controller.ts +87 -64
- package/src/browser/history-state.ts +80 -0
- package/src/browser/intercept-utils.ts +52 -0
- package/src/browser/link-interceptor.ts +24 -4
- package/src/browser/logging.ts +55 -0
- package/src/browser/merge-segment-loaders.ts +20 -12
- package/src/browser/navigation-bridge.ts +285 -553
- package/src/browser/navigation-client.ts +124 -71
- package/src/browser/navigation-store.ts +33 -50
- package/src/browser/navigation-transaction.ts +295 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +258 -308
- package/src/browser/prefetch/cache.ts +146 -0
- package/src/browser/prefetch/fetch.ts +135 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +42 -0
- package/src/browser/prefetch/queue.ts +88 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +185 -73
- package/src/browser/react/NavigationProvider.tsx +51 -11
- package/src/browser/react/context.ts +6 -0
- package/src/browser/react/filter-segment-order.ts +11 -0
- package/src/browser/react/index.ts +12 -12
- package/src/browser/react/location-state-shared.ts +95 -53
- package/src/browser/react/location-state.ts +60 -15
- package/src/browser/react/mount-context.ts +6 -1
- package/src/browser/react/nonce-context.ts +23 -0
- package/src/browser/react/shallow-equal.ts +27 -0
- package/src/browser/react/use-action.ts +29 -51
- package/src/browser/react/use-client-cache.ts +5 -3
- package/src/browser/react/use-handle.ts +32 -79
- package/src/browser/react/use-href.tsx +2 -2
- package/src/browser/react/use-link-status.ts +6 -5
- package/src/browser/react/use-navigation.ts +22 -63
- package/src/browser/react/use-params.ts +65 -0
- package/src/browser/react/use-pathname.ts +47 -0
- package/src/browser/react/use-router.ts +63 -0
- package/src/browser/react/use-search-params.ts +56 -0
- package/src/browser/react/use-segments.ts +80 -97
- package/src/browser/response-adapter.ts +73 -0
- package/src/browser/rsc-router.tsx +107 -26
- package/src/browser/scroll-restoration.ts +92 -16
- package/src/browser/segment-reconciler.ts +216 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +504 -599
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +109 -47
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +235 -24
- package/src/build/generate-route-types.ts +36 -0
- package/src/build/index.ts +13 -0
- package/src/build/route-trie.ts +265 -0
- package/src/build/route-types/ast-helpers.ts +25 -0
- package/src/build/route-types/ast-route-extraction.ts +98 -0
- package/src/build/route-types/codegen.ts +102 -0
- package/src/build/route-types/include-resolution.ts +411 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +469 -0
- package/src/build/route-types/scan-filter.ts +78 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +338 -0
- package/src/cache/cache-scope.ts +120 -303
- package/src/cache/cf/cf-cache-store.ts +119 -7
- package/src/cache/cf/index.ts +8 -2
- package/src/cache/document-cache.ts +101 -72
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +0 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +98 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +106 -126
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +86 -0
- package/src/debug.ts +17 -7
- package/src/errors.ts +108 -2
- package/src/handle.ts +15 -29
- package/src/handles/MetaTags.tsx +73 -20
- package/src/handles/breadcrumbs.ts +66 -0
- package/src/handles/index.ts +1 -0
- package/src/handles/meta.ts +30 -13
- package/src/host/cookie-handler.ts +21 -15
- package/src/host/errors.ts +8 -8
- package/src/host/index.ts +4 -7
- package/src/host/pattern-matcher.ts +27 -27
- package/src/host/router.ts +61 -39
- package/src/host/testing.ts +8 -8
- package/src/host/types.ts +15 -7
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +119 -29
- package/src/index.rsc.ts +153 -19
- package/src/index.ts +211 -30
- package/src/internal-debug.ts +11 -0
- package/src/loader.rsc.ts +26 -157
- package/src/loader.ts +27 -10
- package/src/network-error-thrower.tsx +3 -1
- package/src/outlet-provider.tsx +45 -0
- package/src/prerender/param-hash.ts +37 -0
- package/src/prerender/store.ts +185 -0
- package/src/prerender.ts +463 -0
- package/src/reverse.ts +330 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +934 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +430 -0
- package/src/route-definition/index.ts +52 -0
- package/src/route-definition/redirect.ts +93 -0
- package/src/route-definition.ts +1 -1428
- package/src/route-map-builder.ts +211 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +59 -8
- package/src/router/content-negotiation.ts +116 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +158 -0
- package/src/router/handler-context.ts +374 -81
- package/src/router/intercept-resolution.ts +395 -0
- package/src/router/lazy-includes.ts +234 -0
- package/src/router/loader-resolution.ts +215 -122
- package/src/router/logging.ts +248 -0
- package/src/router/manifest.ts +148 -35
- package/src/router/match-api.ts +620 -0
- package/src/router/match-context.ts +5 -3
- package/src/router/match-handlers.ts +440 -0
- package/src/router/match-middleware/background-revalidation.ts +80 -93
- package/src/router/match-middleware/cache-lookup.ts +382 -9
- package/src/router/match-middleware/cache-store.ts +51 -22
- package/src/router/match-middleware/intercept-resolution.ts +55 -17
- package/src/router/match-middleware/segment-resolution.ts +24 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +34 -28
- package/src/router/metrics.ts +235 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +222 -0
- package/src/router/middleware.ts +324 -367
- package/src/router/pattern-matching.ts +211 -43
- package/src/router/prerender-match.ts +402 -0
- package/src/router/preview-match.ts +170 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/router-context.ts +36 -21
- package/src/router/router-interfaces.ts +452 -0
- package/src/router/router-options.ts +592 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +570 -0
- package/src/router/segment-resolution/helpers.ts +263 -0
- package/src/router/segment-resolution/loader-cache.ts +198 -0
- package/src/router/segment-resolution/revalidation.ts +1241 -0
- package/src/router/segment-resolution/static-store.ts +67 -0
- package/src/router/segment-resolution.ts +21 -0
- package/src/router/segment-wrappers.ts +289 -0
- package/src/router/telemetry-otel.ts +299 -0
- package/src/router/telemetry.ts +300 -0
- package/src/router/timeout.ts +148 -0
- package/src/router/trie-matching.ts +239 -0
- package/src/router/types.ts +77 -3
- package/src/router.ts +692 -4257
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +764 -754
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +209 -0
- package/src/rsc/manifest-init.ts +86 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +379 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +235 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +348 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +38 -11
- package/src/search-params.ts +230 -0
- package/src/segment-system.tsx +25 -13
- package/src/server/context.ts +182 -51
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +94 -15
- package/src/server/loader-registry.ts +15 -56
- package/src/server/request-context.ts +430 -70
- package/src/server.ts +35 -130
- package/src/ssr/index.tsx +100 -31
- package/src/static-handler.ts +114 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +687 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +183 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +102 -0
- package/src/types/segments.ts +148 -0
- package/src/types.ts +1 -1623
- package/src/urls/include-helper.ts +197 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +339 -0
- package/src/urls/path-helper.ts +329 -0
- package/src/urls/pattern-types.ts +95 -0
- package/src/urls/response-types.ts +106 -0
- package/src/urls/type-extraction.ts +372 -0
- package/src/urls/urls-function.ts +98 -0
- package/src/urls.ts +1 -802
- package/src/use-loader.tsx +85 -77
- package/src/vite/discovery/bundle-postprocess.ts +184 -0
- package/src/vite/discovery/discover-routers.ts +344 -0
- package/src/vite/discovery/prerender-collection.ts +385 -0
- package/src/vite/discovery/route-types-writer.ts +258 -0
- package/src/vite/discovery/self-gen-tracking.ts +47 -0
- package/src/vite/discovery/state.ts +110 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +11 -1133
- package/src/vite/plugin-types.ts +131 -0
- package/src/vite/plugins/cjs-to-esm.ts +93 -0
- package/src/vite/plugins/client-ref-dedup.ts +115 -0
- package/src/vite/plugins/client-ref-hashing.ts +105 -0
- package/src/vite/{expose-action-id.ts → plugins/expose-action-id.ts} +72 -51
- package/src/vite/plugins/expose-id-utils.ts +287 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +179 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +569 -0
- package/src/vite/plugins/refresh-cmd.ts +65 -0
- package/src/vite/plugins/use-cache-transform.ts +323 -0
- package/src/vite/plugins/version-injector.ts +83 -0
- package/src/vite/plugins/version-plugin.ts +254 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +510 -0
- package/src/vite/router-discovery.ts +785 -0
- package/src/vite/utils/ast-handler-extract.ts +517 -0
- package/src/vite/utils/banner.ts +36 -0
- package/src/vite/utils/bundle-analysis.ts +137 -0
- package/src/vite/utils/manifest-utils.ts +70 -0
- package/src/vite/{package-resolution.ts → utils/package-resolution.ts} +25 -29
- package/src/vite/utils/prerender-utils.ts +189 -0
- package/src/vite/utils/shared-utils.ts +169 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/href.ts +0 -255
- package/src/server/route-manifest-cache.ts +0 -173
- package/src/vite/expose-handle-id.ts +0 -209
- package/src/vite/expose-loader-id.ts +0 -426
- package/src/vite/expose-location-state-id.ts +0 -177
- /package/src/vite/{version.d.ts → plugins/version.d.ts} +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSC plugin entry points configuration.
|
|
3
|
+
* All entries use virtual modules by default. Specify a path to use a custom entry file.
|
|
4
|
+
*/
|
|
5
|
+
export interface RscEntries {
|
|
6
|
+
/**
|
|
7
|
+
* Path to a custom browser/client entry file.
|
|
8
|
+
* If not specified, a default virtual entry is used.
|
|
9
|
+
*/
|
|
10
|
+
client?: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Path to a custom SSR entry file.
|
|
14
|
+
* If not specified, a default virtual entry is used.
|
|
15
|
+
*/
|
|
16
|
+
ssr?: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Path to a custom RSC entry file.
|
|
20
|
+
* If not specified, a default virtual entry is used that imports the router from the `entry` option.
|
|
21
|
+
*/
|
|
22
|
+
rsc?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Options for @vitejs/plugin-rsc integration
|
|
27
|
+
*/
|
|
28
|
+
export interface RscPluginOptions {
|
|
29
|
+
/**
|
|
30
|
+
* Entry points for client, ssr, and rsc environments.
|
|
31
|
+
* All entries use virtual modules by default.
|
|
32
|
+
* Specify paths only when you need custom entry files.
|
|
33
|
+
*/
|
|
34
|
+
entries?: RscEntries;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Base options shared by all presets
|
|
39
|
+
*/
|
|
40
|
+
interface RangoBaseOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Show startup banner. Set to false to disable.
|
|
43
|
+
* @default true
|
|
44
|
+
*/
|
|
45
|
+
banner?: boolean;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Generate named-routes.gen.ts by parsing url modules at startup.
|
|
49
|
+
* Provides type-safe Handler<"name"> and href() without executing router code.
|
|
50
|
+
* Set to `false` to disable (run `npx rango extract-names` manually instead).
|
|
51
|
+
* @default true
|
|
52
|
+
*/
|
|
53
|
+
staticRouteTypesGeneration?: boolean;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Glob patterns for files to include in route type scanning.
|
|
57
|
+
* Only files matching at least one pattern will be scanned.
|
|
58
|
+
* Patterns are relative to the project root.
|
|
59
|
+
* When unset, all .ts/.tsx files are scanned.
|
|
60
|
+
*/
|
|
61
|
+
include?: string[];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Glob patterns for files to exclude from route type scanning.
|
|
65
|
+
* Takes precedence over `include`. Patterns are relative to the project root.
|
|
66
|
+
* Defaults to common test/build directories.
|
|
67
|
+
*/
|
|
68
|
+
exclude?: string[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Options for Node.js deployment (default)
|
|
73
|
+
*/
|
|
74
|
+
export interface RangoNodeOptions extends RangoBaseOptions {
|
|
75
|
+
/**
|
|
76
|
+
* Deployment preset. Defaults to 'node' when not specified.
|
|
77
|
+
*/
|
|
78
|
+
preset?: "node";
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Path to your router configuration file that exports the route tree.
|
|
82
|
+
* This file must export a `router` object created with `createRouter()`.
|
|
83
|
+
*
|
|
84
|
+
* When omitted, auto-discovers the router by scanning for files containing
|
|
85
|
+
* `createRouter`. If exactly one is found, it is used automatically.
|
|
86
|
+
* If multiple are found, an error is thrown with the list of candidates.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* rango({ router: './src/router.tsx' })
|
|
91
|
+
* // or simply:
|
|
92
|
+
* rango()
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
router?: string;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* RSC plugin configuration. By default, rsc-router includes @vitejs/plugin-rsc
|
|
99
|
+
* with sensible defaults.
|
|
100
|
+
*
|
|
101
|
+
* Entry files (browser, ssr, rsc) are optional - if they don't exist,
|
|
102
|
+
* virtual defaults are used.
|
|
103
|
+
*
|
|
104
|
+
* - Omit or pass `true`/`{}` to use defaults (recommended)
|
|
105
|
+
* - Pass `{ entries: {...} }` to customize entry paths
|
|
106
|
+
* - Pass `false` to disable (for manual @vitejs/plugin-rsc configuration)
|
|
107
|
+
*
|
|
108
|
+
* @default true
|
|
109
|
+
*/
|
|
110
|
+
rsc?: boolean | RscPluginOptions;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Options for Cloudflare Workers deployment
|
|
115
|
+
*/
|
|
116
|
+
export interface RangoCloudflareOptions extends RangoBaseOptions {
|
|
117
|
+
/**
|
|
118
|
+
* Deployment preset for Cloudflare Workers.
|
|
119
|
+
* When using cloudflare preset:
|
|
120
|
+
* - @vitejs/plugin-rsc is NOT added (cloudflare plugin adds it)
|
|
121
|
+
* - Your worker entry (e.g., worker.rsc.tsx) imports the router directly
|
|
122
|
+
* - Browser and SSR use virtual entries
|
|
123
|
+
* - Build-time manifest generation is auto-detected from the resolved RSC environment config
|
|
124
|
+
*/
|
|
125
|
+
preset: "cloudflare";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Options for rango() Vite plugin
|
|
130
|
+
*/
|
|
131
|
+
export type RangoOptions = RangoNodeOptions | RangoCloudflareOptions;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Transform CJS vendor files from @vitejs/plugin-rsc to ESM for browser compatibility.
|
|
5
|
+
* The react-server-dom vendor files are shipped as CJS which doesn't work in browsers.
|
|
6
|
+
*/
|
|
7
|
+
export function createCjsToEsmPlugin(): Plugin {
|
|
8
|
+
return {
|
|
9
|
+
name: "@rangojs/router:cjs-to-esm",
|
|
10
|
+
enforce: "pre",
|
|
11
|
+
transform(code, id) {
|
|
12
|
+
const cleanId = id.split("?")[0];
|
|
13
|
+
|
|
14
|
+
// Transform the client.browser.js entry point to re-export from CJS
|
|
15
|
+
if (
|
|
16
|
+
cleanId.includes("vendor/react-server-dom/client.browser.js") ||
|
|
17
|
+
cleanId.includes("vendor\\react-server-dom\\client.browser.js")
|
|
18
|
+
) {
|
|
19
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
20
|
+
const cjsFile = isProd
|
|
21
|
+
? "./cjs/react-server-dom-webpack-client.browser.production.js"
|
|
22
|
+
: "./cjs/react-server-dom-webpack-client.browser.development.js";
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
code: `export * from "${cjsFile}";`,
|
|
26
|
+
map: null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Transform the actual CJS files to ESM
|
|
31
|
+
if (
|
|
32
|
+
(cleanId.includes("vendor/react-server-dom/cjs/") ||
|
|
33
|
+
cleanId.includes("vendor\\react-server-dom\\cjs\\")) &&
|
|
34
|
+
cleanId.includes("client.browser")
|
|
35
|
+
) {
|
|
36
|
+
let transformed = code;
|
|
37
|
+
|
|
38
|
+
// Extract the license comment to preserve it
|
|
39
|
+
const licenseMatch = transformed.match(/^\/\*\*[\s\S]*?\*\//);
|
|
40
|
+
const license = licenseMatch ? licenseMatch[0] : "";
|
|
41
|
+
if (license) {
|
|
42
|
+
transformed = transformed.slice(license.length);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Remove "use strict" (both dev and prod have this)
|
|
46
|
+
transformed = transformed.replace(/^\s*["']use strict["'];\s*/, "");
|
|
47
|
+
|
|
48
|
+
// Remove the conditional IIFE wrapper (development only)
|
|
49
|
+
transformed = transformed.replace(
|
|
50
|
+
/^\s*["']production["']\s*!==\s*process\.env\.NODE_ENV\s*&&\s*\(function\s*\(\)\s*\{/,
|
|
51
|
+
"",
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Remove the closing of the conditional IIFE at the end (development only)
|
|
55
|
+
transformed = transformed.replace(/\}\)\(\);?\s*$/, "");
|
|
56
|
+
|
|
57
|
+
// Replace require('react') and require('react-dom') with imports (development)
|
|
58
|
+
transformed = transformed.replace(
|
|
59
|
+
/var\s+React\s*=\s*require\s*\(\s*["']react["']\s*\)\s*,[\s\n]+ReactDOM\s*=\s*require\s*\(\s*["']react-dom["']\s*\)\s*,/g,
|
|
60
|
+
'import React from "react";\nimport ReactDOM from "react-dom";\nvar ',
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Replace require('react-dom') only (production - doesn't import React)
|
|
64
|
+
transformed = transformed.replace(
|
|
65
|
+
/var\s+ReactDOM\s*=\s*require\s*\(\s*["']react-dom["']\s*\)\s*,/g,
|
|
66
|
+
'import ReactDOM from "react-dom";\nvar ',
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Transform exports.xyz = function() to export function xyz()
|
|
70
|
+
transformed = transformed.replace(
|
|
71
|
+
/exports\.(\w+)\s*=\s*function\s*\(/g,
|
|
72
|
+
"export function $1(",
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Transform exports.xyz = value to export const xyz = value
|
|
76
|
+
transformed = transformed.replace(
|
|
77
|
+
/exports\.(\w+)\s*=/g,
|
|
78
|
+
"export const $1 =",
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// Reconstruct with license at the top
|
|
82
|
+
transformed = license + "\n" + transformed;
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
code: transformed,
|
|
86
|
+
map: null,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return null;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { Plugin, ResolvedConfig } from "vite";
|
|
2
|
+
|
|
3
|
+
const CLIENT_IN_SERVER_PROXY_PREFIX =
|
|
4
|
+
"virtual:vite-rsc/client-in-server-package-proxy/";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Extract the bare package name from an absolute node_modules path.
|
|
8
|
+
* Handles scoped packages (@org/name) and nested node_modules.
|
|
9
|
+
* Returns null if the path doesn't contain a valid package reference.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: This is a lossy transformation. It maps a specific submodule path
|
|
12
|
+
* (e.g., pkg/internal/context.js) to the package root (pkg). The load()
|
|
13
|
+
* hook then re-exports via the bare specifier, which resolves to the
|
|
14
|
+
* package entry point. This works for packages that barrel-export their
|
|
15
|
+
* "use client" symbols from the root, which covers the common case
|
|
16
|
+
* (component libraries like @mantine/core, @chakra-ui/react, etc.).
|
|
17
|
+
* Packages whose client symbols are only available from deep subpaths
|
|
18
|
+
* (not re-exported from the root) would lose those symbols after the
|
|
19
|
+
* rewrite. A more precise approach would resolve through the package's
|
|
20
|
+
* exports map to find the correct entry point, but that adds significant
|
|
21
|
+
* complexity for a rare edge case.
|
|
22
|
+
* See: https://github.com/cloudflare/vinext/pull/413
|
|
23
|
+
*/
|
|
24
|
+
export function extractPackageName(absolutePath: string): string | null {
|
|
25
|
+
// Find the last /node_modules/ segment (handles nested node_modules)
|
|
26
|
+
const marker = "/node_modules/";
|
|
27
|
+
const idx = absolutePath.lastIndexOf(marker);
|
|
28
|
+
if (idx === -1) return null;
|
|
29
|
+
|
|
30
|
+
const afterModules = absolutePath.slice(idx + marker.length);
|
|
31
|
+
|
|
32
|
+
if (afterModules.startsWith("@")) {
|
|
33
|
+
// Scoped package: @org/name
|
|
34
|
+
const parts = afterModules.split("/");
|
|
35
|
+
if (parts.length < 2 || !parts[1]) return null;
|
|
36
|
+
return `${parts[0]}/${parts[1]}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Unscoped package: name
|
|
40
|
+
const name = afterModules.split("/")[0];
|
|
41
|
+
return name || null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Vite plugin that deduplicates client references from third-party packages
|
|
46
|
+
* in dev mode.
|
|
47
|
+
*
|
|
48
|
+
* When @vitejs/plugin-rsc encounters a "use client" submodule inside a
|
|
49
|
+
* package imported from a server component, it creates a
|
|
50
|
+
* client-in-server-package-proxy virtual module that re-exports from the
|
|
51
|
+
* absolute file path. In the client environment, this absolute path bypasses
|
|
52
|
+
* Vite's pre-bundling, while direct client imports of the same package go
|
|
53
|
+
* through .vite/deps/. Two separate module instances are created, breaking
|
|
54
|
+
* React contexts (createContext runs twice, provider/consumer mismatch).
|
|
55
|
+
*
|
|
56
|
+
* This plugin intercepts absolute node_modules imports from proxy modules
|
|
57
|
+
* in the client environment and rewrites them to bare specifier imports
|
|
58
|
+
* that go through pre-bundling, ensuring a single module instance.
|
|
59
|
+
*
|
|
60
|
+
* Dev-only: production builds use the SSR manifest which handles module
|
|
61
|
+
* identity correctly.
|
|
62
|
+
*/
|
|
63
|
+
export function clientRefDedup(): Plugin {
|
|
64
|
+
let clientExclude: string[] = [];
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
name: "@rangojs/router:client-ref-dedup",
|
|
68
|
+
enforce: "pre",
|
|
69
|
+
apply: "serve",
|
|
70
|
+
|
|
71
|
+
configResolved(config: ResolvedConfig) {
|
|
72
|
+
// Respect user's optimizeDeps.exclude — if a package is explicitly
|
|
73
|
+
// excluded from pre-bundling, we shouldn't redirect it there.
|
|
74
|
+
const clientEnv = config.environments?.["client"];
|
|
75
|
+
clientExclude =
|
|
76
|
+
clientEnv?.optimizeDeps?.exclude ?? config.optimizeDeps?.exclude ?? [];
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
resolveId(source, importer, options) {
|
|
80
|
+
// Only intercept in the client environment
|
|
81
|
+
if (this.environment?.name !== "client") return;
|
|
82
|
+
|
|
83
|
+
// Only handle imports from client-in-server-package-proxy virtual modules
|
|
84
|
+
if (!importer?.includes(CLIENT_IN_SERVER_PROXY_PREFIX)) return;
|
|
85
|
+
|
|
86
|
+
// Only handle absolute node_modules paths
|
|
87
|
+
if (!source.includes("/node_modules/")) return;
|
|
88
|
+
|
|
89
|
+
// Must have an importer
|
|
90
|
+
if (!importer) return;
|
|
91
|
+
|
|
92
|
+
const packageName = extractPackageName(source);
|
|
93
|
+
if (!packageName) return;
|
|
94
|
+
|
|
95
|
+
// Don't redirect packages that are excluded from optimization
|
|
96
|
+
if (clientExclude.includes(packageName)) return;
|
|
97
|
+
|
|
98
|
+
// Return a virtual module that re-exports via bare specifier
|
|
99
|
+
return `\0rango:dedup/${packageName}`;
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
load(id) {
|
|
103
|
+
if (!id.startsWith("\0rango:dedup/")) return;
|
|
104
|
+
|
|
105
|
+
const packageName = id.slice("\0rango:dedup/".length);
|
|
106
|
+
|
|
107
|
+
// Re-export via bare specifier so Vite routes through pre-bundling
|
|
108
|
+
return [
|
|
109
|
+
`export * from ${JSON.stringify(packageName)};`,
|
|
110
|
+
`import * as __all__ from ${JSON.stringify(packageName)};`,
|
|
111
|
+
`export default __all__.default;`,
|
|
112
|
+
].join("\n");
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import { relative } from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
|
|
5
|
+
// Dev-mode client-reference key prefixes emitted by @vitejs/plugin-rsc
|
|
6
|
+
const CLIENT_PKG_PROXY_PREFIX =
|
|
7
|
+
"/@id/__x00__virtual:vite-rsc/client-package-proxy/";
|
|
8
|
+
const CLIENT_IN_SERVER_PKG_PROXY_PREFIX =
|
|
9
|
+
"/@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/";
|
|
10
|
+
const FS_PREFIX = "/@fs/";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Compute the production SHA-256 hash for a dev-mode client reference key.
|
|
14
|
+
* Mirrors the hashing logic in @vitejs/plugin-rsc's build mode:
|
|
15
|
+
* - Local files: hashString(toRelativeId(id)) where toRelativeId = relative(root, id)
|
|
16
|
+
* - Package proxies: hashString(packageSource)
|
|
17
|
+
* - client-in-server-package proxies: hashString(relative(root, decodedAbsPath))
|
|
18
|
+
*
|
|
19
|
+
* Returns the input unchanged if it doesn't match a known dev-mode pattern
|
|
20
|
+
* (e.g., already a production hash).
|
|
21
|
+
*/
|
|
22
|
+
export function computeProductionHash(
|
|
23
|
+
projectRoot: string,
|
|
24
|
+
refKey: string,
|
|
25
|
+
): string {
|
|
26
|
+
let toHash: string;
|
|
27
|
+
|
|
28
|
+
if (refKey.startsWith(CLIENT_PKG_PROXY_PREFIX)) {
|
|
29
|
+
// /@id/__x00__virtual:vite-rsc/client-package-proxy/<pkg> -> hash("<pkg>")
|
|
30
|
+
toHash = refKey.slice(CLIENT_PKG_PROXY_PREFIX.length);
|
|
31
|
+
} else if (refKey.startsWith(CLIENT_IN_SERVER_PKG_PROXY_PREFIX)) {
|
|
32
|
+
// /@id/__x00__virtual:vite-rsc/client-in-server-package-proxy/<encodedAbsPath>
|
|
33
|
+
const absPath = decodeURIComponent(
|
|
34
|
+
refKey.slice(CLIENT_IN_SERVER_PKG_PROXY_PREFIX.length),
|
|
35
|
+
);
|
|
36
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
37
|
+
} else if (refKey.startsWith(FS_PREFIX)) {
|
|
38
|
+
// /@fs/abs/path.tsx -> hash(relative(root, "/abs/path.tsx"))
|
|
39
|
+
const absPath = refKey.slice(FS_PREFIX.length - 1); // keep leading /
|
|
40
|
+
toHash = relative(projectRoot, absPath).replaceAll("\\", "/");
|
|
41
|
+
} else if (refKey.startsWith("/")) {
|
|
42
|
+
// /src/Button.tsx -> hash("src/Button.tsx")
|
|
43
|
+
toHash = refKey.slice(1);
|
|
44
|
+
} else {
|
|
45
|
+
// Already hashed or unknown format — return unchanged
|
|
46
|
+
return refKey;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return createHash("sha256").update(toHash).digest("hex").slice(0, 12);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Regex to match registerClientReference() calls as emitted by @vitejs/plugin-rsc.
|
|
53
|
+
// Captures the reference key (second argument) from the call.
|
|
54
|
+
// Handles two proxy forms: parenthesized expression `(expr)` and arrow-throw `() => { ... }`.
|
|
55
|
+
const REGISTER_CLIENT_REF_RE =
|
|
56
|
+
/registerClientReference\(\s*(?:(?:\([^)]*\))|(?:\(\)[\s\S]*?\}))\s*,\s*"([^"]+)"\s*,\s*"[^"]+"\s*\)/g;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Transform source code by replacing dev-mode client reference keys with
|
|
60
|
+
* production hashes. Exported for testing; used internally by hashClientRefs.
|
|
61
|
+
* Returns null if no replacements were made.
|
|
62
|
+
*/
|
|
63
|
+
export function transformClientRefs(
|
|
64
|
+
code: string,
|
|
65
|
+
projectRoot: string,
|
|
66
|
+
): string | null {
|
|
67
|
+
if (!code.includes("registerClientReference")) return null;
|
|
68
|
+
|
|
69
|
+
let hasReplacement = false;
|
|
70
|
+
const result = code.replace(
|
|
71
|
+
REGISTER_CLIENT_REF_RE,
|
|
72
|
+
(match, refKey: string) => {
|
|
73
|
+
const hash = computeProductionHash(projectRoot, refKey);
|
|
74
|
+
if (hash === refKey) return match;
|
|
75
|
+
hasReplacement = true;
|
|
76
|
+
return match.replace(`"${refKey}"`, `"${hash}"`);
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return hasReplacement ? result : null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Vite plugin that rewrites registerClientReference() calls in the RSC
|
|
85
|
+
* environment, replacing dev-mode reference keys with production hashes.
|
|
86
|
+
*
|
|
87
|
+
* This runs AFTER the RSC plugin's transform so the Flight serializer
|
|
88
|
+
* naturally emits production IDs, eliminating the need for post-build
|
|
89
|
+
* regex replacement of Flight payloads.
|
|
90
|
+
*/
|
|
91
|
+
export function hashClientRefs(projectRoot: string): Plugin {
|
|
92
|
+
return {
|
|
93
|
+
name: "@rangojs/router:hash-client-refs",
|
|
94
|
+
// Run after the RSC plugin's transform (default enforce is normal)
|
|
95
|
+
enforce: "post",
|
|
96
|
+
applyToEnvironment(env) {
|
|
97
|
+
return env.name === "rsc";
|
|
98
|
+
},
|
|
99
|
+
transform(code, _id) {
|
|
100
|
+
const result = transformClientRefs(code, projectRoot);
|
|
101
|
+
if (result === null) return;
|
|
102
|
+
return { code: result, map: null };
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { Plugin, ResolvedConfig } from "vite";
|
|
|
2
2
|
import MagicString from "magic-string";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import fs from "node:fs";
|
|
5
|
+
import { normalizePath } from "./expose-id-utils.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Type for the RSC plugin's manager API
|
|
@@ -34,12 +35,12 @@ function getRscPluginApi(config: ResolvedConfig): RscPluginApi | undefined {
|
|
|
34
35
|
plugin = config.plugins.find(
|
|
35
36
|
(p) =>
|
|
36
37
|
(p.api as RscPluginApi | undefined)?.manager?.serverReferenceMetaMap !==
|
|
37
|
-
undefined
|
|
38
|
+
undefined,
|
|
38
39
|
);
|
|
39
40
|
if (plugin) {
|
|
40
41
|
console.warn(
|
|
41
42
|
`[rsc-router:expose-action-id] RSC plugin found by API structure (name: "${plugin.name}"). ` +
|
|
42
|
-
`Consider updating the name lookup if the plugin was renamed
|
|
43
|
+
`Consider updating the name lookup if the plugin was renamed.`,
|
|
43
44
|
);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -47,13 +48,6 @@ function getRscPluginApi(config: ResolvedConfig): RscPluginApi | undefined {
|
|
|
47
48
|
return plugin?.api as RscPluginApi | undefined;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
/**
|
|
51
|
-
* Normalize path to forward slashes
|
|
52
|
-
*/
|
|
53
|
-
function normalizePath(p: string): string {
|
|
54
|
-
return p.split(path.sep).join("/");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
51
|
/**
|
|
58
52
|
* Check if a file is a "use server" module (has the directive at the module level).
|
|
59
53
|
* This distinguishes module-level server action files from files with inline actions.
|
|
@@ -88,21 +82,27 @@ function isUseServerModule(filePath: string): boolean {
|
|
|
88
82
|
* @param sourceId - The source file identifier (for sourcemap)
|
|
89
83
|
* @param hashToFileMap - Optional mapping from hash to file path (for server bundles)
|
|
90
84
|
*/
|
|
91
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Apply createServerReference wrapping to a MagicString instance.
|
|
87
|
+
* Returns true if any changes were made.
|
|
88
|
+
*/
|
|
89
|
+
function applyServerReferenceWrapping(
|
|
92
90
|
code: string,
|
|
93
|
-
|
|
94
|
-
hashToFileMap?: Map<string, string
|
|
95
|
-
):
|
|
91
|
+
s: MagicString,
|
|
92
|
+
hashToFileMap?: Map<string, string>,
|
|
93
|
+
): boolean {
|
|
96
94
|
if (!code.includes("createServerReference(")) {
|
|
97
|
-
return
|
|
95
|
+
return false;
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
// Match: createServerReference("hash#actionName", ...) or $$ReactClient.createServerReference(...)
|
|
101
|
-
// The RSC plugin uses $$ReactClient namespace in transformed code
|
|
99
|
+
// The RSC plugin uses $$ReactClient namespace in transformed code.
|
|
100
|
+
// Note: [^)]* cannot handle nested parens in trailing args. This is safe in practice
|
|
101
|
+
// because the RSC plugin always generates simple variable references (e.g., callServer)
|
|
102
|
+
// as the second argument, never nested function calls.
|
|
102
103
|
const pattern =
|
|
103
104
|
/((?:\$\$\w+\.)?createServerReference)\(("[^"]+#[^"]+")([^)]*)\)/g;
|
|
104
105
|
|
|
105
|
-
const s = new MagicString(code);
|
|
106
106
|
let hasChanges = false;
|
|
107
107
|
let match: RegExpExecArray | null;
|
|
108
108
|
|
|
@@ -133,7 +133,16 @@ function transformServerReferences(
|
|
|
133
133
|
s.overwrite(start, end, replacement);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
return hasChanges;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function transformServerReferences(
|
|
140
|
+
code: string,
|
|
141
|
+
sourceId?: string,
|
|
142
|
+
hashToFileMap?: Map<string, string>,
|
|
143
|
+
): { code: string; map: ReturnType<MagicString["generateMap"]> } | null {
|
|
144
|
+
const s = new MagicString(code);
|
|
145
|
+
if (!applyServerReferenceWrapping(code, s, hashToFileMap)) {
|
|
137
146
|
return null;
|
|
138
147
|
}
|
|
139
148
|
|
|
@@ -159,20 +168,27 @@ function transformServerReferences(
|
|
|
159
168
|
* @param sourceId - The source file identifier (for sourcemap)
|
|
160
169
|
* @param hashToFileMap - Mapping from hash to file path (only module-level "use server" files)
|
|
161
170
|
*/
|
|
162
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Apply registerServerReference wrapping to a MagicString instance.
|
|
173
|
+
* Returns true if any changes were made.
|
|
174
|
+
*
|
|
175
|
+
* Only actions from module-level "use server" files are transformed.
|
|
176
|
+
* Inline actions keep their hashed IDs for client security.
|
|
177
|
+
*/
|
|
178
|
+
function applyRegisterReferenceWrapping(
|
|
163
179
|
code: string,
|
|
164
|
-
|
|
165
|
-
hashToFileMap
|
|
166
|
-
):
|
|
167
|
-
if (!
|
|
168
|
-
return
|
|
180
|
+
s: MagicString,
|
|
181
|
+
hashToFileMap: Map<string, string>,
|
|
182
|
+
): boolean {
|
|
183
|
+
if (!code.includes("registerServerReference(")) {
|
|
184
|
+
return false;
|
|
169
185
|
}
|
|
170
186
|
|
|
171
187
|
// Match: registerServerReference(fn, "hash", "exportName")
|
|
172
188
|
// The hash is the second argument, exportName is the third
|
|
173
|
-
const pattern =
|
|
189
|
+
const pattern =
|
|
190
|
+
/registerServerReference\(([^,]+),\s*"([^"]+)",\s*"([^"]+)"\)/g;
|
|
174
191
|
|
|
175
|
-
const s = new MagicString(code);
|
|
176
192
|
let hasChanges = false;
|
|
177
193
|
let match: RegExpExecArray | null;
|
|
178
194
|
|
|
@@ -196,7 +212,18 @@ function transformRegisterServerReference(
|
|
|
196
212
|
}
|
|
197
213
|
}
|
|
198
214
|
|
|
199
|
-
|
|
215
|
+
return hasChanges;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function transformRegisterServerReference(
|
|
219
|
+
code: string,
|
|
220
|
+
sourceId?: string,
|
|
221
|
+
hashToFileMap?: Map<string, string>,
|
|
222
|
+
): { code: string; map: ReturnType<MagicString["generateMap"]> } | null {
|
|
223
|
+
if (!hashToFileMap) return null;
|
|
224
|
+
|
|
225
|
+
const s = new MagicString(code);
|
|
226
|
+
if (!applyRegisterReferenceWrapping(code, s, hashToFileMap)) {
|
|
200
227
|
return null;
|
|
201
228
|
}
|
|
202
229
|
|
|
@@ -253,7 +280,7 @@ export function exposeActionId(): Plugin {
|
|
|
253
280
|
"[rsc-router] Could not find @vitejs/plugin-rsc. " +
|
|
254
281
|
"@rangojs/router requires the Vite RSC plugin.\n" +
|
|
255
282
|
"The RSC plugin should be included automatically. If you disabled it with\n" +
|
|
256
|
-
"
|
|
283
|
+
"rango({ rsc: false }), add rsc() before rango() in your config.",
|
|
257
284
|
);
|
|
258
285
|
}
|
|
259
286
|
|
|
@@ -263,7 +290,7 @@ export function exposeActionId(): Plugin {
|
|
|
263
290
|
const { serverReferenceMetaMap } = rscPluginApi.manager;
|
|
264
291
|
|
|
265
292
|
for (const [absolutePath, meta] of Object.entries(
|
|
266
|
-
serverReferenceMetaMap
|
|
293
|
+
serverReferenceMetaMap,
|
|
267
294
|
)) {
|
|
268
295
|
// Only include module-level "use server" files
|
|
269
296
|
// Inline actions (defined in RSC components) should keep hashed IDs for client security
|
|
@@ -272,7 +299,7 @@ export function exposeActionId(): Plugin {
|
|
|
272
299
|
}
|
|
273
300
|
|
|
274
301
|
const relativePath = normalizePath(
|
|
275
|
-
path.relative(config.root, absolutePath)
|
|
302
|
+
path.relative(config.root, absolutePath),
|
|
276
303
|
);
|
|
277
304
|
|
|
278
305
|
// The referenceKey in build mode is the hash
|
|
@@ -281,7 +308,6 @@ export function exposeActionId(): Plugin {
|
|
|
281
308
|
}
|
|
282
309
|
},
|
|
283
310
|
|
|
284
|
-
|
|
285
311
|
// Dev mode only: transform hook runs after RSC plugin creates server references
|
|
286
312
|
// In dev mode, IDs already contain file paths, not hashes
|
|
287
313
|
transform(code, id) {
|
|
@@ -314,31 +340,26 @@ export function exposeActionId(): Plugin {
|
|
|
314
340
|
// Only use file path mapping for RSC environment
|
|
315
341
|
const effectiveMap = isRscEnv ? hashToFileMap : undefined;
|
|
316
342
|
|
|
317
|
-
//
|
|
318
|
-
|
|
319
|
-
code,
|
|
320
|
-
chunk.fileName,
|
|
321
|
-
effectiveMap
|
|
322
|
-
);
|
|
323
|
-
|
|
324
|
-
// For RSC bundles, also transform registerServerReference calls
|
|
325
|
-
// This replaces hashed IDs with file paths so $id contains the actual path
|
|
343
|
+
// For RSC bundles, both createServerReference and registerServerReference
|
|
344
|
+
// may need transforming. Use a single MagicString for correct sourcemaps.
|
|
326
345
|
if (isRscEnv && hashToFileMap) {
|
|
327
|
-
const
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
346
|
+
const s = new MagicString(code);
|
|
347
|
+
const changed1 = applyServerReferenceWrapping(code, s, effectiveMap);
|
|
348
|
+
const changed2 = applyRegisterReferenceWrapping(code, s, hashToFileMap);
|
|
349
|
+
if (changed1 || changed2) {
|
|
350
|
+
return {
|
|
351
|
+
code: s.toString(),
|
|
352
|
+
map: s.generateMap({
|
|
353
|
+
source: chunk.fileName,
|
|
354
|
+
includeContent: true,
|
|
355
|
+
}),
|
|
356
|
+
};
|
|
335
357
|
}
|
|
358
|
+
return null;
|
|
336
359
|
}
|
|
337
360
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
return null;
|
|
361
|
+
// Non-RSC environments: only transform createServerReference calls
|
|
362
|
+
return transformServerReferences(code, chunk.fileName, effectiveMap);
|
|
342
363
|
},
|
|
343
364
|
};
|
|
344
365
|
}
|