@vitejs/plugin-rsc 0.5.14 → 0.5.15

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 CHANGED
@@ -245,6 +245,33 @@ ssrModule.renderHTML(...);
245
245
  export function renderHTML(...) {}
246
246
  ```
247
247
 
248
+ #### `import.meta.viteRsc.import`
249
+
250
+ - Type: `<T>(specifier: string, options: { environment: string }) => Promise<T>`
251
+
252
+ A more ergonomic alternative to `loadModule`:
253
+
254
+ 1. No manual `rollupOptions.input` config needed - entries are auto-discovered
255
+ 2. Specifier matches the path in `typeof import(...)` type annotations
256
+
257
+ **Comparison:**
258
+
259
+ ```ts
260
+ // Before (loadModule) - requires vite.config.ts:
261
+ // environments.ssr.build.rollupOptions.input = { index: './entry.ssr.tsx' }
262
+ import.meta.viteRsc.loadModule<typeof import('./entry.ssr.tsx')>('ssr', 'index')
263
+
264
+ // After (import) - no config needed, auto-discovered
265
+ import.meta.viteRsc.import<typeof import('./entry.ssr.tsx')>(
266
+ './entry.ssr.tsx',
267
+ { environment: 'ssr' },
268
+ )
269
+ ```
270
+
271
+ During development, this works the same as `loadModule`, using the `__VITE_ENVIRONMENT_RUNNER_IMPORT__` function to import modules in the target environment.
272
+
273
+ During production build, the plugin auto-discovers these imports and emits them as entries in the target environment. A manifest file (`__vite_rsc_env_imports_manifest.js`) is generated to map module specifiers to their output filenames.
274
+
248
275
  ### Available on `rsc` environment
249
276
 
250
277
  #### `import.meta.viteRsc.loadCss`
@@ -616,6 +643,13 @@ Note that while there are official npm packages [`server-only`](https://www.npmj
616
643
 
617
644
  This build-time validation is enabled by default and can be disabled by setting `validateImports: false` in the plugin options.
618
645
 
646
+ ## Architecture Documentation
647
+
648
+ For developers interested in the internal architecture:
649
+
650
+ - **[docs/architecture.md](docs/architecture.md)** - Build pipeline, data flow, and key components
651
+ - **[docs/bundler-comparison.md](docs/bundler-comparison.md)** - How different bundlers approach RSC
652
+
619
653
  ## Credits
620
654
 
621
655
  This project builds on fundamental techniques and insights from pioneering Vite RSC implementations.
package/dist/core/ssr.js CHANGED
@@ -9,10 +9,7 @@ function setRequireModule(options) {
9
9
  const requireModule = memoize((id) => {
10
10
  return options.load(removeReferenceCacheTag(id));
11
11
  });
12
- const clientRequire = (id) => {
13
- return requireModule(id);
14
- };
15
- globalThis.__vite_rsc_client_require__ = clientRequire;
12
+ globalThis.__vite_rsc_client_require__ = requireModule;
16
13
  setInternalRequire();
17
14
  }
18
15
  function createServerConsumerManifest() {
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import "./index-CFOPl4Gi.js";
2
- import vitePluginRsc, { PluginApi, RscPluginOptions, getPluginApi } from "./plugin.js";
1
+ import { c as getPluginApi, r as PluginApi, s as RscPluginOptions, u as vitePluginRsc } from "./plugin-V6VFxi_0.js";
2
+ import "./index-DJ0AhQ9B.js";
3
3
  export { type PluginApi, type RscPluginOptions, vitePluginRsc as default, getPluginApi };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./cjs-DH9Oa3zy.js";
2
- import { r as vitePluginRsc, t as getPluginApi } from "./plugin-Ch1dPqbr.js";
2
+ import { r as vitePluginRsc, t as getPluginApi } from "./plugin-DBWiu_Dx.js";
3
3
  import "./transforms-D4jDIHgD.js";
4
4
  import "./rpc-DbBe389F.js";
5
5
 
@@ -155,65 +155,6 @@ async function findSourceMapURL(server, filename, environmentName) {
155
155
  };
156
156
  }
157
157
 
158
- //#endregion
159
- //#region src/plugins/resolved-id-proxy.ts
160
- const RESOLVED_ID_PROXY_PREFIX = "virtual:vite-rsc/resolved-id/";
161
- function toResolvedIdProxy(resolvedId) {
162
- return RESOLVED_ID_PROXY_PREFIX + encodeURIComponent(resolvedId);
163
- }
164
- function withResolvedIdProxy(resolvedId) {
165
- return resolvedId.startsWith("\0") ? toResolvedIdProxy(resolvedId) : resolvedId;
166
- }
167
- function fromResolvedIdProxy(source) {
168
- if (!source.startsWith(RESOLVED_ID_PROXY_PREFIX)) return;
169
- const clean = source.split("?")[0];
170
- return decodeURIComponent(clean.slice(29));
171
- }
172
- /**
173
- * Vite plugin that resolves proxy import specifiers to the original resolved IDs.
174
- */
175
- function vitePluginResolvedIdProxy() {
176
- return {
177
- name: "rsc:resolved-id-proxy",
178
- resolveId: { handler(source) {
179
- const originalId = fromResolvedIdProxy(source);
180
- if (originalId !== void 0) return originalId;
181
- } }
182
- };
183
- }
184
-
185
- //#endregion
186
- //#region src/plugins/scan.ts
187
- function scanBuildStripPlugin({ manager }) {
188
- return {
189
- name: "rsc:scan-strip",
190
- apply: "build",
191
- enforce: "post",
192
- async transform(code, _id, _options) {
193
- if (!manager.isScanBuild) return;
194
- return {
195
- code: await transformScanBuildStrip(code),
196
- map: { mappings: "" }
197
- };
198
- }
199
- };
200
- }
201
- const importGlobRE = /\bimport\.meta\.glob(?:<\w+>)?\s*\(/g;
202
- async function transformScanBuildStrip(code) {
203
- const [imports] = esModuleLexer.parse(code);
204
- let output = imports.map((e) => e.n && `import ${JSON.stringify(e.n)};\n`).filter(Boolean).join("");
205
- if (importGlobRE.test(code)) {
206
- walk(await parseAstAsync(code), { enter(node) {
207
- if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && node.callee.object.type === "MetaProperty" && node.callee.object.meta.type === "Identifier" && node.callee.object.meta.name === "import" && node.callee.object.property.type === "Identifier" && node.callee.object.property.name === "meta" && node.callee.property.type === "Identifier" && node.callee.property.name === "glob") {
208
- const importMetaGlob = code.slice(node.start, node.end);
209
- output += `console.log(${importMetaGlob});\n`;
210
- }
211
- } });
212
- output += "";
213
- }
214
- return output;
215
- }
216
-
217
158
  //#endregion
218
159
  //#region src/plugins/utils.ts
219
160
  function sortObject(o) {
@@ -284,6 +225,183 @@ function getFetchHandlerExport(exports) {
284
225
  throw new Error("Invalid server handler entry");
285
226
  }
286
227
 
228
+ //#endregion
229
+ //#region src/plugins/import-environment.ts
230
+ const ENV_IMPORTS_MANIFEST_NAME = "__vite_rsc_env_imports_manifest.js";
231
+ const ENV_IMPORTS_MANIFEST_PLACEHOLDER = "virtual:vite-rsc/env-imports-manifest";
232
+ const ENV_IMPORTS_ENTRY_FALLBACK = "virtual:vite-rsc/env-imports-entry-fallback";
233
+ function ensureEnvironmentImportsEntryFallback({ environments }) {
234
+ for (const [name, config] of Object.entries(environments)) {
235
+ if (name === "client") continue;
236
+ const input = normalizeRollupOpitonsInput(config.build?.rollupOptions?.input);
237
+ if (Object.keys(input).length === 0) {
238
+ config.build = config.build || {};
239
+ config.build.rollupOptions = config.build.rollupOptions || {};
240
+ config.build.rollupOptions.input = { __vite_rsc_env_imports_entry_fallback: ENV_IMPORTS_ENTRY_FALLBACK };
241
+ }
242
+ }
243
+ }
244
+ function vitePluginImportEnvironment(manager) {
245
+ return [{
246
+ name: "rsc:import-environment",
247
+ resolveId(source) {
248
+ if (source === ENV_IMPORTS_MANIFEST_PLACEHOLDER) return {
249
+ id: ENV_IMPORTS_MANIFEST_PLACEHOLDER,
250
+ external: true
251
+ };
252
+ },
253
+ buildStart() {
254
+ if (this.environment.mode !== "build") return;
255
+ const emitted = /* @__PURE__ */ new Set();
256
+ for (const byTargetEnv of Object.values(manager.environmentImportMetaMap)) {
257
+ const imports = byTargetEnv[this.environment.name];
258
+ if (!imports) continue;
259
+ for (const meta of Object.values(imports)) if (!emitted.has(meta.resolvedId)) {
260
+ emitted.add(meta.resolvedId);
261
+ this.emitFile({
262
+ type: "chunk",
263
+ id: meta.resolvedId
264
+ });
265
+ }
266
+ }
267
+ },
268
+ transform: { async handler(code, id) {
269
+ if (!code.includes("import.meta.viteRsc.import")) return;
270
+ const { server } = manager;
271
+ const s = new MagicString(code);
272
+ for (const match of stripLiteral(code).matchAll(/import\.meta\.viteRsc\.import\s*(<[\s\S]*?>)?\s*\(([\s\S]*?)\)/dg)) {
273
+ const [argStart, argEnd] = match.indices[2];
274
+ const [specifier, options] = evalValue(`[${code.slice(argStart, argEnd).trim()}]`);
275
+ const environmentName = options.environment;
276
+ let resolvedId;
277
+ if (this.environment.mode === "dev") {
278
+ const targetEnv$1 = server.environments[environmentName];
279
+ assert(targetEnv$1, `[vite-rsc] unknown environment '${environmentName}'`);
280
+ const resolved = await targetEnv$1.pluginContainer.resolveId(specifier, id);
281
+ assert(resolved, `[vite-rsc] failed to resolve '${specifier}' in environment '${environmentName}'`);
282
+ resolvedId = resolved.id;
283
+ } else {
284
+ const targetEnvConfig = manager.config.environments[environmentName];
285
+ assert(targetEnvConfig, `[vite-rsc] unknown environment '${environmentName}'`);
286
+ const resolved = await this.resolve(specifier, id);
287
+ assert(resolved, `[vite-rsc] failed to resolve '${specifier}' in environment '${environmentName}'`);
288
+ resolvedId = resolved.id;
289
+ }
290
+ const sourceEnv = this.environment.name;
291
+ const targetEnv = environmentName;
292
+ manager.environmentImportMetaMap[sourceEnv] ??= {};
293
+ manager.environmentImportMetaMap[sourceEnv][targetEnv] ??= {};
294
+ manager.environmentImportMetaMap[sourceEnv][targetEnv][resolvedId] = {
295
+ resolvedId,
296
+ targetEnv,
297
+ sourceEnv,
298
+ specifier
299
+ };
300
+ let replacement;
301
+ if (this.environment.mode === "dev") replacement = `globalThis.__VITE_ENVIRONMENT_RUNNER_IMPORT__(${JSON.stringify(environmentName)}, ${JSON.stringify(resolvedId)})`;
302
+ else {
303
+ const relativeId = manager.toRelativeId(resolvedId);
304
+ replacement = `(await import(${JSON.stringify(ENV_IMPORTS_MANIFEST_PLACEHOLDER)})).default[${JSON.stringify(relativeId)}]()`;
305
+ }
306
+ const [start, end] = match.indices[0];
307
+ s.overwrite(start, end, replacement);
308
+ }
309
+ if (s.hasChanged()) return {
310
+ code: s.toString(),
311
+ map: s.generateMap({ hires: "boundary" })
312
+ };
313
+ } },
314
+ renderChunk(code, chunk) {
315
+ if (code.includes(ENV_IMPORTS_MANIFEST_PLACEHOLDER)) {
316
+ const replacement = normalizeRelativePath(path.relative(path.join(chunk.fileName, ".."), ENV_IMPORTS_MANIFEST_NAME));
317
+ code = code.replaceAll(ENV_IMPORTS_MANIFEST_PLACEHOLDER, () => replacement);
318
+ return { code };
319
+ }
320
+ }
321
+ }, createVirtualPlugin(ENV_IMPORTS_ENTRY_FALLBACK.slice(8), () => {
322
+ return `export default "__vite_rsc_env_imports_entry_fallback";`;
323
+ })];
324
+ }
325
+ function writeEnvironmentImportsManifest(manager) {
326
+ if (Object.keys(manager.environmentImportMetaMap).length === 0) return;
327
+ for (const [sourceEnv, byTargetEnv] of Object.entries(manager.environmentImportMetaMap)) {
328
+ const sourceOutDir = manager.config.environments[sourceEnv].build.outDir;
329
+ const manifestPath = path.join(sourceOutDir, ENV_IMPORTS_MANIFEST_NAME);
330
+ let code = "export default {\n";
331
+ for (const [_targetEnv, imports] of Object.entries(byTargetEnv)) for (const [resolvedId, meta] of Object.entries(imports)) {
332
+ const bundle = manager.bundles[meta.targetEnv];
333
+ if (!bundle) throw new Error(`[vite-rsc] missing bundle for environment import: ${meta.targetEnv}`);
334
+ const chunk = Object.values(bundle).find((c) => c.type === "chunk" && c.facadeModuleId === resolvedId);
335
+ if (!chunk) throw new Error(`[vite-rsc] missing output for environment import: ${resolvedId}`);
336
+ const targetOutDir = manager.config.environments[meta.targetEnv].build.outDir;
337
+ const relativePath = normalizeRelativePath(path.relative(sourceOutDir, path.join(targetOutDir, chunk.fileName)));
338
+ const relativeId = manager.toRelativeId(resolvedId);
339
+ code += ` ${JSON.stringify(relativeId)}: () => import(${JSON.stringify(relativePath)}),\n`;
340
+ }
341
+ code += "}\n";
342
+ fs.writeFileSync(manifestPath, code);
343
+ }
344
+ }
345
+
346
+ //#endregion
347
+ //#region src/plugins/resolved-id-proxy.ts
348
+ const RESOLVED_ID_PROXY_PREFIX = "virtual:vite-rsc/resolved-id/";
349
+ function toResolvedIdProxy(resolvedId) {
350
+ return RESOLVED_ID_PROXY_PREFIX + encodeURIComponent(resolvedId);
351
+ }
352
+ function withResolvedIdProxy(resolvedId) {
353
+ return resolvedId.startsWith("\0") ? toResolvedIdProxy(resolvedId) : resolvedId;
354
+ }
355
+ function fromResolvedIdProxy(source) {
356
+ if (!source.startsWith(RESOLVED_ID_PROXY_PREFIX)) return;
357
+ const clean = source.split("?")[0];
358
+ return decodeURIComponent(clean.slice(29));
359
+ }
360
+ /**
361
+ * Vite plugin that resolves proxy import specifiers to the original resolved IDs.
362
+ */
363
+ function vitePluginResolvedIdProxy() {
364
+ return {
365
+ name: "rsc:resolved-id-proxy",
366
+ resolveId: { handler(source) {
367
+ const originalId = fromResolvedIdProxy(source);
368
+ if (originalId !== void 0) return originalId;
369
+ } }
370
+ };
371
+ }
372
+
373
+ //#endregion
374
+ //#region src/plugins/scan.ts
375
+ function scanBuildStripPlugin({ manager }) {
376
+ return {
377
+ name: "rsc:scan-strip",
378
+ apply: "build",
379
+ enforce: "post",
380
+ async transform(code, _id, _options) {
381
+ if (!manager.isScanBuild) return;
382
+ return {
383
+ code: await transformScanBuildStrip(code),
384
+ map: { mappings: "" }
385
+ };
386
+ }
387
+ };
388
+ }
389
+ const importGlobRE = /\bimport\.meta\.glob(?:<\w+>)?\s*\(/g;
390
+ async function transformScanBuildStrip(code) {
391
+ const [imports] = esModuleLexer.parse(code);
392
+ let output = imports.map((e) => e.n && `import ${JSON.stringify(e.n)};\n`).filter(Boolean).join("");
393
+ if (importGlobRE.test(code)) {
394
+ walk(await parseAstAsync(code), { enter(node) {
395
+ if (node.type === "CallExpression" && node.callee.type === "MemberExpression" && node.callee.object.type === "MetaProperty" && node.callee.object.meta.type === "Identifier" && node.callee.object.meta.name === "import" && node.callee.object.property.type === "Identifier" && node.callee.object.property.name === "meta" && node.callee.property.type === "Identifier" && node.callee.property.name === "glob") {
396
+ const importMetaGlob = code.slice(node.start, node.end);
397
+ output += `console.log(${importMetaGlob});\n`;
398
+ }
399
+ } });
400
+ output += "";
401
+ }
402
+ return output;
403
+ }
404
+
287
405
  //#endregion
288
406
  //#region src/plugins/validate-import.ts
289
407
  function validateImportPlugin() {
@@ -380,13 +498,14 @@ function resolvePackage(name) {
380
498
  var RscPluginManager = class {
381
499
  server;
382
500
  config;
383
- rscBundle;
501
+ bundles = {};
384
502
  buildAssetsManifest;
385
503
  isScanBuild = false;
386
504
  clientReferenceMetaMap = {};
387
505
  clientReferenceGroups = {};
388
506
  serverReferenceMetaMap = {};
389
507
  serverResourcesMetaMap = {};
508
+ environmentImportMetaMap = {};
390
509
  stabilize() {
391
510
  this.clientReferenceMetaMap = sortObject(this.clientReferenceMetaMap);
392
511
  this.serverResourcesMetaMap = sortObject(this.serverResourcesMetaMap);
@@ -401,6 +520,9 @@ var RscPluginManager = class {
401
520
  fs.writeFileSync(manifestPath, assetsManifestCode);
402
521
  }
403
522
  }
523
+ writeEnvironmentImportsManifest() {
524
+ writeEnvironmentImportsManifest(this);
525
+ }
404
526
  };
405
527
  /** @experimental */
406
528
  function getPluginApi(config) {
@@ -465,29 +587,11 @@ function vitePluginRsc(rscPluginOptions = {}) {
465
587
  const logStep = (msg) => {
466
588
  builder.config.logger.info(colors.blue(msg));
467
589
  };
468
- if (!builder.environments.ssr?.config.build.rollupOptions.input) {
469
- manager.isScanBuild = true;
470
- builder.environments.rsc.config.build.write = false;
471
- builder.environments.client.config.build.write = false;
472
- logStep("[1/4] analyze client references...");
473
- await builder.build(builder.environments.rsc);
474
- logStep("[2/4] analyze server references...");
475
- await builder.build(builder.environments.client);
476
- manager.isScanBuild = false;
477
- builder.environments.rsc.config.build.write = true;
478
- builder.environments.client.config.build.write = true;
479
- logStep("[3/4] build rsc environment...");
480
- await builder.build(builder.environments.rsc);
481
- manager.stabilize();
482
- logStep("[4/4] build client environment...");
483
- await builder.build(builder.environments.client);
484
- manager.writeAssetsManifest(["rsc"]);
485
- return;
486
- }
487
590
  const rscOutDir = builder.environments.rsc.config.build.outDir;
488
591
  const ssrOutDir = builder.environments.ssr.config.build.outDir;
489
592
  const rscInsideSsr = path.normalize(rscOutDir).startsWith(path.normalize(ssrOutDir) + path.sep);
490
593
  const tempRscOutDir = path.join(builder.config.root, "node_modules", ".vite-rsc-temp", "rsc");
594
+ ensureEnvironmentImportsEntryFallback(builder.config);
491
595
  manager.isScanBuild = true;
492
596
  builder.environments.rsc.config.build.write = false;
493
597
  builder.environments.ssr.config.build.write = false;
@@ -516,6 +620,7 @@ function vitePluginRsc(rscPluginOptions = {}) {
516
620
  fs.renameSync(tempRscOutDir, rscOutDir);
517
621
  }
518
622
  manager.writeAssetsManifest(["ssr", "rsc"]);
623
+ manager.writeEnvironmentImportsManifest();
519
624
  };
520
625
  let hasReactServerDomWebpack = false;
521
626
  return [
@@ -874,18 +979,19 @@ export function createRpcClient(params) {
874
979
  assert(this.environment.mode === "dev");
875
980
  const manifest = {
876
981
  bootstrapScriptContent: `import(${serializeValueWithRuntime(assetsURL("@id/__x00__" + VIRTUAL_ENTRIES.browser, manager))})`,
877
- clientReferenceDeps: {}
982
+ clientReferenceDeps: {},
983
+ cssLinkPrecedence: rscPluginOptions.cssLinkPrecedence
878
984
  };
879
985
  return `export default ${JSON.stringify(manifest, null, 2)}`;
880
986
  }
881
987
  },
882
988
  generateBundle(_options, bundle) {
883
- if (this.environment.name === "rsc") manager.rscBundle = bundle;
989
+ manager.bundles[this.environment.name] = bundle;
884
990
  if (this.environment.name === "client") {
885
991
  const filterAssets = rscPluginOptions.copyServerAssetsToClient ?? (() => true);
886
992
  const rscBuildOptions = manager.config.environments.rsc.build;
887
993
  const rscViteManifest = typeof rscBuildOptions.manifest === "string" ? rscBuildOptions.manifest : rscBuildOptions.manifest && ".vite/manifest.json";
888
- for (const asset of Object.values(manager.rscBundle)) {
994
+ for (const asset of Object.values(manager.bundles["rsc"])) {
889
995
  if (asset.fileName === rscViteManifest) continue;
890
996
  if (asset.type === "asset" && filterAssets(asset.fileName)) this.emitFile({
891
997
  type: "asset",
@@ -894,30 +1000,35 @@ export function createRpcClient(params) {
894
1000
  });
895
1001
  }
896
1002
  const serverResources = {};
897
- const rscAssetDeps = collectAssetDeps(manager.rscBundle);
1003
+ const rscAssetDeps = collectAssetDeps(manager.bundles["rsc"]);
898
1004
  for (const [id, meta] of Object.entries(manager.serverResourcesMetaMap)) serverResources[meta.key] = assetsURLOfDeps({
899
1005
  js: [],
900
1006
  css: rscAssetDeps[id]?.deps.css ?? []
901
1007
  }, manager);
902
1008
  const assetDeps = collectAssetDeps(bundle);
903
- const entry = Object.values(assetDeps).find((v) => v.chunk.name === "index" && v.chunk.isEntry);
904
- assert(entry);
905
- const entryUrl = assetsURL(entry.chunk.fileName, manager);
1009
+ let bootstrapScriptContent = "";
906
1010
  const clientReferenceDeps = {};
907
1011
  for (const meta of Object.values(manager.clientReferenceMetaMap)) {
908
1012
  const deps = assetDeps[meta.groupChunkId]?.deps ?? {
909
1013
  js: [],
910
1014
  css: []
911
1015
  };
912
- clientReferenceDeps[meta.referenceKey] = assetsURLOfDeps(mergeAssetDeps(deps, entry.deps), manager);
1016
+ clientReferenceDeps[meta.referenceKey] = assetsURLOfDeps(deps, manager);
1017
+ }
1018
+ if (!rscPluginOptions.customClientEntry) {
1019
+ const entry = Object.values(assetDeps).find((v) => v.chunk.name === "index" && v.chunk.isEntry);
1020
+ if (!entry) throw new Error(`[vite-rsc] Client build must have an entry chunk named "index". Use 'customClientEntry' option to disable this requirement.`);
1021
+ const entryDeps = assetsURLOfDeps(entry.deps, manager);
1022
+ for (const [key, deps] of Object.entries(clientReferenceDeps)) clientReferenceDeps[key] = mergeAssetDeps(deps, entryDeps);
1023
+ const entryUrl = assetsURL(entry.chunk.fileName, manager);
1024
+ if (typeof entryUrl === "string") bootstrapScriptContent = `import(${JSON.stringify(entryUrl)})`;
1025
+ else bootstrapScriptContent = new RuntimeAsset(`"import(" + JSON.stringify(${entryUrl.runtime}) + ")"`);
913
1026
  }
914
- let bootstrapScriptContent;
915
- if (typeof entryUrl === "string") bootstrapScriptContent = `import(${JSON.stringify(entryUrl)})`;
916
- else bootstrapScriptContent = new RuntimeAsset(`"import(" + JSON.stringify(${entryUrl.runtime}) + ")"`);
917
1027
  manager.buildAssetsManifest = {
918
1028
  bootstrapScriptContent,
919
1029
  clientReferenceDeps,
920
- serverResources
1030
+ serverResources,
1031
+ cssLinkPrecedence: rscPluginOptions.cssLinkPrecedence
921
1032
  };
922
1033
  }
923
1034
  },
@@ -941,6 +1052,7 @@ export default assetsManifest.bootstrapScriptContent;
941
1052
  name: "rsc:bootstrap-script-content",
942
1053
  async transform(code) {
943
1054
  if (!code.includes("loadBootstrapScriptContent") || !/import\s*\.\s*meta\s*\.\s*viteRsc\s*\.\s*loadBootstrapScriptContent/.test(code)) return;
1055
+ assert(!rscPluginOptions.customClientEntry, `[vite-rsc] 'import.meta.viteRsc.loadBootstrapScriptContent' cannot be used with 'customClientEntry' option`);
944
1056
  assert(this.environment.name !== "client");
945
1057
  const output = new MagicString(code);
946
1058
  for (const match of stripLiteral(code).matchAll(/import\s*\.\s*meta\s*\.\s*viteRsc\s*\.\s*loadBootstrapScriptContent\(([\s\S]*?)\)/dg)) {
@@ -997,6 +1109,7 @@ import.meta.hot.on("rsc:update", () => {
997
1109
  return code;
998
1110
  }),
999
1111
  ...vitePluginRscMinimal(rscPluginOptions, manager),
1112
+ ...vitePluginImportEnvironment(manager),
1000
1113
  ...vitePluginFindSourceMapURL(),
1001
1114
  ...vitePluginRscCss(rscPluginOptions, manager),
1002
1115
  {
@@ -1661,13 +1774,13 @@ function vitePluginRscCss(rscCssOptions = {}, manager) {
1661
1774
  return generateResourcesCode(serializeValueWithRuntime(assetsURLOfDeps({
1662
1775
  css: result.hrefs.map((href) => href.slice(1)),
1663
1776
  js: []
1664
- }, manager)), manager);
1777
+ }, manager)), manager, { cssLinkPrecedence: rscCssOptions.cssLinkPrecedence });
1665
1778
  } else {
1666
1779
  const key = manager.toRelativeId(importer);
1667
1780
  manager.serverResourcesMetaMap[importer] = { key };
1668
1781
  return `
