vite-plugin-react-server 0.3.18 → 0.3.19

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.
Files changed (208) hide show
  1. package/README.md +119 -118
  2. package/bin/patch.mjs +8 -2
  3. package/dist/package.json +3 -3
  4. package/dist/plugin/checkFilesExist.d.ts.map +1 -1
  5. package/dist/plugin/checkFilesExist.js +6 -2
  6. package/dist/plugin/checkFilesExist.js.map +1 -1
  7. package/dist/plugin/collect-manifest-client-files.d.ts +23 -0
  8. package/dist/plugin/collect-manifest-client-files.d.ts.map +1 -0
  9. package/dist/plugin/collect-manifest-client-files.js +117 -0
  10. package/dist/plugin/collect-manifest-client-files.js.map +1 -0
  11. package/dist/plugin/components.d.ts +9 -9
  12. package/dist/plugin/components.d.ts.map +1 -1
  13. package/dist/plugin/components.js +50 -9
  14. package/dist/plugin/components.js.map +1 -0
  15. package/dist/plugin/config/defaults.d.ts +7 -6
  16. package/dist/plugin/config/defaults.d.ts.map +1 -1
  17. package/dist/plugin/config/defaults.js +8 -5
  18. package/dist/plugin/config/defaults.js.map +1 -1
  19. package/dist/plugin/config/getPaths.d.ts +0 -1
  20. package/dist/plugin/config/getPaths.d.ts.map +1 -1
  21. package/dist/plugin/config/getPaths.js +2 -7
  22. package/dist/plugin/config/getPaths.js.map +1 -1
  23. package/dist/plugin/config/mimeTypes.d.ts +2 -0
  24. package/dist/plugin/config/mimeTypes.d.ts.map +1 -0
  25. package/dist/plugin/config/mimeTypes.js +24 -0
  26. package/dist/plugin/config/mimeTypes.js.map +1 -0
  27. package/dist/plugin/config/resolveOptions.d.ts +1 -1
  28. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  29. package/dist/plugin/config/resolveOptions.js +41 -28
  30. package/dist/plugin/config/resolveOptions.js.map +1 -1
  31. package/dist/plugin/config/resolvePages.d.ts +1 -0
  32. package/dist/plugin/config/resolvePages.d.ts.map +1 -1
  33. package/dist/plugin/config/resolvePages.js +9 -5
  34. package/dist/plugin/config/resolvePages.js.map +1 -1
  35. package/dist/plugin/config/resolveUserConfig.d.ts +2 -1
  36. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  37. package/dist/plugin/config/resolveUserConfig.js +10 -5
  38. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  39. package/dist/plugin/copy-dir.js +23 -18
  40. package/dist/plugin/copy-dir.js.map +1 -0
  41. package/dist/plugin/helpers/createHandler.d.ts +22 -0
  42. package/dist/plugin/helpers/createHandler.d.ts.map +1 -0
  43. package/dist/plugin/{react-server → helpers}/createHandler.js +36 -48
  44. package/dist/plugin/helpers/createHandler.js.map +1 -0
  45. package/dist/plugin/{react-server → helpers}/createRscStream.d.ts +2 -1
  46. package/dist/plugin/helpers/createRscStream.d.ts.map +1 -0
  47. package/dist/plugin/helpers/createRscStream.js +71 -0
  48. package/dist/plugin/helpers/createRscStream.js.map +1 -0
  49. package/dist/plugin/helpers/getBundleManifest.d.ts.map +1 -1
  50. package/dist/plugin/helpers/getBundleManifest.js +12 -4
  51. package/dist/plugin/helpers/getBundleManifest.js.map +1 -1
  52. package/dist/plugin/loader/createBuildLoader.d.ts +1 -1
  53. package/dist/plugin/loader/createBuildLoader.d.ts.map +1 -1
  54. package/dist/plugin/loader/createBuildLoader.js +8 -5
  55. package/dist/plugin/loader/createBuildLoader.js.map +1 -1
  56. package/dist/plugin/loader/css-loader.d.ts.map +1 -1
  57. package/dist/plugin/loader/css-loader.js.map +1 -1
  58. package/dist/plugin/loader/react-loader.js +2 -2
  59. package/dist/plugin/loader/react-loader.js.map +1 -1
  60. package/dist/plugin/preserver/plugin.d.ts.map +1 -1
  61. package/dist/plugin/preserver/plugin.js +49 -14
  62. package/dist/plugin/preserver/plugin.js.map +1 -1
  63. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  64. package/dist/plugin/react-client/plugin.js +18 -76
  65. package/dist/plugin/react-client/plugin.js.map +1 -1
  66. package/dist/plugin/react-server/index.d.ts.map +1 -1
  67. package/dist/plugin/react-server/index.js +2 -0
  68. package/dist/plugin/react-server/index.js.map +1 -1
  69. package/dist/plugin/react-server/plugin.d.ts +2 -1
  70. package/dist/plugin/react-server/plugin.d.ts.map +1 -1
  71. package/dist/plugin/react-server/plugin.js +53 -217
  72. package/dist/plugin/react-server/plugin.js.map +1 -1
  73. package/dist/plugin/react-static/index.d.ts +2 -0
  74. package/dist/plugin/react-static/index.d.ts.map +1 -0
  75. package/dist/plugin/react-static/index.js +1 -0
  76. package/dist/plugin/react-static/plugin.d.ts +7 -0
  77. package/dist/plugin/react-static/plugin.d.ts.map +1 -0
  78. package/dist/plugin/react-static/plugin.js +199 -0
  79. package/dist/plugin/react-static/plugin.js.map +1 -0
  80. package/dist/plugin/resolvePage.d.ts.map +1 -1
  81. package/dist/plugin/resolvePage.js +9 -0
  82. package/dist/plugin/resolvePage.js.map +1 -1
  83. package/dist/plugin/root.d.ts +2 -0
  84. package/dist/plugin/root.d.ts.map +1 -0
  85. package/dist/plugin/root.js +12 -0
  86. package/dist/plugin/root.js.map +1 -0
  87. package/dist/plugin/transformer/plugin.d.ts.map +1 -1
  88. package/dist/plugin/transformer/plugin.js +32 -23
  89. package/dist/plugin/transformer/plugin.js.map +1 -1
  90. package/dist/plugin/transformer/types.d.ts +1 -18
  91. package/dist/plugin/transformer/types.d.ts.map +1 -1
  92. package/dist/plugin/types.d.ts +24 -6
  93. package/dist/plugin/types.d.ts.map +1 -1
  94. package/dist/plugin/worker/createWorker.js +0 -1
  95. package/dist/plugin/worker/createWorker.js.map +1 -1
  96. package/dist/plugin/worker/html/html-worker.development.d.ts +30 -0
  97. package/dist/plugin/worker/html/html-worker.development.d.ts.map +1 -1
  98. package/dist/plugin/worker/html/html-worker.development.js +30 -2
  99. package/dist/plugin/worker/html/html-worker.development.js.map +1 -1
  100. package/dist/plugin/worker/html/html-worker.production.js +3 -5
  101. package/dist/plugin/worker/html/html-worker.production.js.map +1 -1
  102. package/dist/plugin/worker/html/messageHandler.d.ts.map +1 -1
  103. package/dist/plugin/worker/html/messageHandler.js +8 -2
  104. package/dist/plugin/worker/html/messageHandler.js.map +1 -1
  105. package/dist/plugin/worker/html/plugin.d.ts.map +1 -1
  106. package/dist/plugin/worker/html/plugin.js +2 -3
  107. package/dist/plugin/worker/html/renderPages.d.ts +8 -4
  108. package/dist/plugin/worker/html/renderPages.d.ts.map +1 -1
  109. package/dist/plugin/worker/html/renderPages.js +118 -83
  110. package/dist/plugin/worker/html/renderPages.js.map +1 -1
  111. package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -1
  112. package/dist/plugin/worker/rsc/messageHandler.js +89 -84
  113. package/dist/plugin/worker/rsc/messageHandler.js.map +1 -1
  114. package/dist/plugin/worker/rsc/plugin.d.ts.map +1 -1
  115. package/dist/plugin/worker/rsc/plugin.js +1 -2
  116. package/dist/plugin/worker/rsc/rsc-worker.development.js +13 -18
  117. package/dist/plugin/worker/rsc/rsc-worker.development.js.map +1 -1
  118. package/dist/plugin/worker/rsc/rsc-worker.production.js +4 -1
  119. package/dist/plugin/worker/rsc/rsc-worker.production.js.map +1 -1
  120. package/dist/plugin/worker/rsc/state.d.ts.map +1 -1
  121. package/dist/plugin/worker/rsc/state.js.map +1 -1
  122. package/dist/tsconfig.tsbuildinfo +1 -1
  123. package/package.json +3 -3
  124. package/plugin/checkFilesExist.ts +7 -3
  125. package/plugin/collect-manifest-client-files.ts +152 -0
  126. package/plugin/components.tsx +55 -10
  127. package/plugin/config/defaults.tsx +69 -0
  128. package/plugin/config/getPaths.ts +1 -7
  129. package/plugin/config/mimeTypes.ts +17 -0
  130. package/plugin/config/resolveOptions.ts +48 -40
  131. package/plugin/config/resolvePages.ts +8 -4
  132. package/plugin/config/resolveUserConfig.ts +12 -9
  133. package/plugin/{react-server → helpers}/createHandler.ts +46 -63
  134. package/plugin/helpers/createRscStream.ts +81 -0
  135. package/plugin/helpers/getBundleManifest.ts +14 -5
  136. package/plugin/loader/createBuildLoader.ts +9 -6
  137. package/plugin/loader/css-loader.ts +0 -2
  138. package/plugin/loader/react-loader.ts +2 -2
  139. package/plugin/preserver/plugin.ts +64 -17
  140. package/plugin/react-client/plugin.ts +20 -91
  141. package/plugin/react-server/index.ts +2 -0
  142. package/plugin/react-server/plugin.ts +66 -293
  143. package/plugin/react-static/index.ts +1 -0
  144. package/plugin/react-static/plugin.ts +247 -0
  145. package/plugin/resolvePage.ts +9 -0
  146. package/plugin/root.ts +4 -0
  147. package/plugin/transformer/plugin.ts +40 -31
  148. package/plugin/transformer/types.ts +0 -19
  149. package/plugin/types.ts +25 -6
  150. package/plugin/worker/createWorker.ts +1 -1
  151. package/plugin/worker/html/README.md +63 -0
  152. package/plugin/worker/html/html-worker.development.tsx +89 -2
  153. package/plugin/worker/html/html-worker.production.tsx +8 -10
  154. package/plugin/worker/html/messageHandler.ts +8 -2
  155. package/plugin/worker/html/plugin.ts +2 -3
  156. package/plugin/worker/html/renderPages.ts +150 -114
  157. package/plugin/worker/rsc/README.md +58 -0
  158. package/plugin/worker/rsc/messageHandler.tsx +95 -111
  159. package/plugin/worker/rsc/plugin.ts +1 -2
  160. package/plugin/worker/rsc/rsc-worker.development.ts +12 -22
  161. package/plugin/worker/rsc/rsc-worker.production.ts +5 -1
  162. package/plugin/worker/rsc/state.ts +0 -3
  163. package/scripts/react+0.0.0-experimental-eda36a1c-20250228.patch +114 -12
  164. package/scripts/react-dom+0.0.0-experimental-eda36a1c-20250228.patch +10571 -121
  165. package/tsconfig.json +2 -2
  166. package/dist/plugin/collect-css-manifest.d.ts +0 -4
  167. package/dist/plugin/collect-css-manifest.d.ts.map +0 -1
  168. package/dist/plugin/collect-css-manifest.js +0 -65
  169. package/dist/plugin/collect-css-manifest.js.map +0 -1
  170. package/dist/plugin/config/createModuleIdGenerator.d.ts +0 -11
  171. package/dist/plugin/config/createModuleIdGenerator.d.ts.map +0 -1
  172. package/dist/plugin/config/createModuleIdGenerator.js +0 -44
  173. package/dist/plugin/config/createModuleIdGenerator.js.map +0 -1
  174. package/dist/plugin/loader/createCssLoader.d.ts +0 -30
  175. package/dist/plugin/loader/createCssLoader.d.ts.map +0 -1
  176. package/dist/plugin/loader/createCssLoader.js +0 -35
  177. package/dist/plugin/loader/createPageLoader.d.ts +0 -24
  178. package/dist/plugin/loader/createPageLoader.d.ts.map +0 -1
  179. package/dist/plugin/loader/createPageLoader.js +0 -50
  180. package/dist/plugin/loader/rsc/messageHandler.d.ts +0 -2
  181. package/dist/plugin/loader/rsc/messageHandler.d.ts.map +0 -1
  182. package/dist/plugin/loader/rsc/messageHandler.js +0 -1
  183. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts +0 -2
  184. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts.map +0 -1
  185. package/dist/plugin/loader/rsc/rsc-worker.development.js +0 -1
  186. package/dist/plugin/react-server/createHandler.d.ts +0 -17
  187. package/dist/plugin/react-server/createHandler.d.ts.map +0 -1
  188. package/dist/plugin/react-server/createHandler.js.map +0 -1
  189. package/dist/plugin/react-server/createRscStream.d.ts.map +0 -1
  190. package/dist/plugin/react-server/createRscStream.js +0 -70
  191. package/dist/plugin/react-server/createRscStream.js.map +0 -1
  192. package/dist/plugin/react-server/createSsrHandler.d.ts +0 -4
  193. package/dist/plugin/react-server/createSsrHandler.d.ts.map +0 -1
  194. package/dist/plugin/react-server/createSsrHandler.js +0 -95
  195. package/dist/plugin/utils/logger.d.ts +0 -9
  196. package/dist/plugin/utils/logger.d.ts.map +0 -1
  197. package/dist/plugin/utils/logger.js +0 -68
  198. package/dist/plugin/utils/logger.js.map +0 -1
  199. package/plugin/collect-css-manifest.ts +0 -82
  200. package/plugin/config/createModuleIdGenerator.ts +0 -52
  201. package/plugin/config/defaults.ts +0 -51
  202. package/plugin/loader/createCssLoader.ts +0 -73
  203. package/plugin/loader/createPageLoader.ts +0 -103
  204. package/plugin/loader/rsc/messageHandler.tsx +0 -1
  205. package/plugin/loader/rsc/rsc-worker.development.ts +0 -1
  206. package/plugin/react-server/createRscStream.ts +0 -86
  207. package/plugin/react-server/createSsrHandler.ts +0 -125
  208. package/plugin/utils/logger.ts +0 -52
