Skip to content

Commit 687458d

Browse files
hi-ogawaclaude
andauthored
feat(rsc): use __VITE_ENVIRONMENT_RUNNER_IMPORT__ for import.meta.viteRsc.loadModule global (#1037)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3fd9997 commit 687458d

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

packages/plugin-rsc/README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,9 @@ The plugin provides an additional helper for multi environment interaction.
228228

229229
This allows importing `ssr` environment module specified by `environments.ssr.build.rollupOptions.input[entryName]` inside `rsc` environment and vice versa.
230230

231-
During development, by default, this API assumes both `rsc` and `ssr` environments execute under the main Vite process. When enabling `rsc({ loadModuleDevProxy: true })` plugin option, the loaded module is implemented as a proxy with `fetch`-based RPC to call in node environment on the main Vite process, which for example, allows `rsc` environment inside cloudflare workers to access `ssr` environment on the main Vite process. This proxy mechanism uses [turbo-stream](https://github.com/jacob-ebey/turbo-stream) for serializing data types beyond JSON, with custom encoders/decoders to additionally support `Request` and `Response` instances.
231+
During development, by default, this API assumes both `rsc` and `ssr` environments execute under the main Vite process as `RunnableDevEnvironment`. Internally, `loadModule` uses the global `__VITE_ENVIRONMENT_RUNNER_IMPORT__` function to import modules in the target environment (see [`__VITE_ENVIRONMENT_RUNNER_IMPORT__`](#__vite_environment_runner_import__) below).
232+
233+
When enabling `rsc({ loadModuleDevProxy: true })` plugin option, the loaded module is implemented as a proxy with `fetch`-based RPC to call in node environment on the main Vite process, which for example, allows `rsc` environment inside cloudflare workers to access `ssr` environment on the main Vite process. This proxy mechanism uses [turbo-stream](https://github.com/jacob-ebey/turbo-stream) for serializing data types beyond JSON, with custom encoders/decoders to additionally support `Request` and `Response` instances.
232234

233235
During production build, this API will be rewritten into a static import of the specified entry of other environment build and the modules are executed inside the same runtime.
234236

@@ -327,6 +329,35 @@ import.meta.hot.on('rsc:update', async () => {
327329
})
328330
```
329331

332+
### Global API
333+
334+
#### `__VITE_ENVIRONMENT_RUNNER_IMPORT__`
335+
336+
- Type: `(environmentName: string, id: string) => Promise<any>`
337+
338+
This global function provides a standardized way to import a module in a given environment during development. It is used internally by `import.meta.viteRsc.loadModule` to execute modules in the target environment.
339+
340+
By default, the plugin sets this global to import via the environment's module runner:
341+
342+
```js
343+
globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__ = async (environmentName, id) => {
344+
return server.environments[environmentName].runner.import(id)
345+
}
346+
```
347+
348+
**Custom Environment Integration:**
349+
350+
Frameworks with custom environment setups (e.g., environments running in separate workers or with custom module loading) can override this global to provide their own module import logic.
351+
352+
```js
353+
// Custom logic to import module between multiple environments inside worker
354+
globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__ = async (environmentName, id) => {
355+
return myWorkerRunners[environmentname].import(id)
356+
}
357+
```
358+
359+
This allows `import.meta.viteRsc.loadModule` to work seamlessly with different runtime configurations without requiring changes to user code.
360+
330361
## Plugin API
331362

332363
### `@vitejs/plugin-rsc`

packages/plugin-rsc/src/plugin.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ export function vitePluginRscMinimal(
301301
]
302302
}
303303

304+
declare global {
305+
function __VITE_ENVIRONMENT_RUNNER_IMPORT__(
306+
environmentName: string,
307+
id: string,
308+
): Promise<any>
309+
}
310+
304311
export default function vitePluginRsc(
305312
rscPluginOptions: RscPluginOptions = {},
306313
): Plugin[] {
@@ -516,7 +523,23 @@ export default function vitePluginRsc(
516523
},
517524
},
518525
configureServer(server) {
519-
;(globalThis as any).__viteRscDevServer = server
526+
globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__ = async function (
527+
environmentName,
528+
id,
529+
) {
530+
const environment = server.environments[environmentName]
531+
if (!environment) {
532+
throw new Error(
533+
`[vite-rsc] unknown environment '${environmentName}'`,
534+
)
535+
}
536+
if (!vite.isRunnableDevEnvironment(environment)) {
537+
throw new Error(
538+
`[vite-rsc] environment '${environmentName}' is not runnable`,
539+
)
540+
}
541+
return environment.runner.import(id)
542+
}
520543

521544
// intercept client hmr to propagate client boundary invalidation to server environment
522545
const oldSend = server.environments.client.hot.send
@@ -768,10 +791,7 @@ export default function vitePluginRsc(
768791
const source = getEntrySource(environment.config, entryName)
769792
const resolved = await environment.pluginContainer.resolveId(source)
770793
assert(resolved, `[vite-rsc] failed to resolve entry '${source}'`)
771-
replacement =
772-
`globalThis.__viteRscDevServer.environments[${JSON.stringify(
773-
environmentName,
774-
)}]` + `.runner.import(${JSON.stringify(resolved.id)})`
794+
replacement = `globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__(${JSON.stringify(environmentName)}, ${JSON.stringify(resolved.id)})`
775795
} else {
776796
replacement = JSON.stringify(
777797
`__vite_rsc_load_module:${this.environment.name}:${environmentName}:${entryName}`,

0 commit comments

Comments
 (0)