1669
1782
  import __vite_rsc_assets_manifest__ from "virtual:vite-rsc/assets-manifest";
1670
- ${generateResourcesCode(`__vite_rsc_assets_manifest__.serverResources[${JSON.stringify(key)}]`, manager)}
1783
+ ${generateResourcesCode(`__vite_rsc_assets_manifest__.serverResources[${JSON.stringify(key)}]`, manager, { cssLinkPrecedence: rscCssOptions.cssLinkPrecedence })}
1671
1784
  `;
1672
1785
  }
1673
1786
  }
@@ -1693,13 +1806,14 @@ export default function RemoveDuplicateServerCss() {
1693
1806
  })
1694
1807
  ];
1695
1808
  }
1696
- function generateResourcesCode(depsCode, manager) {
1697
- const ResourcesFn = (React, deps, RemoveDuplicateServerCss) => {
1809
+ function generateResourcesCode(depsCode, manager, options = {}) {
1810
+ const usePrecedence = options.cssLinkPrecedence !== false;
1811
+ const ResourcesFn = (React, deps, RemoveDuplicateServerCss, precedence) => {
1698
1812
  return function Resources() {
1699
1813
  return React.createElement(React.Fragment, null, [...deps.css.map((href) => React.createElement("link", {
1700
1814
  key: "css:" + href,
1701
1815
  rel: "stylesheet",
1702
- precedence: "vite-rsc/importer-resources",
1816
+ ...precedence ? { precedence } : {},
1703
1817
  href,
1704
1818
  "data-rsc-css-href": href
1705
1819
  })), RemoveDuplicateServerCss && React.createElement(RemoveDuplicateServerCss, { key: "remove-duplicate-css" })]);
@@ -1714,6 +1828,7 @@ export const Resources = (${ResourcesFn.toString()})(
1714
1828
  __vite_rsc_react__,
1715
1829
  ${depsCode},
1716
1830
  RemoveDuplicateServerCss,
1831
+ ${usePrecedence ? `"vite-rsc/importer-resources"` : `undefined`},
1717
1832
  );
1718
1833
  `;