@@ -7,7 +7,6 @@ import {
7
7
  createFromNodeStream,
8
8
  // @ts-ignore
9
9
  } from "react-server-dom-esm/client.node";
10
- import { join } from "path";
11
10
 
12
11
  // Track active renders and streams
13
12
  const activeRenders = new Map<string, HtmlRenderState>();
@@ -29,7 +28,7 @@ export const messageHandler = async (message: HtmlWorkerMessage) => {
29
28
  moduleRootPath,
30
29
  moduleBaseURL,
31
30
  outDir: '',
32
- htmlOutputPath: htmlOutputPath ?? join(process.cwd(), 'index.html'),
31
+ htmlOutputPath: htmlOutputPath,
33
32
  pipableStreamOptions: pipableStreamOptions,
34
33
  });
35
34
  } else {
@@ -88,6 +87,13 @@ export const messageHandler = async (message: HtmlWorkerMessage) => {
88
87
  reactElements as React.ReactNode,
89
88
  {
90
89
  ...render.pipableStreamOptions,
90
+ // Calculate relative paths based on route depth
91
+ bootstrapModules: render.pipableStreamOptions?.bootstrapModules?.map(path => {
92
+ if (!path) return path;
93
+ const depth = id.split('/').filter(Boolean).length ;
94
+ const prefix = depth > 0 ? '../'.repeat(depth) : '/';
95
+ return path.startsWith('/') ? prefix + path.slice(1) : prefix + path;
96
+ }),
91
97
  onShellReady() {
92
98
  parentPort?.postMessage({ type: "SHELL_READY", id });
93
99
  }
@@ -3,12 +3,12 @@ import { join, resolve } from "path";
3
3
  import type { ModuleFormat, RollupOptions } from 'rollup';
4
4
  import type { ResolvedUserOptions, StreamPluginOptions } from "../../types.js";
5
5
  import { DEFAULT_CONFIG } from "../../config/defaults.js";
6
- import { getPluginRoot } from "../../config/getPaths.js";
6
+ import { pluginRoot } from "../../root.js";
7
7
  import { resolveOptions } from "../../config/resolveOptions.js";
8
8
 
9
9
  let userOptions: ResolvedUserOptions;
10
10
  export function reactHtmlWorkerPlugin(options: StreamPluginOptions): Plugin {
11
- const resolvedUserOptions = resolveOptions(options);
11
+ const resolvedUserOptions = resolveOptions(options, false);
12
12
  if(resolvedUserOptions.type === 'error') {
13
13
  throw resolvedUserOptions.error
14
14
  }
@@ -17,7 +17,6 @@ export function reactHtmlWorkerPlugin(options: StreamPluginOptions): Plugin {
17
17
  name: "vite:react-html-worker",
18
18
  config(config) {
19
19
  const root = config.root ?? process.cwd();
20
- const pluginRoot = getPluginRoot();
21
20
  const htmlWorkerPath = typeof options.htmlWorkerPath === 'string'
22
21
  ? resolve(root, options.htmlWorkerPath)
23
22
  : resolve(pluginRoot, DEFAULT_CONFIG.HTML_WORKER_PATH);
@@ -1,20 +1,17 @@
1
- import { mkdirSync } from "node:fs";
2
1
  import { mkdir, writeFile } from "node:fs/promises";
3
- import { dirname, join, resolve as resolvePath } from "node:path";
2
+ import { dirname, join } from "node:path";
4
3
  import { Transform } from "node:stream";
5
4
  import type { Worker } from "node:worker_threads";
6
- import { createHandler } from "../../react-server/createHandler.js";
7
- import type { CheckFilesExistReturn, ResolvedUserConfig, ResolvedUserOptions } from "../../types.js";
5
+ import { createHandler } from "../../helpers/createHandler.js";
8
6
  import type {
9
- HtmlWorkerResponse,
10
- WorkerRscChunkMessage,
11
- } from "../types.js";
12
- import type { Manifest } from "vite";
13
- import type {
14
- PluginContext,
15
- } from "rollup";
7
+ CheckFilesExistReturn,
8
+ PageData,
9
+ ResolvedUserConfig,
10
+ ResolvedUserOptions,
11
+ } from "../../types.js";
12
+ import type { HtmlWorkerResponse } from "../types.js";
13
+ import type { Manifest, IndexHtmlTransformHook } from "vite";
16
14
  import React from "react";
17
- import { collectManifestCss } from "../../collect-css-manifest.js";
18
15
 
19
16
  interface PipeableStreamOptions {
20
17
  bootstrapModules?: string[];
@@ -42,48 +39,82 @@ type RenderPagesOptions = {
42
39
  pipableStreamOptions?: PipeableStreamOptions;
43
40
  loader: (id: string) => Promise<Record<string, any>>;
44
41
  onCssFile?: (url: string, parentUrl: string) => void;
42
+ onClientJSFile?: (url: string, parentUrl: string) => void;
43
+ onPage?: (pageData: PageData) => Promise<void>;
45
44
  clientCss?: string[];
46
45
  moduleBasePath: string;
47
46
  moduleBaseURL: string;
47
+ transformIndexHtml: IndexHtmlTransformHook;
48
+ outDir: string;
49
+ htmlOutputPath: string;
48
50
  };
49
51
 
50
52
  export async function renderPages(
51
- pluginContext: PluginContext,
52
53
  routes: string[],
53
54
  files: CheckFilesExistReturn,
54
- options: RenderPagesOptions,
55
+ options: RenderPagesOptions
55
56
  ) {
56
- const root = pluginContext.environment.config.root;
57
- const outDir = pluginContext.environment.config.build.outDir;
58
57
  const failedRoutes = new Map<string, Error>();
59
58
  const completedRoutes = new Set<string>();
60
- const writePromises = new Map<string, Promise<void>>();
61
59
  const clientCss = options.clientCss ?? [];
60
+ const partialPageData = new Map<string, Partial<PageData>>();
61
+
62
+ const mergeAndSendPageData = async (route: string, resolve: () => void) => {
63
+ const partial = partialPageData.get(route);
64
+ if (!partial?.html || !partial.rsc) {
65
+ return; // Wait for both parts
66
+ }
67
+
68
+ const pageData: PageData = {
69
+ route,
70
+ html: partial.html,
71
+ rsc: partial.rsc,
72
+ };
73
+
74
+ // Write RSC file
75
+ console.log('route', route)
76
+ // Write HTML file
77
+ let routeHtmlPath = route === '/' ? options.htmlOutputPath : options.htmlOutputPath.replace('index.html', join(route, 'index.html'));
78
+ if(routeHtmlPath.startsWith('/')) {
79
+ routeHtmlPath = routeHtmlPath.slice(1);
80
+ }
81
+ const routeRscPath = routeHtmlPath.slice(0, -5) + '.rsc';
82
+ await mkdir(dirname(routeHtmlPath), { recursive: true });
83
+ await writeFile(routeRscPath, partial.rsc.content);
84
+ await writeFile(routeHtmlPath, partial.html.raw);
85
+
86
+ await options.onPage?.(pageData);
87
+ completedRoutes.add(route);
88
+ if (completedRoutes.size === routes.length) {
89
+ resolve();
90
+ }
91
+ };
92
+
62
93
  try {
63
94
  // Set up worker message handling
64
95
  const allRoutesComplete = new Promise<void>((resolve, reject) => {
65
- options.worker.on("message", (msg: HtmlWorkerResponse) => {
96
+ options.worker.on("message", async (msg: HtmlWorkerResponse) => {
66
97
  switch (msg.type) {
67
98
  case "ALL_READY": {
68
- const { id, html, outputPath } = msg;
69
- mkdirSync(dirname(outputPath), { recursive: true });
70
-
71
- writeFile(outputPath, html)
72
- .then(() => {
73
- completedRoutes.add(id);
74
- if (completedRoutes.size === routes.length) {
75
- resolve();
76
- }
77
- })
78
- .catch((error) => {
79
- console.error('Write error for route:', id, error);
80
- failedRoutes.set(id, error as Error);
81
- reject(error);
82
- });
99
+ const { id, html } = msg;
100
+ try {
101
+ const partial = partialPageData.get(id) || { route: id };
102
+
103
+ partial.html = {
104
+ raw: html,
105
+ transformed: "", // Will be set by main thread transform
106
+ assets: [],
107
+ };
108
+ partialPageData.set(id, partial);
109
+ await mergeAndSendPageData(id, resolve);
110
+ } catch (error) {
111
+ failedRoutes.set(id, error as Error);
112
+ reject(error);
113
+ }
83
114
  break;
84
115
  }
85
116
  case "ERROR": {
86
- console.error('Worker error for route:', msg.id, msg.error);
117
+ console.error("Worker error for route:", msg.id, msg.error);
87
118
  failedRoutes.set(msg.id, new Error(msg.error));
88
119
  reject(new Error(msg.error));
89
120
  break;
@@ -92,124 +123,130 @@ export async function renderPages(
92
123
  });
93
124
  });
94
125
 
95
- const newCssFiles = collectManifestCss(
96
- options.clientManifest,
97
- options.moduleBasePath,
98
- 'index.html',
99
- (url, parentUrl)=>{
100
- options?.onCssFile?.(url, parentUrl);
101
- if(!clientCss.includes(url)){
102
- clientCss.push(url);
103
- }
104
- },
105
- join(root, options.pluginOptions.build.outDir, options.pluginOptions.build.client)
106
- );
107
-
108
126
  // Process routes sequentially
109
127
  for (const route of routes) {
110
128
  const routeFiles = files.urlMap.get(route);
111
129
  if (!routeFiles) {
112
- console.error('No files found for route:', route);
130
+ console.error("No files found for route:", route);
113
131
  failedRoutes.set(route, new Error(`No files found for ${route}`));
114
132
  continue;
115
133
  }
116
134
 
117
- collectManifestCss(
118
- options.serverManifest,
119
- options.moduleBasePath,
120
- routeFiles.page,
121
- (url, parentUrl)=>{
122
- options.onCssFile?.(url, parentUrl);
123
- if(!clientCss.includes(url)){
124
- clientCss.push(url);
125
- }
135
+ if (options.pipableStreamOptions?.importMap?.imports) {
136
+ for (let [, value] of Object.entries(
137
+ options.pipableStreamOptions?.importMap?.imports
138
+ )) {
139
+ options.onClientJSFile?.(value, route);
126
140
  }
127
- );
141
+ }
142
+
128
143
  // Create handler for pure RSC output
129
- const rscResult = await createHandler(route, {
130
- ...options.pluginOptions,
131
- Html: React.Fragment // Use Fragment for pure RSC output
132
- }, {
133
- loader: options.loader,
134
- clientManifest: options.clientManifest,
135
- serverManifest: options.serverManifest,
136
- cssFiles: Array.from(newCssFiles.values()).concat(clientCss),
137
- pipableStreamOptions: {
138
- ...options.pipableStreamOptions,
139
- importMap: {
140
- imports: {
141
- ...options.pipableStreamOptions?.importMap?.imports,
142
- }
143
- }
144
+ const rscResult = await createHandler({
145
+ url: route,
146
+ urlMap: files.urlMap,
147
+ pluginOptions: {
148
+ ...options.pluginOptions,
149
+ Html: React.Fragment, // Use Fragment for pure RSC output
150
+ },
151
+ streamOptions: {
152
+ loader: options.loader,
153
+ clientManifest: options.clientManifest,
154
+ serverManifest: options.serverManifest,
155
+ cssFiles: clientCss,
156
+ moduleBasePath: '',
157
+ moduleBaseURL: '',
158
+ pipableStreamOptions: {
159
+ ...options.pipableStreamOptions,
160
+ importMap: {
161
+ imports: {
162
+ ...options.pipableStreamOptions?.importMap?.imports,
163
+ },
164
+ },
165
+ },
144
166
  },
145
167
  });
146
168
 
147
169
  // Create handler for HTML output
148
- const htmlResult = await createHandler(route, options.pluginOptions, {
149
- loader: options.loader,
150
- clientManifest: options.clientManifest,
151
- serverManifest: options.serverManifest,
152
- cssFiles: clientCss,
153
- pipableStreamOptions: {
154
- ...options.pipableStreamOptions,
155
- importMap: {
156
- imports: {
157
- ...options.pipableStreamOptions?.importMap?.imports
158
- }
159
- }
170
+ const htmlResult = await createHandler({
171
+ url: route,
172
+ urlMap: files.urlMap,
173
+ pluginOptions: options.pluginOptions,
174
+ streamOptions: {
175
+ loader: options.loader,
176
+ clientManifest: options.clientManifest,
177
+ serverManifest: options.serverManifest,
178
+ cssFiles: clientCss,
179
+ moduleBasePath: '',
180
+ moduleBaseURL: '',
181
+ pipableStreamOptions: {
182
+ ...options.pipableStreamOptions,
183
+ importMap: {
184
+ imports: {
185
+ ...options.pipableStreamOptions?.importMap?.imports,
186
+ },
187
+ },
188
+ },
160
189
  },
161
190
  });
162
191
 
163
192
  if (rscResult.type !== "success" || htmlResult.type !== "success") {
164
- console.error('Handler failed for route:', route);
193
+ if (rscResult.type !== "success") {
194
+ if (rscResult.type !== "skip") {
195
+ console.error("Handler failed for route:", route, rscResult.error);
196
+ }
197
+ }
198
+ if (htmlResult.type !== "success") {
199
+ if (htmlResult.type !== "skip") {
200
+ console.error("Handler failed for route:", route, htmlResult.error);
201
+ }
202
+ }
165
203
  failedRoutes.set(route, new Error(`Handler failed for ${route}`));
166
204
  continue;
167
205
  }
168
206
 
169
207
  // Process both streams
170
208
  await Promise.all([
171
- // Save RSC stream to .rsc file in client directory
209
+ // Handle RSC stream
172
210
  new Promise<void>((resolve, reject) => {
173
211
  const chunks: Buffer[] = [];
174
212
  const rscTransform = new Transform({
175
213
  transform(chunk, _encoding, callback) {
176
214
  try {
177
- chunks.push(Buffer.from(chunk));
178
- callback(null, chunk);
215
+ if (chunk) {
216
+ chunks.push(Buffer.from(chunk));
217
+ callback(null, chunk);
218
+ }
179
219
  } catch (error) {
180
220
  callback(error as Error);
181
221
  }
182
222
  },
183
- flush(callback) {
223
+ async flush(callback) {
184
224
  try {
185
- const rscPath = join(options.pluginOptions.build.outDir, options.pluginOptions.build.client, route, 'index.rsc');
186
-
187
- // Ensure directory exists
188
- mkdirSync(dirname(rscPath), { recursive: true });
189
-
190
- // Write complete file
191
- writeFile(rscPath, Buffer.concat(chunks))
192
- .then(() => {
193
- callback();
194
- resolve();
195
- })
196
- .catch(error => {
197
- console.error('RSC write error:', error);
198
- callback(error as Error);
199
- reject(error);
200
- });
225
+ const rscContent = Buffer.concat(chunks).toString("utf-8");
226
+
227
+ // Update partial page data with raw RSC content
228
+ const partial = partialPageData.get(route) || { route };
229
+ partial.rsc = {
230
+ modules: [], // Will be parsed by the client
231
+ content: rscContent,
232
+ };
233
+ partialPageData.set(route, partial);
234
+ await mergeAndSendPageData(route, resolve);
235
+
236
+ callback();
237
+ resolve();
201
238
  } catch (error) {
202
239
  callback(error as Error);
203
240
  reject(error);
204
241
  }
205
- }
242
+ },
206
243
  });
207
244
 
208
245
  rscResult.stream.pipe(rscTransform);
209
246
  }),
210
247
 
211
248
  // Send HTML stream to worker
212
- new Promise<void>((resolve, reject) => {
249
+ new Promise<void>((resolve) => {
213
250
  const htmlTransform = new Transform({
214
251
  transform(chunk, _encoding, callback) {
215
252
  try {
@@ -217,9 +254,9 @@ export async function renderPages(
217
254
  type: "RSC_CHUNK",
218
255
  id: route,
219
256
  chunk: chunk.toString(),
220
- moduleRootPath: join(root, options.pluginOptions.build.outDir, options.pluginOptions.build.client),
257
+ moduleRootPath: options.moduleBasePath,
221
258
  moduleBaseURL: options.moduleBaseURL,
222
- htmlOutputPath: join(options.pluginOptions.build.outDir, options.pluginOptions.build.client, route, 'index.html'),
259
+ htmlOutputPath: options.htmlOutputPath,
223
260
  pipableStreamOptions: options.pipableStreamOptions,
224
261
  });
225
262
  callback(null, chunk);
@@ -234,18 +271,17 @@ export async function renderPages(
234
271
  });
235
272
  callback();
236
273
  resolve();
237
- }
274
+ },
238
275
  });
239
276
 
240
277
  htmlResult.stream.pipe(htmlTransform);
241
- })
278
+ }),
242
279
  ]);
243
280
  }
244
281
 
245
282
  await allRoutesComplete;
246
-
247
283
  } catch (error) {
248
- console.error('Render error:', error);
284
+ console.error("Render error:", error);
249
285
  throw error;
250
286
  }
251
287
 
@@ -0,0 +1,58 @@
1
+ # RSC Worker
2
+
3
+ The RSC worker is used by the client plugin to handle React Server Components when the main thread is running without the `react-server` condition. It provides the server-condition capabilities that the client plugin needs but can't access directly.
4
+
5
+ ## Purpose
6
+
7
+ The RSC worker serves several key functions:
8
+
9
+ 1. **Server Condition Access**: Enables RSC processing in a client-focused environment
10
+ 2. **Message-Based Communication**: Handles RSC streaming through a message passing interface
11
+
12
+ ## Implementation Details
13
+
14
+ The worker comes in two variants:
15
+
16
+ - `rsc-worker.development.ts`: Full implementation with detailed logging and error handling
17
+ - `rsc-worker.production.ts`: Optimized implementation for production builds
18
+
19
+ ## Extending the Worker
20
+
21
+ Users can create their own RSC workers for application-level use. This allows for:
22
+
23
+ 1. Custom RSC processing logic
24
+ 2. Application-specific message handling
25
+ 3. Specialized worker architectures
26
+
27
+ Example of creating a custom RSC worker:
28
+
29
+ ```typescript
30
+ import { messageHandler } from 'vite-plugin-react-server/worker/rsc/messageHandler'
31
+ import type { RscWorkerMessage } from 'vite-plugin-react-server/worker/types'
32
+
33
+ // Create your custom message handler
34
+ const customMessageHandler = async (msg: RscWorkerMessage) => {
35
+ // Add your custom logic here
36
+ return messageHandler(msg)
37
+ }
38
+
39
+ // Initialize your worker
40
+ if (typeof WorkerGlobalScope !== 'undefined') {
41
+ parentPort.on('message', customMessageHandler)
42
+ }
43
+ ```
44
+
45
+ ## Future Possibilities
46
+
47
+ The RSC worker architecture is designed to be extensible. Future enhancements could include:
48
+
49
+ - Custom streaming strategies
50
+ - Advanced caching mechanisms
51
+ - Specialized RSC processing pipelines
52
+ - Integration with other build tools
53
+
54
+ ## Notes
55
+
56
+ - The worker must be initialized with appropriate Node conditions
57
+ - Message handling must account for streaming data
58
+ - Consider memory usage when processing large RSC payloads