@rangojs/router 0.0.0-experimental.8 → 0.0.0-experimental.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -0
- package/README.md +942 -4
- package/dist/bin/rango.js +1689 -0
- package/dist/vite/index.js +4960 -935
- package/package.json +70 -60
- package/skills/breadcrumbs/SKILL.md +250 -0
- package/skills/cache-guide/SKILL.md +294 -0
- package/skills/caching/SKILL.md +93 -23
- package/skills/composability/SKILL.md +172 -0
- package/skills/debug-manifest/SKILL.md +12 -8
- package/skills/document-cache/SKILL.md +18 -16
- package/skills/fonts/SKILL.md +167 -0
- package/skills/handler-use/SKILL.md +362 -0
- package/skills/hooks/SKILL.md +334 -72
- package/skills/host-router/SKILL.md +218 -0
- package/skills/intercept/SKILL.md +151 -8
- package/skills/layout/SKILL.md +122 -3
- package/skills/links/SKILL.md +92 -31
- package/skills/loader/SKILL.md +404 -44
- package/skills/middleware/SKILL.md +205 -37
- package/skills/migrate-nextjs/SKILL.md +560 -0
- package/skills/migrate-react-router/SKILL.md +764 -0
- package/skills/mime-routes/SKILL.md +128 -0
- package/skills/parallel/SKILL.md +263 -1
- package/skills/prerender/SKILL.md +685 -0
- package/skills/rango/SKILL.md +87 -16
- package/skills/response-routes/SKILL.md +411 -0
- package/skills/route/SKILL.md +281 -14
- package/skills/router-setup/SKILL.md +210 -32
- package/skills/tailwind/SKILL.md +129 -0
- package/skills/theme/SKILL.md +9 -8
- package/skills/typesafety/SKILL.md +328 -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/app-version.ts +14 -0
- package/src/browser/event-controller.ts +92 -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 +317 -560
- package/src/browser/navigation-client.ts +206 -68
- package/src/browser/navigation-store.ts +73 -55
- package/src/browser/navigation-transaction.ts +297 -0
- package/src/browser/network-error-handler.ts +61 -0
- package/src/browser/partial-update.ts +343 -316
- package/src/browser/prefetch/cache.ts +216 -0
- package/src/browser/prefetch/fetch.ts +206 -0
- package/src/browser/prefetch/observer.ts +65 -0
- package/src/browser/prefetch/policy.ts +48 -0
- package/src/browser/prefetch/queue.ts +160 -0
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +112 -0
- package/src/browser/react/Link.tsx +253 -74
- package/src/browser/react/NavigationProvider.tsx +87 -11
- package/src/browser/react/context.ts +11 -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 +30 -126
- 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 +44 -65
- 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 +76 -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 +214 -58
- package/src/browser/scroll-restoration.ts +127 -52
- package/src/browser/segment-reconciler.ts +243 -0
- package/src/browser/segment-structure-assert.ts +16 -0
- package/src/browser/server-action-bridge.ts +510 -603
- package/src/browser/shallow.ts +6 -1
- package/src/browser/types.ts +141 -48
- package/src/browser/validate-redirect-origin.ts +29 -0
- package/src/build/generate-manifest.ts +235 -24
- package/src/build/generate-route-types.ts +39 -0
- package/src/build/index.ts +13 -0
- package/src/build/route-trie.ts +291 -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 +418 -0
- package/src/build/route-types/param-extraction.ts +48 -0
- package/src/build/route-types/per-module-writer.ts +128 -0
- package/src/build/route-types/router-processing.ts +618 -0
- package/src/build/route-types/scan-filter.ts +85 -0
- package/src/build/runtime-discovery.ts +231 -0
- package/src/cache/background-task.ts +34 -0
- package/src/cache/cache-key-utils.ts +44 -0
- package/src/cache/cache-policy.ts +125 -0
- package/src/cache/cache-runtime.ts +342 -0
- package/src/cache/cache-scope.ts +167 -309
- package/src/cache/cf/cf-cache-store.ts +571 -17
- package/src/cache/cf/index.ts +13 -3
- package/src/cache/document-cache.ts +116 -77
- package/src/cache/handle-capture.ts +81 -0
- package/src/cache/handle-snapshot.ts +41 -0
- package/src/cache/index.ts +1 -15
- package/src/cache/memory-segment-store.ts +191 -13
- package/src/cache/profile-registry.ts +73 -0
- package/src/cache/read-through-swr.ts +134 -0
- package/src/cache/segment-codec.ts +256 -0
- package/src/cache/taint.ts +153 -0
- package/src/cache/types.ts +72 -122
- package/src/client.rsc.tsx +3 -1
- package/src/client.tsx +135 -301
- package/src/component-utils.ts +4 -4
- package/src/components/DefaultDocument.tsx +5 -1
- package/src/context-var.ts +156 -0
- package/src/debug.ts +19 -9
- package/src/errors.ts +108 -2
- package/src/handle.ts +55 -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 +155 -19
- package/src/index.ts +251 -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 +186 -0
- package/src/prerender.ts +524 -0
- package/src/reverse.ts +354 -0
- package/src/root-error-boundary.tsx +41 -29
- package/src/route-content-wrapper.tsx +7 -4
- package/src/route-definition/dsl-helpers.ts +1121 -0
- package/src/route-definition/helper-factories.ts +200 -0
- package/src/route-definition/helpers-types.ts +478 -0
- package/src/route-definition/index.ts +55 -0
- package/src/route-definition/redirect.ts +101 -0
- package/src/route-definition/resolve-handler-use.ts +149 -0
- package/src/route-definition.ts +1 -1428
- package/src/route-map-builder.ts +217 -123
- package/src/route-name.ts +53 -0
- package/src/route-types.ts +77 -8
- package/src/router/content-negotiation.ts +215 -0
- package/src/router/debug-manifest.ts +72 -0
- package/src/router/error-handling.ts +9 -9
- package/src/router/find-match.ts +160 -0
- package/src/router/handler-context.ts +438 -86
- package/src/router/intercept-resolution.ts +402 -0
- package/src/router/lazy-includes.ts +237 -0
- package/src/router/loader-resolution.ts +356 -128
- package/src/router/logging.ts +251 -0
- package/src/router/manifest.ts +163 -35
- package/src/router/match-api.ts +555 -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 +108 -93
- package/src/router/match-middleware/cache-lookup.ts +460 -10
- package/src/router/match-middleware/cache-store.ts +98 -26
- package/src/router/match-middleware/intercept-resolution.ts +57 -17
- package/src/router/match-middleware/segment-resolution.ts +80 -6
- package/src/router/match-pipelines.ts +10 -45
- package/src/router/match-result.ts +135 -35
- package/src/router/metrics.ts +240 -15
- package/src/router/middleware-cookies.ts +55 -0
- package/src/router/middleware-types.ts +220 -0
- package/src/router/middleware.ts +324 -369
- package/src/router/navigation-snapshot.ts +182 -0
- package/src/router/pattern-matching.ts +211 -43
- package/src/router/prerender-match.ts +502 -0
- package/src/router/preview-match.ts +98 -0
- package/src/router/request-classification.ts +310 -0
- package/src/router/revalidation.ts +137 -38
- package/src/router/route-snapshot.ts +245 -0
- package/src/router/router-context.ts +41 -21
- package/src/router/router-interfaces.ts +484 -0
- package/src/router/router-options.ts +618 -0
- package/src/router/router-registry.ts +24 -0
- package/src/router/segment-resolution/fresh.ts +748 -0
- package/src/router/segment-resolution/helpers.ts +268 -0
- package/src/router/segment-resolution/loader-cache.ts +199 -0
- package/src/router/segment-resolution/revalidation.ts +1379 -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 +291 -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 +78 -3
- package/src/router.ts +740 -4252
- package/src/rsc/handler-context.ts +45 -0
- package/src/rsc/handler.ts +907 -797
- package/src/rsc/helpers.ts +140 -6
- package/src/rsc/index.ts +0 -20
- package/src/rsc/loader-fetch.ts +229 -0
- package/src/rsc/manifest-init.ts +90 -0
- package/src/rsc/nonce.ts +14 -0
- package/src/rsc/origin-guard.ts +141 -0
- package/src/rsc/progressive-enhancement.ts +391 -0
- package/src/rsc/response-error.ts +37 -0
- package/src/rsc/response-route-handler.ts +347 -0
- package/src/rsc/rsc-rendering.ts +246 -0
- package/src/rsc/runtime-warnings.ts +42 -0
- package/src/rsc/server-action.ts +356 -0
- package/src/rsc/ssr-setup.ts +128 -0
- package/src/rsc/types.ts +46 -11
- package/src/search-params.ts +230 -0
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +122 -0
- package/src/segment-system.tsx +134 -36
- package/src/server/context.ts +341 -61
- package/src/server/cookie-store.ts +190 -0
- package/src/server/fetchable-loader-store.ts +37 -0
- package/src/server/handle-store.ts +113 -15
- package/src/server/loader-registry.ts +24 -64
- package/src/server/request-context.ts +607 -81
- package/src/server.ts +35 -130
- package/src/ssr/index.tsx +103 -30
- package/src/static-handler.ts +126 -0
- package/src/theme/ThemeProvider.tsx +21 -15
- package/src/theme/ThemeScript.tsx +5 -5
- package/src/theme/constants.ts +5 -2
- package/src/theme/index.ts +4 -14
- package/src/theme/theme-context.ts +4 -30
- package/src/theme/theme-script.ts +21 -18
- package/src/types/boundaries.ts +158 -0
- package/src/types/cache-types.ts +198 -0
- package/src/types/error-types.ts +192 -0
- package/src/types/global-namespace.ts +100 -0
- package/src/types/handler-context.ts +791 -0
- package/src/types/index.ts +88 -0
- package/src/types/loader-types.ts +210 -0
- package/src/types/route-config.ts +170 -0
- package/src/types/route-entry.ts +120 -0
- package/src/types/segments.ts +150 -0
- package/src/types.ts +1 -1623
- package/src/urls/include-helper.ts +207 -0
- package/src/urls/index.ts +53 -0
- package/src/urls/path-helper-types.ts +372 -0
- package/src/urls/path-helper.ts +364 -0
- package/src/urls/pattern-types.ts +107 -0
- package/src/urls/response-types.ts +116 -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 +161 -81
- package/src/vite/discovery/bundle-postprocess.ts +181 -0
- package/src/vite/discovery/discover-routers.ts +348 -0
- package/src/vite/discovery/prerender-collection.ts +439 -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 +117 -0
- package/src/vite/discovery/virtual-module-codegen.ts +203 -0
- package/src/vite/index.ts +15 -1133
- package/src/vite/plugin-types.ts +103 -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 -53
- package/src/vite/plugins/expose-id-utils.ts +299 -0
- package/src/vite/plugins/expose-ids/export-analysis.ts +296 -0
- package/src/vite/plugins/expose-ids/handler-transform.ts +209 -0
- package/src/vite/plugins/expose-ids/loader-transform.ts +74 -0
- package/src/vite/plugins/expose-ids/router-transform.ts +110 -0
- package/src/vite/plugins/expose-ids/types.ts +45 -0
- package/src/vite/plugins/expose-internal-ids.ts +786 -0
- package/src/vite/plugins/performance-tracks.ts +88 -0
- package/src/vite/plugins/refresh-cmd.ts +127 -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 +266 -0
- package/src/vite/{virtual-entries.ts → plugins/virtual-entries.ts} +23 -14
- package/src/vite/plugins/virtual-stub-plugin.ts +29 -0
- package/src/vite/rango.ts +462 -0
- package/src/vite/router-discovery.ts +918 -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 +221 -0
- package/src/vite/utils/shared-utils.ts +170 -0
- package/CLAUDE.md +0 -43
- package/src/browser/lru-cache.ts +0 -69
- package/src/browser/request-controller.ts +0 -164
- package/src/cache/memory-store.ts +0 -253
- package/src/href-context.ts +0 -33
- package/src/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,103 @@
|
|
|
1
|
+
// -- Build-time environment types -------------------------------------------
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context passed to a buildEnv factory function.
|
|
5
|
+
* Provides Vite config details for conditional env setup.
|
|
6
|
+
*/
|
|
7
|
+
export interface BuildEnvFactoryContext {
|
|
8
|
+
/** Vite project root directory. */
|
|
9
|
+
root: string;
|
|
10
|
+
/** Vite mode (e.g. "development", "production"). */
|
|
11
|
+
mode: string;
|
|
12
|
+
/** Vite command ("serve" for dev, "build" for production). */
|
|
13
|
+
command: "serve" | "build";
|
|
14
|
+
/** Router deployment preset. */
|
|
15
|
+
preset: "node" | "cloudflare";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Factory function that creates build-time environment bindings.
|
|
20
|
+
* Called once at plugin startup. Return `dispose` to clean up resources.
|
|
21
|
+
*/
|
|
22
|
+
export type BuildEnvFactory = (
|
|
23
|
+
ctx: BuildEnvFactoryContext,
|
|
24
|
+
) => Promise<BuildEnvResult> | BuildEnvResult;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Result of resolving build-time environment bindings.
|
|
28
|
+
*/
|
|
29
|
+
export interface BuildEnvResult {
|
|
30
|
+
/** Environment bindings available to Prerender/Static handlers via ctx.env. */
|
|
31
|
+
env: Record<string, unknown>;
|
|
32
|
+
/** Called after build completes to clean up resources (e.g., miniflare). */
|
|
33
|
+
dispose?: () => Promise<void> | void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Build-time environment configuration for Prerender and Static handlers.
|
|
38
|
+
*
|
|
39
|
+
* - `false` (default): no build-time env, `ctx.env` throws.
|
|
40
|
+
* - `"auto"`: calls `wrangler.getPlatformProxy()` (cloudflare preset only).
|
|
41
|
+
* - Object: used directly as `ctx.env` during build.
|
|
42
|
+
* - Factory: called once at startup, must return `{ env, dispose? }`.
|
|
43
|
+
*/
|
|
44
|
+
export type BuildEnvOption =
|
|
45
|
+
| false
|
|
46
|
+
| "auto"
|
|
47
|
+
| Record<string, unknown>
|
|
48
|
+
| BuildEnvFactory;
|
|
49
|
+
|
|
50
|
+
// -- Plugin options ---------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Base options shared by all presets
|
|
54
|
+
*/
|
|
55
|
+
interface RangoBaseOptions {
|
|
56
|
+
/**
|
|
57
|
+
* Show startup banner. Set to false to disable.
|
|
58
|
+
* @default true
|
|
59
|
+
*/
|
|
60
|
+
banner?: boolean;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Environment bindings available to Prerender and Static handlers at build
|
|
64
|
+
* time via `ctx.env`. Applies to both production build and dev on-demand
|
|
65
|
+
* prerender (`/__rsc_prerender`).
|
|
66
|
+
*
|
|
67
|
+
* This is the build-time env supplied by the Vite plugin, not the live
|
|
68
|
+
* request env. It is shared across all prerender invocations for the build.
|
|
69
|
+
*
|
|
70
|
+
* @default false
|
|
71
|
+
*/
|
|
72
|
+
buildEnv?: BuildEnvOption;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Options for Node.js deployment (default)
|
|
77
|
+
*/
|
|
78
|
+
export interface RangoNodeOptions extends RangoBaseOptions {
|
|
79
|
+
/**
|
|
80
|
+
* Deployment preset. Defaults to 'node' when not specified.
|
|
81
|
+
*/
|
|
82
|
+
preset?: "node";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Options for Cloudflare Workers deployment
|
|
87
|
+
*/
|
|
88
|
+
export interface RangoCloudflareOptions extends RangoBaseOptions {
|
|
89
|
+
/**
|
|
90
|
+
* Deployment preset for Cloudflare Workers.
|
|
91
|
+
* When using cloudflare preset:
|
|
92
|
+
* - @vitejs/plugin-rsc is NOT added (cloudflare plugin adds it)
|
|
93
|
+
* - Your worker entry (e.g., worker.rsc.tsx) imports the router directly
|
|
94
|
+
* - Browser and SSR use virtual entries
|
|
95
|
+
* - Build-time manifest generation is auto-detected from the resolved RSC environment config
|
|
96
|
+
*/
|
|
97
|
+
preset: "cloudflare";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Options for rango() Vite plugin
|
|
102
|
+
*/
|
|
103
|
+
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
|
|
|
@@ -251,9 +278,7 @@ export function exposeActionId(): Plugin {
|
|
|
251
278
|
if (!rscPluginApi) {
|
|
252
279
|
throw new Error(
|
|
253
280
|
"[rsc-router] Could not find @vitejs/plugin-rsc. " +
|
|
254
|
-
"@rangojs/router requires the Vite RSC plugin
|
|
255
|
-
"The RSC plugin should be included automatically. If you disabled it with\n" +
|
|
256
|
-
"rscRouter({ rsc: false }), add rsc() before rscRouter() in your config."
|
|
281
|
+
"@rangojs/router requires the Vite RSC plugin, which is included automatically by rango().",
|
|
257
282
|
);
|
|
258
283
|
}
|
|
259
284
|
|
|
@@ -263,7 +288,7 @@ export function exposeActionId(): Plugin {
|
|
|
263
288
|
const { serverReferenceMetaMap } = rscPluginApi.manager;
|
|
264
289
|
|
|
265
290
|
for (const [absolutePath, meta] of Object.entries(
|
|
266
|
-
serverReferenceMetaMap
|
|
291
|
+
serverReferenceMetaMap,
|
|
267
292
|
)) {
|
|
268
293
|
// Only include module-level "use server" files
|
|
269
294
|
// Inline actions (defined in RSC components) should keep hashed IDs for client security
|
|
@@ -272,7 +297,7 @@ export function exposeActionId(): Plugin {
|
|
|
272
297
|
}
|
|
273
298
|
|
|
274
299
|
const relativePath = normalizePath(
|
|
275
|
-
path.relative(config.root, absolutePath)
|
|
300
|
+
path.relative(config.root, absolutePath),
|
|
276
301
|
);
|
|
277
302
|
|
|
278
303
|
// The referenceKey in build mode is the hash
|
|
@@ -281,7 +306,6 @@ export function exposeActionId(): Plugin {
|
|
|
281
306
|
}
|
|
282
307
|
},
|
|
283
308
|
|
|
284
|
-
|
|
285
309
|
// Dev mode only: transform hook runs after RSC plugin creates server references
|
|
286
310
|
// In dev mode, IDs already contain file paths, not hashes
|
|
287
311
|
transform(code, id) {
|
|
@@ -314,31 +338,26 @@ export function exposeActionId(): Plugin {
|
|
|
314
338
|
// Only use file path mapping for RSC environment
|
|
315
339
|
const effectiveMap = isRscEnv ? hashToFileMap : undefined;
|
|
316
340
|
|
|
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
|
|
341
|
+
// For RSC bundles, both createServerReference and registerServerReference
|
|
342
|
+
// may need transforming. Use a single MagicString for correct sourcemaps.
|
|
326
343
|
if (isRscEnv && hashToFileMap) {
|
|
327
|
-
const
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
344
|
+
const s = new MagicString(code);
|
|
345
|
+
const changed1 = applyServerReferenceWrapping(code, s, effectiveMap);
|
|
346
|
+
const changed2 = applyRegisterReferenceWrapping(code, s, hashToFileMap);
|
|
347
|
+
if (changed1 || changed2) {
|
|
348
|
+
return {
|
|
349
|
+
code: s.toString(),
|
|
350
|
+
map: s.generateMap({
|
|
351
|
+
source: chunk.fileName,
|
|
352
|
+
includeContent: true,
|
|
353
|
+
}),
|
|
354
|
+
};
|
|
335
355
|
}
|
|
356
|
+
return null;
|
|
336
357
|
}
|
|
337
358
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
return null;
|
|
359
|
+
// Non-RSC environments: only transform createServerReference calls
|
|
360
|
+
return transformServerReferences(code, chunk.fileName, effectiveMap);
|
|
342
361
|
},
|
|
343
362
|
};
|
|
344
363
|
}
|