1719
1834
  }
@@ -0,0 +1,193 @@
1
+ import { s as TransformWrapExportFilter } from "./index-DJ0AhQ9B.js";
2
+ import MagicString from "magic-string";
3
+ import { Plugin, ResolvedConfig, Rollup, ViteDevServer, parseAstAsync } from "vite";
4
+
5
+ //#region src/plugins/import-environment.d.ts
6
+ type EnvironmentImportMeta = {
7
+ resolvedId: string;
8
+ targetEnv: string;
9
+ sourceEnv: string;
10
+ specifier: string;
11
+ };
12
+ //#endregion
13
+ //#region src/plugin.d.ts
14
+ type ClientReferenceMeta = {
15
+ importId: string;
16
+ referenceKey: string;
17
+ packageSource?: string;
18
+ exportNames: string[];
19
+ renderedExports: string[];
20
+ serverChunk?: string;
21
+ groupChunkId?: string;
22
+ };
23
+ type ServerRerferenceMeta = {
24
+ importId: string;
25
+ referenceKey: string;
26
+ exportNames: string[];
27
+ };
28
+ /**
29
+ * @experimental
30
+ */
31
+ declare class RscPluginManager {
32
+ server: ViteDevServer;
33
+ config: ResolvedConfig;
34
+ bundles: Record<string, Rollup.OutputBundle>;
35
+ buildAssetsManifest: AssetsManifest | undefined;
36
+ isScanBuild: boolean;
37
+ clientReferenceMetaMap: Record<string, ClientReferenceMeta>;
38
+ clientReferenceGroups: Record<string, ClientReferenceMeta[]>;
39
+ serverReferenceMetaMap: Record<string, ServerRerferenceMeta>;
40
+ serverResourcesMetaMap: Record<string, {
41
+ key: string;
42
+ }>;
43
+ environmentImportMetaMap: Record<string, Record<string, Record<string, EnvironmentImportMeta>>>;
44
+ stabilize(): void;
45
+ toRelativeId(id: string): string;
46
+ writeAssetsManifest(environmentNames: string[]): void;
47
+ writeEnvironmentImportsManifest(): void;
48
+ }
49
+ type RscPluginOptions = {
50
+ /**
51
+ * shorthand for configuring `environments.(name).build.rollupOptions.input.index`
52
+ */
53
+ entries?: Partial<Record<"client" | "ssr" | "rsc", string>>;
54
+ /** @default { enviornmentName: "rsc", entryName: "index" } */
55
+ serverHandler?: {
56
+ environmentName: string;
57
+ entryName: string;
58
+ } | false;
59
+ /** @default false */
60
+ loadModuleDevProxy?: boolean;
61
+ rscCssTransform?: false | {
62
+ filter?: (id: string) => boolean;
63
+ };
64
+ /**
65
+ * This option allows customizing how client build copies assets from server build.
66
+ * By default, all assets are copied, but frameworks can establish server asset convention
67
+ * to tighten security using this option.
68
+ */
69
+ copyServerAssetsToClient?: (fileName: string) => boolean;
70
+ /**
71
+ * This option allows disabling action closure encryption for debugging purpose.
72
+ * @default true
73
+ */
74
+ enableActionEncryption?: boolean;
75
+ /**
76
+ * By default, the plugin uses a build-time generated encryption key for
77
+ * "use server" closure argument binding.
78
+ * This can be overwritten by configuring `defineEncryptionKey` option,
79
+ * for example, to obtain a key through environment variable during runtime.
80
+ * cf. https://nextjs.org/docs/app/guides/data-security#overwriting-encryption-keys-advanced
81
+ */
82
+ defineEncryptionKey?: string;
83
+ /** Escape hatch for Waku's `allowServer` */
84
+ keepUseCientProxy?: boolean;
85
+ /**
86
+ * Enable build-time validation of 'client-only' and 'server-only' imports
87
+ * @default true
88
+ */
89
+ validateImports?: boolean;
90
+ /**
91
+ * use `Plugin.buildApp` hook (introduced on Vite 7) instead of `builder.buildApp` configuration
92
+ * for better composability with other plugins.
93
+ * @default true since Vite 7
94
+ */
95
+ useBuildAppHook?: boolean;
96
+ /**
97
+ * Skip the default buildApp orchestration for downstream frameworks
98
+ * to implement custom build pipelines using `getPluginApi()`.
99
+ * @experimental
100
+ * @default false
101
+ */
102
+ customBuildApp?: boolean;
103
+ /**
104
+ * Custom environment configuration
105
+ * @experimental
106
+ * @default { browser: 'client', ssr: 'ssr', rsc: 'rsc' }
107
+ */
108
+ environment?: {
109
+ browser?: string;
110
+ ssr?: string;
111
+ rsc?: string;
112
+ };
113
+ /**
114
+ * Custom chunking strategy for client reference modules.
115
+ *
116
+ * This function allows you to group multiple client components into
117
+ * custom chunks instead of having each module in its own chunk.
118
+ * By default, client chunks are grouped by `meta.serverChunk`.
119
+ */
120
+ clientChunks?: (meta: {
121
+ /** client reference module id */
122
+ id: string;
123
+ /** normalized client reference module id */
124
+ normalizedId: string;
125
+ /** server chunk which includes a corresponding client reference proxy module */
126
+ serverChunk: string;
127
+ }) => string | undefined;
128
+ /**
129
+ * Controls whether CSS links use React's `precedence` attribute.
130
+ * @experimental
131
+ * @default true
132
+ */
133
+ cssLinkPrecedence?: boolean;
134
+ /**
135
+ * Opt out of the default "index" client entry convention.
136
+ * When enabled, the plugin will not:
137
+ * - Require an entry chunk named "index"
138
+ * - Automatically include client entry deps in each client reference's dependencies
139
+ *
140
+ * Note: `import.meta.viteRsc.loadBootstrapScriptContent` cannot be used with this option.
141
+ *
142
+ * Use this when you manually handle client entry setup and preloading.
143
+ *
144
+ * @experimental
145
+ * @default false
146
+ */
147
+ customClientEntry?: boolean;
148
+ };
149
+ type PluginApi = {
150
+ manager: RscPluginManager;
151
+ };
152
+ /** @experimental */
153
+ declare function getPluginApi(config: Pick<ResolvedConfig, "plugins">): PluginApi | undefined;
154
+ /** @experimental */
155
+ declare function vitePluginRscMinimal(rscPluginOptions?: RscPluginOptions, manager?: RscPluginManager): Plugin[];
156
+ declare global {
157
+ function __VITE_ENVIRONMENT_RUNNER_IMPORT__(environmentName: string, id: string): Promise<any>;
158
+ }
159
+ declare function vitePluginRsc(rscPluginOptions?: RscPluginOptions): Plugin[];
160
+ declare class RuntimeAsset {
161
+ runtime: string;
162
+ constructor(value: string);
163
+ }
164
+ type AssetsManifest = {
165
+ bootstrapScriptContent: string | RuntimeAsset;
166
+ clientReferenceDeps: Record<string, AssetDeps>;
167
+ serverResources?: Record<string, Pick<AssetDeps, "css">>;
168
+ cssLinkPrecedence?: boolean;
169
+ };
170
+ type AssetDeps = {
171
+ js: (string | RuntimeAsset)[];
172
+ css: (string | RuntimeAsset)[];
173
+ };
174
+ type ResolvedAssetsManifest = {
175
+ bootstrapScriptContent: string;
176
+ clientReferenceDeps: Record<string, ResolvedAssetDeps>;
177
+ serverResources?: Record<string, Pick<ResolvedAssetDeps, "css">>;
178
+ cssLinkPrecedence?: boolean;
179
+ };
180
+ type ResolvedAssetDeps = {
181
+ js: string[];
182
+ css: string[];
183
+ };
184
+ declare function transformRscCssExport(options: {
185
+ ast: Awaited<ReturnType<typeof parseAstAsync>>;
186
+ code: string;
187
+ id?: string;
188
+ filter: TransformWrapExportFilter;
189
+ }): Promise<{
190
+ output: MagicString;
191
+ } | undefined>;
192
+ //#endregion
193
+ export { ResolvedAssetsManifest as a, getPluginApi as c, vitePluginRscMinimal as d, ResolvedAssetDeps as i, transformRscCssExport as l, AssetsManifest as n, RscPluginManager as o, PluginApi as r, RscPluginOptions as s, AssetDeps as t, vitePluginRsc as u };
package/dist/plugin.d.ts CHANGED
@@ -1,161 +1,3 @@
1
- import { s as TransformWrapExportFilter } from "./index-CFOPl4Gi.js";
2
- import MagicString from "magic-string";
3
- import { Plugin, ResolvedConfig, Rollup, ViteDevServer, parseAstAsync } from "vite";
4
-
5
- //#region src/plugin.d.ts
6
- type ClientReferenceMeta = {
7
- importId: string;
8
- referenceKey: string;
9
- packageSource?: string;
10
- exportNames: string[];
11
- renderedExports: string[];
12
- serverChunk?: string;
13
- groupChunkId?: string;
14
- };
15
- type ServerRerferenceMeta = {
16
- importId: string;
17
- referenceKey: string;
18
- exportNames: string[];
19
- };
20
- /**
21
- * @experimental
22
- */
23
- declare class RscPluginManager {
24
- server: ViteDevServer;
25
- config: ResolvedConfig;
26
- rscBundle: Rollup.OutputBundle;
27
- buildAssetsManifest: AssetsManifest | undefined;
28
- isScanBuild: boolean;
29
- clientReferenceMetaMap: Record<string, ClientReferenceMeta>;
30
- clientReferenceGroups: Record<string, ClientReferenceMeta[]>;
31
- serverReferenceMetaMap: Record<string, ServerRerferenceMeta>;
32
- serverResourcesMetaMap: Record<string, {
33
- key: string;
34
- }>;
35
- stabilize(): void;
36
- toRelativeId(id: string): string;
37
- writeAssetsManifest(environmentNames: string[]): void;
38
- }
39
- type RscPluginOptions = {
40
- /**
41
- * shorthand for configuring `environments.(name).build.rollupOptions.input.index`
42
- */
43
- entries?: Partial<Record<"client" | "ssr" | "rsc", string>>;
44
- /** @default { enviornmentName: "rsc", entryName: "index" } */
45
- serverHandler?: {
46
- environmentName: string;
47
- entryName: string;
48
- } | false;
49
- /** @default false */
50
- loadModuleDevProxy?: boolean;
51
- rscCssTransform?: false | {
52
- filter?: (id: string) => boolean;
53
- };
54
- /**
55
- * This option allows customizing how client build copies assets from server build.
56
- * By default, all assets are copied, but frameworks can establish server asset convention
57
- * to tighten security using this option.
58
- */
59
- copyServerAssetsToClient?: (fileName: string) => boolean;
60
- /**
61
- * This option allows disabling action closure encryption for debugging purpose.
62
- * @default true
63
- */
64
- enableActionEncryption?: boolean;
65
- /**
66
- * By default, the plugin uses a build-time generated encryption key for
67
- * "use server" closure argument binding.
68
- * This can be overwritten by configuring `defineEncryptionKey` option,
69
- * for example, to obtain a key through environment variable during runtime.
70
- * cf. https://nextjs.org/docs/app/guides/data-security#overwriting-encryption-keys-advanced
71
- */
72
- defineEncryptionKey?: string;
73
- /** Escape hatch for Waku's `allowServer` */
74
- keepUseCientProxy?: boolean;
75
- /**
76
- * Enable build-time validation of 'client-only' and 'server-only' imports
77
- * @default true
78
- */
79
- validateImports?: boolean;
80
- /**
81
- * use `Plugin.buildApp` hook (introduced on Vite 7) instead of `builder.buildApp` configuration
82
- * for better composability with other plugins.
83
- * @default true since Vite 7
84
- */
85
- useBuildAppHook?: boolean;
86
- /**
87
- * Skip the default buildApp orchestration for downstream frameworks
88
- * to implement custom build pipelines using `getPluginApi()`.
89
- * @experimental
90
- * @default false
91
- */
92
- customBuildApp?: boolean;
93
- /**
94
- * Custom environment configuration
95
- * @experimental
96
- * @default { browser: 'client', ssr: 'ssr', rsc: 'rsc' }
97
- */
98
- environment?: {
99
- browser?: string;
100
- ssr?: string;
101
- rsc?: string;
102
- };
103
- /**
104
- * Custom chunking strategy for client reference modules.
105
- *
106
- * This function allows you to group multiple client components into
107
- * custom chunks instead of having each module in its own chunk.
108
- * By default, client chunks are grouped by `meta.serverChunk`.
109
- */
110
- clientChunks?: (meta: {
111
- /** client reference module id */
112
- id: string;
113
- /** normalized client reference module id */
114
- normalizedId: string;
115
- /** server chunk which includes a corresponding client reference proxy module */
116
- serverChunk: string;
117
- }) => string | undefined;
118
- };
119
- type PluginApi = {
120
- manager: RscPluginManager;
121
- };
122
- /** @experimental */
123
- declare function getPluginApi(config: Pick<ResolvedConfig, "plugins">): PluginApi | undefined;
124
- /** @experimental */
125
- declare function vitePluginRscMinimal(rscPluginOptions?: RscPluginOptions, manager?: RscPluginManager): Plugin[];
126
- declare global {
127
- function __VITE_ENVIRONMENT_RUNNER_IMPORT__(environmentName: string, id: string): Promise<any>;
128
- }
129
- declare function vitePluginRsc(rscPluginOptions?: RscPluginOptions): Plugin[];
130
- declare class RuntimeAsset {
131
- runtime: string;
132
- constructor(value: string);
133
- }
134
- type AssetsManifest = {
135
- bootstrapScriptContent: string | RuntimeAsset;
136
- clientReferenceDeps: Record<string, AssetDeps>;
137
- serverResources?: Record<string, Pick<AssetDeps, "css">>;
138
- };
139
- type AssetDeps = {
140
- js: (string | RuntimeAsset)[];
141
- css: (string | RuntimeAsset)[];
142
- };
143
- type ResolvedAssetsManifest = {
144
- bootstrapScriptContent: string;
145
- clientReferenceDeps: Record<string, ResolvedAssetDeps>;
146
- serverResources?: Record<string, Pick<ResolvedAssetDeps, "css">>;
147
- };
148
- type ResolvedAssetDeps = {
149
- js: string[];
150
- css: string[];
151
- };
152
- declare function transformRscCssExport(options: {
153
- ast: Awaited<ReturnType<typeof parseAstAsync>>;
154
- code: string;
155
- id?: string;
156
- filter: TransformWrapExportFilter;
157
- }): Promise<{
158
- output: MagicString;
159
- } | undefined>;
160
- //#endregion
161
- export { AssetDeps, AssetsManifest, PluginApi, ResolvedAssetDeps, ResolvedAssetsManifest, type RscPluginManager, RscPluginOptions, vitePluginRsc as default, getPluginApi, transformRscCssExport, vitePluginRscMinimal };
1
+ import { a as ResolvedAssetsManifest, c as getPluginApi, d as vitePluginRscMinimal, i as ResolvedAssetDeps, l as transformRscCssExport, n as AssetsManifest, o as RscPluginManager, r as PluginApi, s as RscPluginOptions, t as AssetDeps, u as vitePluginRsc } from "./plugin-V6VFxi_0.js";
2
+ import "./index-DJ0AhQ9B.js";
3
+ export { AssetDeps, AssetsManifest, PluginApi, ResolvedAssetDeps, ResolvedAssetsManifest, RscPluginManager, RscPluginOptions, vitePluginRsc as default, getPluginApi, transformRscCssExport, vitePluginRscMinimal };
package/dist/plugin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "./cjs-DH9Oa3zy.js";
2
- import { i as vitePluginRscMinimal, n as transformRscCssExport, r as vitePluginRsc, t as getPluginApi } from "./plugin-Ch1dPqbr.js";
2
+ import { i as vitePluginRscMinimal, n as transformRscCssExport, r as vitePluginRsc, t as getPluginApi } from "./plugin-DBWiu_Dx.js";
3
3
  import "./transforms-D4jDIHgD.js";
