@vitejs/plugin-rsc 0.4.12 → 0.4.14

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
@@ -11,7 +11,7 @@ This package provides [React Server Components](https://react.dev/reference/rsc/
11
11
 
12
12
  ## Getting Started
13
13
 
14
- You can start a project by copying an example locally by:
14
+ You can create a starter project by:
15
15
 
16
16
  ```sh
17
17
  npx degit vitejs/vite-plugin-react/packages/plugin-rsc/examples/starter my-app
@@ -22,11 +22,9 @@ npx degit vitejs/vite-plugin-react/packages/plugin-rsc/examples/starter my-app
22
22
  - [`./examples/starter`](./examples/starter)
23
23
  - This example provides an in-depth overview of API with inline comments to explain how they function within RSC-powered React application.
24
24
  - [`./examples/react-router`](./examples/react-router)
25
- - This demonstrates how to integrate [experimental React Router RSC API](https://remix.run/blog/rsc-preview) with this plugin.
26
- It also includes `@cloudflare/vite-plugin` integration.
25
+ - This demonstrates how to integrate [experimental React Router RSC API](https://remix.run/blog/rsc-preview). React Router now provides [official RSC support](https://reactrouter.com/how-to/react-server-components), so it's recommended to follow React Router's official documentation for the latest integration.
27
26
  - [`./examples/basic`](./examples/basic)
28
27
  - This is mainly used for e2e testing and include various advanced RSC usages (e.g. `"use cache"` example).
29
- It also uses a high level `@vitejs/plugin-rsc/extra/{rsc,ssr,browser}` API for quick setup.
30
28
  - [`./examples/ssg`](./examples/ssg)
31
29
  - Static site generation (SSG) example with MDX and client components for interactivity.
32
30
 
@@ -419,7 +417,10 @@ export default defineConfig({
419
417
  })
420
418
  ```
421
419
 
422
- ## Higher level API
420
+ ## High level API
421
+
422
+ > [!NOTE]
423
+ > High level API is deprecated. Please write on your own `@vitejs/plugin-rsc/{rsc,ssr,browser}` integration.
423
424
 
424
425
  This is a wrapper of `react-server-dom` API and helper API to setup a minimal RSC app without writing own framework code like [`./examples/starter/src/framework`](./examples/starter/src/framework/). See [`./examples/basic`](./examples/basic/) for how this API is used.
425
426
 
@@ -5,7 +5,7 @@ import * as clientReferences from "virtual:vite-rsc/client-references";
5
5
  initialize();
6
6
  function initialize() {
7
7
  setRequireModule({ load: async (id) => {
8
- if (!import.meta.env.__vite_rsc_build__) return __vite_rsc_raw_import__(import.meta.env.BASE_URL + id.slice(1));
8
+ if (!import.meta.env.__vite_rsc_build__) return __vite_rsc_raw_import__(withTrailingSlash(import.meta.env.BASE_URL) + id.slice(1));
9
9
  else {
10
10
  const import_ = clientReferences.default[id];
11
11
  if (!import_) throw new Error(`client reference not found '${id}'`);
@@ -13,5 +13,9 @@ function initialize() {
13
13
  }
14
14
  } });
15
15
  }
16
+ function withTrailingSlash(path) {
17
+ if (path[path.length - 1] !== "/") return `${path}/`;
18
+ return path;
19
+ }
16
20
 
17
21
  //#endregion
@@ -5,8 +5,6 @@ declare function createFromReadableStream<T>(stream: ReadableStream<Uint8Array>,
5
5
  declare function createFromFetch<T>(promiseForResponse: Promise<Response>, options?: object): Promise<T>;
6
6
  declare const encodeReply: (v: unknown[], options?: unknown) => Promise<string | FormData>;
7
7
  declare const createServerReference: (...args: any[]) => unknown;
8
- // use global instead of local variable to tolerate duplicate modules
9
- // e.g. when `setServerCallback` is pre-bundled but `createServerReference` is not
10
8
  declare function callServer(...args: any[]): any;
11
9
  declare function setServerCallback(fn: CallServerCallback): void;
12
10
  declare const createTemporaryReferenceSet: () => unknown;
package/dist/browser.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { CallServerCallback } from "./index-BHqtj9tT.js";
2
2
  import { setRequireModule } from "./browser-Dw18EFgE.js";
3
- import { callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setServerCallback } from "./browser-DjnGtEmB.js";
3
+ import { callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setServerCallback } from "./browser-CeSkQWD5.js";
4
4
  export { CallServerCallback, callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setRequireModule, setServerCallback };
package/dist/browser.js CHANGED
@@ -2,6 +2,6 @@ import "./dist-DEF94lDJ.js";
2
2
  import "./shared-CEyKoKAb.js";
3
3
  import { setRequireModule } from "./browser-QWbIPyhO.js";
4
4
  import { callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setServerCallback } from "./browser-D8OPzpF5.js";
5
- import "./browser-LizIyxet.js";
5
+ import "./browser-C1Q4O7AS.js";
6
6
 
7
7
  export { callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setRequireModule, setServerCallback };
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/rsc-html-stream@0.0.6/node_modules/rsc-html-stream/client.js
1
+ //#region ../../node_modules/.pnpm/rsc-html-stream@0.0.7/node_modules/rsc-html-stream/client.js
2
2
  let encoder = new TextEncoder();
3
3
  let streamController;
4
4
  let rscStream = new ReadableStream({ start(controller) {
@@ -1,7 +1,14 @@
1
- import { RscPayload } from "../rsc-Cmvt9txp.js";
1
+ import { RscPayload } from "../rsc-DryRyKqc.js";
2
2
 
3
3
  //#region src/extra/browser.d.ts
4
+
5
+ /**
6
+ * @deprecated Use `@vitejs/plugin-rsc/browser` API instead.
7
+ */
4
8
  declare function hydrate(): Promise<void>;
9
+ /**
10
+ * @deprecated Use `@vitejs/plugin-rsc/browser` API instead.
11
+ */
5
12
  declare function fetchRSC(request: string | URL | Request): Promise<RscPayload["root"]>;
6
13
  //#endregion
7
14
  export { fetchRSC, hydrate };
@@ -2,13 +2,16 @@ import "../dist-DEF94lDJ.js";
2
2
  import "../shared-CEyKoKAb.js";
3
3
  import "../browser-QWbIPyhO.js";
4
4
  import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback } from "../browser-D8OPzpF5.js";
5
- import "../browser-LizIyxet.js";
6
- import { rscStream } from "../client-edAdk2GF.js";
5
+ import "../browser-C1Q4O7AS.js";
6
+ import { rscStream } from "../client-CPc-spDn.js";
7
7
  import React from "react";
8
8
  import ReactDomClient from "react-dom/client";
9
9
  import { jsx } from "react/jsx-runtime";
10
10
 
11
11
  //#region src/extra/browser.tsx
12
+ /**
13
+ * @deprecated Use `@vitejs/plugin-rsc/browser` API instead.
14
+ */
12
15
  async function hydrate() {
13
16
  const callServer = async (id, args) => {
14
17
  const url = new URL(window.location.href);
@@ -45,6 +48,9 @@ async function hydrate() {
45
48
  window.history.replaceState({}, "", window.location.href);
46
49
  });
47
50
  }
51
+ /**
52
+ * @deprecated Use `@vitejs/plugin-rsc/browser` API instead.
53
+ */
48
54
  async function fetchRSC(request) {
49
55
  const payload = await createFromFetch(fetch(request));
50
56
  return payload.root;
@@ -1,2 +1,2 @@
1
- import { RscPayload, renderRequest } from "../rsc-Cmvt9txp.js";
1
+ import { RscPayload, renderRequest } from "../rsc-DryRyKqc.js";
2
2
  export { RscPayload, renderRequest };
package/dist/extra/rsc.js CHANGED
@@ -3,10 +3,13 @@ import "../shared-CEyKoKAb.js";
3
3
  import "../encryption-utils-BDwwcMVT.js";
4
4
  import { loadServerAction } from "../rsc-DKA6wwTB.js";
5
5
  import { createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, renderToReadableStream } from "../rsc-DHfL29FT.js";
6
- import "../rsc-DmPsJrxF.js";
6
+ import "../rsc-BIUd01vh.js";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
 
9
9
  //#region src/extra/rsc.tsx
10
+ /**
11
+ * @deprecated Use `@vitejs/plugin-rsc/rsc` API instead.
12
+ */
10
13
  async function renderRequest(request, root, options) {
11
14
  function RscRoot() {
12
15
  const nonceMeta = options?.nonce && /* @__PURE__ */ jsx("meta", {
@@ -1,6 +1,10 @@
1
1
  import { ReactFormState } from "react-dom/client";
2
2
 
3
3
  //#region src/extra/ssr.d.ts
4
+
5
+ /**
6
+ * @deprecated Use `@vitejs/plugin-rsc/ssr` API instead.
7
+ */
4
8
  declare function renderHtml(rscStream: ReadableStream<Uint8Array>, options?: {
5
9
  formState?: ReactFormState;
6
10
  nonce?: string;
package/dist/extra/ssr.js CHANGED
@@ -2,13 +2,16 @@ import "../dist-DEF94lDJ.js";
2
2
  import "../shared-CEyKoKAb.js";
3
3
  import "../ssr-BOIYlvSn.js";
4
4
  import { createFromReadableStream } from "../ssr-D5pxP29F.js";
5
- import "../ssr-Do_Ok_bB.js";
6
- import { injectRSCPayload } from "../server-DS3S6m0g.js";
5
+ import "../ssr-DNwSdZ9T.js";
6
+ import { injectRSCPayload } from "../server-C50j-DRF.js";
7
7
  import React from "react";
8
8
  import { jsx } from "react/jsx-runtime";
9
9
  import ReactDomServer from "react-dom/server.edge";
10
10
 
11
11
  //#region src/extra/ssr.tsx
12
+ /**
13
+ * @deprecated Use `@vitejs/plugin-rsc/ssr` API instead.
14
+ */
12
15
  async function renderHtml(rscStream, options) {
13
16
  const [rscStream1, rscStream2] = rscStream.tee();
14
17
  let payload;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { RscPluginOptions, vitePluginRsc } from "./plugin-Dg2agPFN.js";
1
+ import { RscPluginOptions, vitePluginRsc } from "./plugin-DXIhXGMa.js";
2
2
  import MagicString from "magic-string";
3
3
  import { Program } from "estree";
4
4
 
@@ -21,4 +21,4 @@ declare function transformHoistInlineDirective(input: string, ast: Program, {
21
21
  names: string[];
22
22
  };
23
23
  //#endregion
24
- export { RscPluginOptions, vitePluginRsc as default, transformHoistInlineDirective };
24
+ export { type RscPluginOptions, vitePluginRsc as default, transformHoistInlineDirective };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import "./dist-DEF94lDJ.js";
2
2
  import "./plugin-CZbI4rhS.js";
3
- import { transformHoistInlineDirective, vitePluginRsc } from "./plugin-BvUB-eig.js";
3
+ import { transformHoistInlineDirective, vitePluginRsc } from "./plugin-6e6xZIb7.js";
4
4
  import "./encryption-utils-BDwwcMVT.js";
5
5
  import "./rpc-tGuLT8PD.js";
6
- import "./vite-utils-CcqBE-C4.js";
6
+ import "./vite-utils-Vzd7cqfv.js";
7
7
 
8
8
  export { vitePluginRsc as default, transformHoistInlineDirective };
@@ -2,7 +2,7 @@ import { tinyassert } from "./dist-DEF94lDJ.js";
2
2
  import { vitePluginRscCore } from "./plugin-CZbI4rhS.js";
3
3
  import { generateEncryptionKey, toBase64 } from "./encryption-utils-BDwwcMVT.js";
4
4
  import { createRpcServer } from "./rpc-tGuLT8PD.js";
5
- import { normalizeViteImportAnalysisUrl } from "./vite-utils-CcqBE-C4.js";
5
+ import { normalizeViteImportAnalysisUrl, prepareError } from "./vite-utils-Vzd7cqfv.js";
6
6
  import { createRequire } from "node:module";
7
7
  import assert from "node:assert";
8
8
  import { createHash } from "node:crypto";
@@ -414,7 +414,7 @@ function vitePluginRsc(rscPluginOptions = {}) {
414
414
  clientReferenceMetaMap = sortObject(clientReferenceMetaMap);
415
415
  serverResourcesMetaMap = sortObject(serverResourcesMetaMap);
416
416
  await builder.build(builder.environments.client);
417
- const assetsManifestCode = `export default ${JSON.stringify(buildAssetsManifest, null, 2)}`;
417
+ const assetsManifestCode = `export default ${serializeValueWithRuntime(buildAssetsManifest)}`;
418
418
  const manifestPath = path.join(builder.environments.rsc.config.build.outDir, BUILD_ASSETS_MANIFEST_NAME);
419
419
  fs.writeFileSync(manifestPath, assetsManifestCode);
420
420
  return;
@@ -456,7 +456,7 @@ function vitePluginRsc(rscPluginOptions = {}) {
456
456
  const resolved = await environment.pluginContainer.resolveId(source);
457
457
  assert(resolved, `[vite-rsc] failed to resolve server handler '${source}'`);
458
458
  const mod = await environment.runner.import(resolved.id);
459
- createRequestListener(mod.default)(req, res);
459
+ await createRequestListener(mod.default)(req, res);
460
460
  } catch (e) {
461
461
  next(e);
462
462
  }
@@ -473,8 +473,9 @@ function vitePluginRsc(rscPluginOptions = {}) {
473
473
  const entryFile = path.join(config.environments[options.environmentName].build.outDir, `${options.entryName}.js`);
474
474
  const entry = pathToFileURL(entryFile).href;
475
475
  const mod = await import(
476
- /* @vite-ignore */
477
- entry);
476
+ /* @vite-ignore */
477
+ entry
478
+ );
478
479
  const handler = createRequestListener(mod.default);
479
480
  server$1.middlewares.use((req, _res, next) => {
480
481
  delete req.headers["accept-encoding"];
@@ -483,7 +484,7 @@ function vitePluginRsc(rscPluginOptions = {}) {
483
484
  return () => {
484
485
  server$1.middlewares.use(async (req, res, next) => {
485
486
  try {
486
- handler(req, res);
487
+ await handler(req, res);
487
488
  } catch (e) {
488
489
  next(e);
489
490
  }
@@ -509,11 +510,22 @@ function vitePluginRsc(rscPluginOptions = {}) {
509
510
  return mods.some((mod) => recurse(mod));
510
511
  }
511
512
  if (!isInsideClientBoundary(ctx.modules)) {
512
- if (this.environment.name === "rsc") ctx.server.environments.client.hot.send({
513
- type: "custom",
514
- event: "rsc:update",
515
- data: { file: ctx.file }
516
- });
513
+ if (this.environment.name === "rsc") {
514
+ for (const mod of ctx.modules) if (mod.type === "js") try {
515
+ await this.environment.transformRequest(mod.url);
516
+ } catch (e) {
517
+ server.environments.client.hot.send({
518
+ type: "error",
519
+ err: prepareError(e)
520
+ });
521
+ throw e;
522
+ }
523
+ ctx.server.environments.client.hot.send({
524
+ type: "custom",
525
+ event: "rsc:update",
526
+ data: { file: ctx.file }
527
+ });
528
+ }
517
529
  if (this.environment.name === "client") {
518
530
  const env = ctx.server.environments.rsc;
519
531
  const mod = env.moduleGraph.getModuleById(ctx.file);
@@ -642,7 +654,7 @@ function vitePluginRsc(rscPluginOptions = {}) {
642
654
  assert(this.environment.mode === "dev");
643
655
  const entryUrl = assetsURL("@id/__x00__" + VIRTUAL_ENTRIES.browser);
644
656
  const manifest = {
645
- bootstrapScriptContent: `import(${JSON.stringify(entryUrl)})`,
657
+ bootstrapScriptContent: `import(${serializeValueWithRuntime(entryUrl)})`,
646
658
  clientReferenceDeps: {}
647
659
  };
648
660
  return `export default ${JSON.stringify(manifest, null, 2)}`;
@@ -680,8 +692,11 @@ function vitePluginRsc(rscPluginOptions = {}) {
680
692
  };
681
693
  clientReferenceDeps[meta.referenceKey] = assetsURLOfDeps(mergeAssetDeps(deps, entry.deps));
682
694
  }
695
+ let bootstrapScriptContent;
696
+ if (typeof entryUrl === "string") bootstrapScriptContent = `import(${JSON.stringify(entryUrl)})`;
697
+ else bootstrapScriptContent = new RuntimeAsset(`"import(" + JSON.stringify(${entryUrl.runtime}) + ")"`);
683
698
  buildAssetsManifest = {
684
- bootstrapScriptContent: `import(${JSON.stringify(entryUrl)})`,
699
+ bootstrapScriptContent,
685
700
  clientReferenceDeps,
686
701
  serverResources
687
702
  };
@@ -698,7 +713,7 @@ function vitePluginRsc(rscPluginOptions = {}) {
698
713
  },
699
714
  writeBundle() {
700
715
  if (this.environment.name === "ssr") {
701
- const assetsManifestCode = `export default ${JSON.stringify(buildAssetsManifest, null, 2)}`;
716
+ const assetsManifestCode = `export default ${serializeValueWithRuntime(buildAssetsManifest)}`;
702
717
  for (const name of ["ssr", "rsc"]) {
703
718
  const manifestPath = path.join(config.environments[name].build.outDir, BUILD_ASSETS_MANIFEST_NAME);
704
719
  fs.writeFileSync(manifestPath, assetsManifestCode);
@@ -754,6 +769,11 @@ window.__vite_plugin_react_preamble_installed__ = true;
754
769
  code += `
755
770
  const ssrCss = document.querySelectorAll("link[rel='stylesheet']");
756
771
  import.meta.hot.on("vite:beforeUpdate", () => ssrCss.forEach(node => node.remove()));
772
+ `;
773
+ code += `
774
+ import.meta.hot.on("rsc:update", () => {
775
+ document.querySelectorAll("vite-error-overlay").forEach((n) => n.close())
776
+ });
757
777
  `;
758
778
  return code;
759
779
  }),
@@ -777,6 +797,7 @@ globalThis.AsyncLocalStorage = __viteRscAyncHooks.AsyncLocalStorage;
777
797
  ...vitePluginDefineEncryptionKey(rscPluginOptions),
778
798
  ...vitePluginFindSourceMapURL(),
779
799
  ...vitePluginRscCss({ rscCssTransform: rscPluginOptions.rscCssTransform }),
800
+ ...rscPluginOptions.validateImports !== false ? [validateImportPlugin()] : [],
780
801
  scanBuildStripPlugin()
781
802
  ];
782
803
  }
@@ -802,8 +823,7 @@ function normalizeRelativePath(s) {
802
823
  }
803
824
  function getEntrySource(config$1, name = "index") {
804
825
  const input = config$1.build.rollupOptions.input;
805
- assert(input);
806
- assert(typeof input === "object" && !Array.isArray(input) && name in input && typeof input[name] === "string");
826
+ assert(typeof input === "object" && !Array.isArray(input) && name in input && typeof input[name] === "string", `[vite-rsc:getEntrySource] expected 'build.rollupOptions.input' to be an object with a '${name}' property that is a string, but got ${JSON.stringify(input)}`);
807
827
  return input[name];
808
828
  }
809
829
  function hashString(v) {
@@ -1084,13 +1104,50 @@ function generateDynamicImportCode(map) {
1084
1104
  let code = Object.entries(map).map(([key, id]) => `${JSON.stringify(key)}: () => import(${JSON.stringify(id)}),`).join("\n");
1085
1105
  return `export default {${code}};\n`;
1086
1106
  }
1107
+ var RuntimeAsset = class {
1108
+ runtime;
1109
+ constructor(value) {
1110
+ this.runtime = value;
1111
+ }
1112
+ };
1113
+ function serializeValueWithRuntime(value) {
1114
+ const replacements = [];
1115
+ let result = JSON.stringify(value, (_key, value$1) => {
1116
+ if (value$1 instanceof RuntimeAsset) {
1117
+ const placeholder = `__runtime_placeholder_${replacements.length}__`;
1118
+ replacements.push([placeholder, value$1.runtime]);
1119
+ return placeholder;
1120
+ }
1121
+ return value$1;
1122
+ }, 2);
1123
+ for (const [placeholder, runtime] of replacements) result = result.replace(`"${placeholder}"`, runtime);
1124
+ return result;
1125
+ }
1087
1126
  function assetsURL(url) {
1127
+ if (config.command === "build" && typeof config.experimental?.renderBuiltUrl === "function") {
1128
+ const result = config.experimental.renderBuiltUrl(url, {
1129
+ type: "asset",
1130
+ hostType: "js",
1131
+ ssr: true,
1132
+ hostId: ""
1133
+ });
1134
+ if (typeof result === "object") {
1135
+ if (result.runtime) return new RuntimeAsset(result.runtime);
1136
+ assert(!result.relative, "\"result.relative\" not supported on renderBuiltUrl() for RSC");
1137
+ } else if (result) return result;
1138
+ }
1088
1139
  return config.base + url;
1089
1140
  }
1090
1141
  function assetsURLOfDeps(deps) {
1091
1142
  return {
1092
- js: deps.js.map((href) => assetsURL(href)),
1093
- css: deps.css.map((href) => assetsURL(href))
1143
+ js: deps.js.map((href) => {
1144
+ assert(typeof href === "string");
1145
+ return assetsURL(href);
1146
+ }),
1147
+ css: deps.css.map((href) => {
1148
+ assert(typeof href === "string");
1149
+ return assetsURL(href);
1150
+ })
1094
1151
  };
1095
1152
  }
1096
1153
  function mergeAssetDeps(a, b) {
@@ -1262,7 +1319,7 @@ function vitePluginRscCss(rscCssOptions) {
1262
1319
  const result = collectCss(server.environments.ssr, mod.id);
1263
1320
  for (const file of [mod.file, ...result.visitedFiles]) this.addWatchFile(file);
1264
1321
  const hrefs = result.hrefs.map((href) => assetsURL(href.slice(1)));
1265
- return `export default ${JSON.stringify(hrefs)}`;
1322
+ return `export default ${serializeValueWithRuntime(hrefs)}`;
1266
1323
  }
1267
1324
  }
1268
1325
  },
@@ -1324,7 +1381,7 @@ function vitePluginRscCss(rscCssOptions) {
1324
1381
  css: cssHrefs,
1325
1382
  js: jsHrefs
1326
1383
  });
1327
- return generateResourcesCode(JSON.stringify(deps, null, 2));
1384
+ return generateResourcesCode(serializeValueWithRuntime(deps));
1328
1385
  } else {
1329
1386
  const key = normalizePath(path.relative(config.root, importer));
1330
1387
  serverResourcesMetaMap[importer] = { key };
@@ -1462,6 +1519,35 @@ function __fix_cloudflare() {
1462
1519
  }
1463
1520
  };
1464
1521
  }
1522
+ function validateImportPlugin() {
1523
+ return {
1524
+ name: "rsc:validate-imports",
1525
+ resolveId: {
1526
+ order: "pre",
1527
+ async handler(source, importer, options) {
1528
+ if ("scan" in options && options.scan) return;
1529
+ if (source === "client-only") {
1530
+ if (this.environment.name === "rsc") throw new Error(`'client-only' cannot be imported in server build (importer: '${importer ?? "unknown"}', environment: ${this.environment.name})`);
1531
+ return {
1532
+ id: `\0virtual:vite-rsc/empty`,
1533
+ moduleSideEffects: false
1534
+ };
1535
+ }
1536
+ if (source === "server-only") {
1537
+ if (this.environment.name !== "rsc") throw new Error(`'server-only' cannot be imported in client build (importer: '${importer ?? "unknown"}', environment: ${this.environment.name})`);
1538
+ return {
1539
+ id: `\0virtual:vite-rsc/empty`,
1540
+ moduleSideEffects: false
1541
+ };
1542
+ }
1543
+ return;
1544
+ }
1545
+ },
1546
+ load(id) {
1547
+ if (id.startsWith("\0virtual:vite-rsc/empty")) return `export {}`;
1548
+ }
1549
+ };
1550
+ }
1465
1551
  function sortObject(o) {
1466
1552
  return Object.fromEntries(Object.entries(o).sort(([a], [b]) => a.localeCompare(b)));
1467
1553
  }
@@ -31,44 +31,56 @@ type RscPluginOptions = {
31
31
  ignoredPackageWarnings?: (string | RegExp)[];
32
32
  /**
33
33
  * This option allows customizing how client build copies assets from server build.
34
- * By default, all assets are copied, but frameworks might want to establish some convention
35
- * to tighten security based on this option.
34
+ * By default, all assets are copied, but frameworks can establish server asset convention
35
+ * to tighten security using this option.
36
36
  */
37
37
  copyServerAssetsToClient?: (fileName: string) => boolean;
38
- defineEncryptionKey?: string;
39
38
  /**
40
- * Allows enabling action closure encryption for debugging purpose.
39
+ * This option allows disabling action closure encryption for debugging purpose.
41
40
  * @default true
42
41
  */
43
42
  enableActionEncryption?: boolean;
43
+ /**
44
+ * By default, the plugin uses a build-time generated encryption key for
45
+ * "use server" closure argument binding.
46
+ * This can be overwritten by configuring `defineEncryptionKey` option,
47
+ * for example, to obtain a key through environment variable during runtime.
48
+ * cf. https://nextjs.org/docs/app/guides/data-security#overwriting-encryption-keys-advanced
49
+ */
50
+ defineEncryptionKey?: string;
44
51
  /** Escape hatch for Waku's `allowServer` */
45
52
  keepUseCientProxy?: boolean;
53
+ /**
54
+ * Enable build-time validation of 'client-only' and 'server-only' imports
55
+ * @default true
56
+ */
57
+ validateImports?: boolean;
46
58
  };
47
59
  declare function vitePluginRsc(rscPluginOptions?: RscPluginOptions): Plugin[];
48
- //
49
- // collect client reference dependency chunk for modulepreload
50
- //
60
+ declare class RuntimeAsset {
61
+ runtime: string;
62
+ constructor(value: string);
63
+ }
51
64
  type AssetsManifest = {
52
- bootstrapScriptContent: string;
65
+ bootstrapScriptContent: string | RuntimeAsset;
53
66
  clientReferenceDeps: Record<string, AssetDeps>;
54
- serverResources?: Record<string, {
55
- css: string[];
56
- }>;
67
+ serverResources?: Record<string, Pick<AssetDeps, "css">>;
57
68
  };
58
69
  type AssetDeps = {
70
+ js: (string | RuntimeAsset)[];
71
+ css: (string | RuntimeAsset)[];
72
+ };
73
+ type ResolvedAssetsManifest = {
74
+ bootstrapScriptContent: string;
75
+ clientReferenceDeps: Record<string, ResolvedAssetDeps>;
76
+ serverResources?: Record<string, Pick<ResolvedAssetDeps, "css">>;
77
+ };
78
+ type ResolvedAssetDeps = {
59
79
  js: string[];
60
80
  css: string[];
61
81
  };
62
- //
63
- // support findSourceMapURL
64
- // https://github.com/facebook/react/pull/29708
65
- // https://github.com/facebook/react/pull/30741
66
- //
67
82
  declare function vitePluginFindSourceMapURL(): Plugin[];
68
83
  declare function findSourceMapURL(server: ViteDevServer, filename: string, environmentName: string): Promise<object | undefined>;
69
- //
70
- // css support
71
- //
72
84
  declare function vitePluginRscCss(rscCssOptions?: Pick<RscPluginOptions, "rscCssTransform">): Plugin[];
73
85
  declare function transformRscCssExport(options: {
74
86
  ast: Awaited<ReturnType<typeof parseAstAsync>>;
@@ -85,4 +97,4 @@ declare function transformRscCssExport(options: {
85
97
  */
86
98
  declare function __fix_cloudflare(): Plugin;
87
99
  //#endregion
88
- export { AssetDeps, AssetsManifest, RscPluginOptions, __fix_cloudflare, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRsc, vitePluginRscCss };
100
+ export { AssetDeps, AssetsManifest, ResolvedAssetDeps, ResolvedAssetsManifest, RscPluginOptions, __fix_cloudflare, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRsc, vitePluginRscCss };
package/dist/plugin.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { AssetDeps, AssetsManifest, RscPluginOptions, __fix_cloudflare, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRsc, vitePluginRscCss } from "./plugin-Dg2agPFN.js";
2
- export { AssetDeps, AssetsManifest, RscPluginOptions, __fix_cloudflare, vitePluginRsc as default, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRscCss };
1
+ import { AssetDeps, AssetsManifest, ResolvedAssetDeps, ResolvedAssetsManifest, RscPluginOptions, __fix_cloudflare, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRsc, vitePluginRscCss } from "./plugin-DXIhXGMa.js";
2
+ export { AssetDeps, AssetsManifest, ResolvedAssetDeps, ResolvedAssetsManifest, RscPluginOptions, __fix_cloudflare, vitePluginRsc as default, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRscCss };
package/dist/plugin.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import "./dist-DEF94lDJ.js";
2
2
  import "./plugin-CZbI4rhS.js";
3
- import { __fix_cloudflare, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRsc, vitePluginRscCss } from "./plugin-BvUB-eig.js";
3
+ import { __fix_cloudflare, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRsc, vitePluginRscCss } from "./plugin-6e6xZIb7.js";
4
4
  import "./encryption-utils-BDwwcMVT.js";
5
5
  import "./rpc-tGuLT8PD.js";
6
- import "./vite-utils-CcqBE-C4.js";
6
+ import "./vite-utils-Vzd7cqfv.js";
7
7
 
8
8
  export { __fix_cloudflare, vitePluginRsc as default, findSourceMapURL, transformRscCssExport, vitePluginFindSourceMapURL, vitePluginRscCss };
@@ -1,4 +1,4 @@
1
1
  import { CallServerCallback } from "../index-BHqtj9tT.js";
2
2
  import { setRequireModule } from "../browser-Dw18EFgE.js";
3
- import { callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setServerCallback } from "../browser-DjnGtEmB.js";
3
+ import { callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setServerCallback } from "../browser-CeSkQWD5.js";
4
4
  export { CallServerCallback, callServer, createFromFetch, createFromReadableStream, createServerReference, createTemporaryReferenceSet, encodeReply, findSourceMapURL, setRequireModule, setServerCallback };
@@ -28,8 +28,9 @@ initialize();
28
28
  function initialize() {
29
29
  setRequireModule({ load: async (id) => {
30
30
  if (!import.meta.env.__vite_rsc_build__) return import(
31
- /* @vite-ignore */
32
- id);
31
+ /* @vite-ignore */
32
+ id
33
+ );
33
34
  else {
34
35
  const import_ = serverReferences[id];
35
36
  if (!import_) throw new Error(`server reference not found '${id}'`);
@@ -6,6 +6,9 @@ type RscPayload = {
6
6
  formState?: ReactFormState;
7
7
  returnValue?: unknown;
8
8
  };
9
+ /**
10
+ * @deprecated Use `@vitejs/plugin-rsc/rsc` API instead.
11
+ */
9
12
  declare function renderRequest(request: Request, root: React.ReactNode, options?: {
10
13
  nonce?: string;
11
14
  }): Promise<Response>;
@@ -1,4 +1,5 @@
1
1
  //#region src/rsc-html-stream/browser.d.ts
2
+ /** @deprecated use `rsc-html-stream/client` instead */
2
3
  declare const getRscStreamFromHtml: () => ReadableStream<Uint8Array>;
3
4
  //#endregion
4
5
  export { getRscStreamFromHtml };
@@ -1,6 +1,7 @@
1
- import { rscStream } from "../client-edAdk2GF.js";
1
+ import { rscStream } from "../client-CPc-spDn.js";
2
2
 
3
3
  //#region src/rsc-html-stream/browser.ts
4
+ /** @deprecated use `rsc-html-stream/client` instead */
4
5
  const getRscStreamFromHtml = () => rscStream;
5
6
 
6
7
  //#endregion
@@ -1,4 +1,5 @@
1
1
  //#region src/rsc-html-stream/ssr.d.ts
2
+ /** @deprecated use `rsc-html-stream/server` instead */
2
3
  declare const injectRscStreamToHtml: (stream: ReadableStream<Uint8Array>, options?: {
3
4
  nonce?: string;
4
5
  }) => TransformStream<Uint8Array, Uint8Array>;
@@ -1,6 +1,7 @@
1
- import { injectRSCPayload } from "../server-DS3S6m0g.js";
1
+ import { injectRSCPayload } from "../server-C50j-DRF.js";
2
2
 
3
3
  //#region src/rsc-html-stream/ssr.ts
4
+ /** @deprecated use `rsc-html-stream/server` instead */
4
5
  const injectRscStreamToHtml = (stream, options) => injectRSCPayload(stream, options);
5
6
 
6
7
  //#endregion
package/dist/rsc.d.ts CHANGED
@@ -3,10 +3,6 @@ import { createClientManifest, createServerManifest, loadServerAction, setRequir
3
3
  import { createClientTemporaryReferenceSet, createFromReadableStream, createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, encodeReply, registerClientReference, registerServerReference, renderToReadableStream } from "./rsc-DgrejoNf.js";
4
4
 
5
5
  //#region src/utils/encryption-runtime.d.ts
6
- // based on
7
- // https://github.com/parcel-bundler/parcel/blob/9855f558a69edde843b1464f39a6010f6b421efe/packages/transformers/js/src/rsc-utils.js
8
- // https://github.com/vercel/next.js/blob/c10c10daf9e95346c31c24dc49d6b7cda48b5bc8/packages/next/src/server/app-render/encryption.ts
9
- // https://github.com/vercel/next.js/pull/56377
10
6
  declare function encryptActionBoundArgs(originalValue: unknown): Promise<string>;
11
7
  declare function decryptActionBoundArgs(encrypted: ReturnType<typeof encryptActionBoundArgs>): Promise<unknown>;
12
8
  //#endregion
package/dist/rsc.js CHANGED
@@ -3,6 +3,6 @@ import "./shared-CEyKoKAb.js";
3
3
  import "./encryption-utils-BDwwcMVT.js";
4
4
  import { createClientManifest, createServerManifest, loadServerAction, setRequireModule } from "./rsc-DKA6wwTB.js";
5
5
  import { createClientTemporaryReferenceSet, createFromReadableStream, createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, encodeReply, registerClientReference, registerServerReference, renderToReadableStream } from "./rsc-DHfL29FT.js";
6
- import { decryptActionBoundArgs, encryptActionBoundArgs } from "./rsc-DmPsJrxF.js";
6
+ import { decryptActionBoundArgs, encryptActionBoundArgs } from "./rsc-BIUd01vh.js";
7
7
 
8
8
  export { createClientManifest, createClientTemporaryReferenceSet, createFromReadableStream, createServerManifest, createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, decryptActionBoundArgs, encodeReply, encryptActionBoundArgs, loadServerAction, registerClientReference, registerServerReference, renderToReadableStream, setRequireModule };
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/rsc-html-stream@0.0.6/node_modules/rsc-html-stream/server.js
1
+ //#region ../../node_modules/.pnpm/rsc-html-stream@0.0.7/node_modules/rsc-html-stream/server.js
2
2
  const encoder = new TextEncoder();
3
3
  const trailer = "</body></html>";
4
4
  function injectRSCPayload(rscStream, options) {
@@ -28,7 +28,13 @@ function injectRSCPayload(rscStream, options) {
28
28
  buffered.push(chunk);
29
29
  if (timeout) return;
30
30
  timeout = setTimeout(async () => {
31
- flushBufferedChunks(controller);
31
+ try {
32
+ flushBufferedChunks(controller);
33
+ } catch (e) {
34
+ controller.error(e);
35
+ resolveFlightDataPromise();
36
+ return;
37
+ }
32
38
  if (!startedRSC) {
33
39
  startedRSC = true;
34
40
  writeRSCStream(rscStream, controller, nonce).catch((err) => controller.error(err)).then(resolveFlightDataPromise);
@@ -9,11 +9,13 @@ function initialize() {
9
9
  setRequireModule({ load: async (id) => {
10
10
  if (!import.meta.env.__vite_rsc_build__) {
11
11
  const mod = await import(
12
- /* @vite-ignore */
13
- id);
12
+ /* @vite-ignore */
13
+ id
14
+ );
14
15
  const modCss = await import(
15
- /* @vite-ignore */
16
- "/@id/__x00__virtual:vite-rsc/css/dev-ssr/" + id);
16
+ /* @vite-ignore */
17
+ "/@id/__x00__virtual:vite-rsc/css/dev-ssr/" + id
18
+ );
17
19
  return wrapResourceProxy(mod, {
18
20
  js: [],
19
21
  css: modCss.default
package/dist/ssr.js CHANGED
@@ -2,6 +2,6 @@ import "./dist-DEF94lDJ.js";
2
2
  import "./shared-CEyKoKAb.js";
3
3
  import { createServerConsumerManifest, setRequireModule } from "./ssr-BOIYlvSn.js";
4
4
  import { callServer, createFromReadableStream, createServerReference, findSourceMapURL } from "./ssr-D5pxP29F.js";
5
- import "./ssr-Do_Ok_bB.js";
5
+ import "./ssr-DNwSdZ9T.js";
6
6
 
7
7
  export { callServer, createFromReadableStream, createServerConsumerManifest, createServerReference, findSourceMapURL, setRequireModule };
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
+ import { stripVTControlCharacters } from "node:util";
3
4
 
4
5
  //#region src/vite-utils.ts
5
6
  const VALID_ID_PREFIX = `/@id/`;
@@ -59,6 +60,20 @@ function normalizeViteImportAnalysisUrl(environment, id) {
59
60
  }
60
61
  return url;
61
62
  }
63
+ function prepareError(err) {
64
+ return {
65
+ message: stripVTControlCharacters(err.message),
66
+ stack: stripVTControlCharacters(cleanStack(err.stack || "")),
67
+ id: err.id,
68
+ frame: stripVTControlCharacters(err.frame || ""),
69
+ plugin: err.plugin,
70
+ pluginCode: err.pluginCode?.toString(),
71
+ loc: err.loc
72
+ };
73
+ }
74
+ function cleanStack(stack) {
75
+ return stack.split(/\n/).filter((l) => /^\s*at/.test(l)).join("\n");
76
+ }
62
77
 
63
78
  //#endregion
64
- export { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId };
79
+ export { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, prepareError, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId };
@@ -1,4 +1,4 @@
1
- import { DevEnvironment, Rollup } from "vite";
1
+ import { DevEnvironment, ErrorPayload, Rollup } from "vite";
2
2
 
3
3
  //#region src/vite-utils.d.ts
4
4
  declare const VALID_ID_PREFIX = "/@id/";
@@ -17,5 +17,7 @@ declare function injectQuery(url: string, queryToInject: string): string;
17
17
  declare function joinUrlSegments(a: string, b: string): string;
18
18
  declare function normalizeResolvedIdToUrl(environment: DevEnvironment, url: string, resolved: Rollup.PartialResolvedId): string;
19
19
  declare function normalizeViteImportAnalysisUrl(environment: DevEnvironment, id: string): string;
20
+ type RollupError = Rollup.RollupError;
21
+ declare function prepareError(err: Error | RollupError): ErrorPayload["err"];
20
22
  //#endregion
21
- export { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId };
23
+ export { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, prepareError, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId };
@@ -1,3 +1,3 @@
1
- import { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId } from "./vite-utils-CcqBE-C4.js";
1
+ import { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, prepareError, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId } from "./vite-utils-Vzd7cqfv.js";
2
2
 
3
- export { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId };
3
+ export { FS_PREFIX, NULL_BYTE_PLACEHOLDER, VALID_ID_PREFIX, cleanUrl, injectQuery, joinUrlSegments, normalizeResolvedIdToUrl, normalizeViteImportAnalysisUrl, prepareError, slash, splitFileAndPostfix, unwrapId, withTrailingSlash, wrapId };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitejs/plugin-rsc",
3
- "version": "0.4.12",
3
+ "version": "0.4.14",
4
4
  "description": "React Server Components (RSC) support for Vite.",
5
5
  "keywords": [
6
6
  "vite",
@@ -48,19 +48,19 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@hiogawa/utils": "^1.7.0",
51
- "@playwright/test": "^1.53.2",
51
+ "@playwright/test": "^1.54.1",
52
52
  "@tsconfig/strictest": "^2.0.5",
53
53
  "@types/estree": "^1.0.8",
54
- "@types/node": "^22.16.0",
54
+ "@types/node": "^22.16.5",
55
55
  "@types/react": "^19.1.8",
56
56
  "@types/react-dom": "^19.1.6",
57
57
  "@vitejs/plugin-react": "workspace:*",
58
58
  "react": "^19.1.0",
59
59
  "react-dom": "^19.1.0",
60
60
  "react-server-dom-webpack": "^19.1.0",
61
- "rsc-html-stream": "^0.0.6",
61
+ "rsc-html-stream": "^0.0.7",
62
62
  "tinyexec": "^1.0.1",
63
- "tsdown": "^0.12.9"
63
+ "tsdown": "^0.13.0"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "react": "*",