4
4
  import "./rpc-DbBe389F.js";
5
5
 
package/dist/ssr.d.ts CHANGED
@@ -1,3 +1,24 @@
1
1
  import { createServerConsumerManifest, setRequireModule } from "./core/ssr.js";
2
+ import { i as ResolvedAssetDeps } from "./plugin-V6VFxi_0.js";
3
+ import "./index-DJ0AhQ9B.js";
2
4
  import { callServer, createFromReadableStream, createServerReference, findSourceMapURL } from "./react/ssr.js";
3
- export { callServer, createFromReadableStream, createServerConsumerManifest, createServerReference, findSourceMapURL, setRequireModule };
5
+
6
+ //#region src/ssr.d.ts
7
+
8
+ /**
9
+ * Callback type for client reference dependency notifications.
10
+ * Called during SSR when a client component's dependencies are loaded.
11
+ * @experimental
12
+ */
13
+ type OnClientReference = (reference: {
14
+ id: string;
15
+ deps: ResolvedAssetDeps;
16
+ }) => void;
17
+ /**
18
+ * Register a callback to be notified when client reference dependencies are loaded.
19
+ * Called during SSR when a client component is accessed.
20
+ * @experimental
21
+ */
22
+ declare function setOnClientReference(callback: OnClientReference | undefined): void;
23
+ //#endregion
24
+ export { OnClientReference, callServer, createFromReadableStream, createServerConsumerManifest, createServerReference, findSourceMapURL, setOnClientReference, setRequireModule };
package/dist/ssr.js CHANGED
@@ -6,6 +6,15 @@ import * as ReactDOM from "react-dom";
6
6
  import assetsManifest from "virtual:vite-rsc/assets-manifest";
7
7
 
8
8
  //#region src/ssr.tsx
9
+ let onClientReference;
10
+ /**
11
+ * Register a callback to be notified when client reference dependencies are loaded.
12
+ * Called during SSR when a client component is accessed.
13
+ * @experimental
14
+ */
15
+ function setOnClientReference(callback) {
16
+ onClientReference = callback;
17
+ }
9
18
  initialize();
10
19
  function initialize() {
11
20
  setRequireModule({ load: async (id) => {
@@ -20,7 +29,7 @@ function initialize() {
20
29
  return wrapResourceProxy(await import(
21
30
  /* @vite-ignore */
22
31
  id
23
- ), {
32
+ ), id, {
24
33
  js: [],
25
34
  css: (await import(
26
35
  /* @vite-ignore */
@@ -33,16 +42,27 @@ function initialize() {
33
42
  } else {
34
43
  const import_ = clientReferences.default[id];
35
44
  if (!import_) throw new Error(`client reference not found '${id}'`);
36
- const deps = assetsManifest.clientReferenceDeps[id];
37
- if (deps) preloadDeps(deps);
38
- return wrapResourceProxy(await import_(), deps);
45
+ const deps = assetsManifest.clientReferenceDeps[id] ?? {
46
+ js: [],
47
+ css: []
48
+ };
49
+ preloadDeps(deps);
50
+ onClientReference?.({
51
+ id,
52
+ deps
53
+ });
54
+ return wrapResourceProxy(await import_(), id, deps);
39
55
  }
40
56
  } });
41
57
  }
42
- function wrapResourceProxy(mod, deps) {
58
+ function wrapResourceProxy(mod, id, deps) {
43
59
  return new Proxy(mod, { get(target, p, receiver) {
44
60
  if (p in mod) {
45
- if (deps) preloadDeps(deps);
61
+ preloadDeps(deps);
62
+ onClientReference?.({
63
+ id,
64
+ deps
65
+ });
46
66
  }
47
67
  return Reflect.get(target, p, receiver);
48
68
  } });
@@ -54,9 +74,9 @@ function preloadDeps(deps) {
54
74
  });
55
75
  for (const href of deps.css) ReactDOM.preinit(href, {
56
76
  as: "style",
57
- precedence: "vite-rsc/client-reference"
77
+ precedence: assetsManifest.cssLinkPrecedence !== false ? "vite-rsc/client-reference" : void 0
58
78
  });
59
79
  }
60
80
 
61
81
  //#endregion
62
- export { callServer, createFromReadableStream, createServerConsumerManifest, createServerReference, findSourceMapURL, setRequireModule };
82
+ export { callServer, createFromReadableStream, createServerConsumerManifest, createServerReference, findSourceMapURL, setOnClientReference, setRequireModule };
@@ -1,2 +1,2 @@
1
- import { a as transformDirectiveProxyExport, c as TransformWrapExportOptions, d as transformHoistInlineDirective, i as TransformProxyExportOptions, l as transformWrapExport, n as getExportNames, o as transformProxyExport, r as hasDirective, s as TransformWrapExportFilter, t as transformServerActionServer, u as findDirectives } from "../index-CFOPl4Gi.js";
1
+ import { a as transformDirectiveProxyExport, c as TransformWrapExportOptions, d as transformHoistInlineDirective, i as TransformProxyExportOptions, l as transformWrapExport, n as getExportNames, o as transformProxyExport, r as hasDirective, s as TransformWrapExportFilter, t as transformServerActionServer, u as findDirectives } from "../index-DJ0AhQ9B.js";
2
2
  export { TransformProxyExportOptions, TransformWrapExportFilter, TransformWrapExportOptions, findDirectives, getExportNames, hasDirective, transformDirectiveProxyExport, transformHoistInlineDirective, transformProxyExport, transformServerActionServer, transformWrapExport };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-rsc",
3
- "version": "0.5.14",
3
+ "version": "0.5.15",
4
4
  "description": "React Server Components (RSC) support for Vite.",
5
5
  "keywords": [
6
6
  "react",
@@ -53,7 +53,7 @@
53
53
  "@playwright/test": "^1.57.0",
54
54
  "@tsconfig/strictest": "^2.0.8",
55
55
  "@types/estree": "^1.0.8",
56
- "@types/node": "^24.10.7",
56
+ "@types/node": "^24.10.9",
57
57
  "@types/react": "^19.2.8",
58
58
  "@types/react-dom": "^19.2.3",
59
59
  "@vitejs/plugin-react": "workspace:*",
@@ -75,5 +75,16 @@
75
75
  "react-server-dom-webpack": {
76
76
  "optional": true
77
77
  }
78
+ },
79
+ "compatiblePackages": {
80
+ "schemaVersion": 1,
81
+ "rolldown": {
82
+ "type": "incompatible",
83
+ "reason": "Uses Vite-specific APIs"
84
+ },
85
+ "rollup": {
86
+ "type": "incompatible",
87
+ "reason": "Uses Vite-specific APIs"
88
+ }
78
89
  }
79
90
  }
package/types/index.d.ts CHANGED
@@ -4,6 +4,29 @@ declare global {
4
4
  loadCss: (importer?: string) => import('react').ReactNode
5
5
  loadModule: <T>(environmentName: string, entryName?: string) => Promise<T>
6
6
  loadBootstrapScriptContent: (entryName: string) => Promise<string>
7
+ /**
8
+ * Import a module from another environment using a module specifier.
9
+ *
10
+ * A more ergonomic alternative to `loadModule` that takes a relative path
11
+ * instead of an entry name, so the specifier matches what you'd use in
12
+ * `typeof import(...)` type annotations.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const ssr = await import.meta.viteRsc.import<typeof import('./entry.ssr')>(
17
+ * './entry.ssr',
18
+ * { environment: 'ssr' }
19
+ * );
20
+ * ```
21
+ *
22
+ * @param specifier - Relative path to the module (e.g., './entry.ssr')
23
+ * @param options - Options object with `environment` specifying the target environment
24
+ * @returns Promise resolving to the module exports
25
+ */
26
+ import: <T>(
27
+ specifier: string,
28
+ options: { environment: string },
29
+ ) => Promise<T>
7
30
  }
8
31
  }
9
32