vite-plugin-react-server 0.3.11 → 0.3.12

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 (220) hide show
  1. package/dist/package.json +15 -11
  2. package/dist/plugin/checkFilesExist.d.ts +2 -2
  3. package/dist/plugin/checkFilesExist.d.ts.map +1 -1
  4. package/dist/plugin/checkFilesExist.js +39 -57
  5. package/dist/plugin/checkFilesExist.js.map +1 -1
  6. package/dist/plugin/collect-css-manifest.d.ts.map +1 -1
  7. package/dist/plugin/collect-css-manifest.js +5 -0
  8. package/dist/plugin/collect-css-manifest.js.map +1 -1
  9. package/dist/plugin/components.js +10 -15
  10. package/dist/plugin/config/createModuleIdGenerator.js +1 -1
  11. package/dist/plugin/config/createModuleIdGenerator.js.map +1 -1
  12. package/dist/plugin/config/defaults.d.ts +5 -14
  13. package/dist/plugin/config/defaults.d.ts.map +1 -1
  14. package/dist/plugin/config/defaults.js +12 -12
  15. package/dist/plugin/config/defaults.js.map +1 -1
  16. package/dist/plugin/config/getPaths.js +1 -1
  17. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  18. package/dist/plugin/config/resolveOptions.js +73 -52
  19. package/dist/plugin/config/resolveOptions.js.map +1 -1
  20. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  21. package/dist/plugin/config/resolveUserConfig.js +53 -65
  22. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  23. package/dist/plugin/helpers/getBundleManifest.d.ts +6 -1
  24. package/dist/plugin/helpers/getBundleManifest.d.ts.map +1 -1
  25. package/dist/plugin/helpers/getBundleManifest.js +48 -19
  26. package/dist/plugin/helpers/getBundleManifest.js.map +1 -1
  27. package/dist/plugin/helpers/inputNormalizer.d.ts +1 -2
  28. package/dist/plugin/helpers/inputNormalizer.d.ts.map +1 -1
  29. package/dist/plugin/helpers/inputNormalizer.js +52 -46
  30. package/dist/plugin/helpers/inputNormalizer.js.map +1 -1
  31. package/dist/plugin/helpers/tryManifest.d.ts +1 -1
  32. package/dist/plugin/helpers/tryManifest.d.ts.map +1 -1
  33. package/dist/plugin/helpers/tryManifest.js.map +1 -1
  34. package/dist/plugin/loader/createBuildLoader.d.ts +1 -1
  35. package/dist/plugin/loader/createBuildLoader.d.ts.map +1 -1
  36. package/dist/plugin/loader/createBuildLoader.js +29 -26
  37. package/dist/plugin/loader/createBuildLoader.js.map +1 -1
  38. package/dist/plugin/loader/css-loader.d.ts +16 -0
  39. package/dist/plugin/loader/css-loader.d.ts.map +1 -0
  40. package/dist/plugin/loader/css-loader.js +70 -0
  41. package/dist/plugin/loader/css-loader.js.map +1 -0
  42. package/dist/plugin/loader/react-loader.d.ts +17 -0
  43. package/dist/plugin/loader/react-loader.d.ts.map +1 -0
  44. package/dist/plugin/loader/react-loader.js +647 -0
  45. package/dist/plugin/loader/react-loader.js.map +1 -0
  46. package/dist/plugin/loader/rsc/messageHandler.d.ts +2 -0
  47. package/dist/plugin/loader/rsc/messageHandler.d.ts.map +1 -0
  48. package/dist/plugin/loader/rsc/messageHandler.js +1 -0
  49. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts +2 -0
  50. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts.map +1 -0
  51. package/dist/plugin/loader/rsc/rsc-worker.development.js +1 -0
  52. package/dist/plugin/react-client/index.js +2 -2
  53. package/dist/plugin/react-client/index.js.map +1 -1
  54. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  55. package/dist/plugin/react-client/plugin.js +202 -25
  56. package/dist/plugin/react-client/plugin.js.map +1 -1
  57. package/dist/plugin/react-server/createHandler.d.ts.map +1 -1
  58. package/dist/plugin/react-server/createHandler.js +10 -4
  59. package/dist/plugin/react-server/createHandler.js.map +1 -1
  60. package/dist/plugin/react-server/createRscStream.d.ts +15 -3
  61. package/dist/plugin/react-server/createRscStream.d.ts.map +1 -1
  62. package/dist/plugin/react-server/createRscStream.js +52 -49
  63. package/dist/plugin/react-server/createRscStream.js.map +1 -1
  64. package/dist/plugin/react-server/plugin.d.ts.map +1 -1
  65. package/dist/plugin/react-server/plugin.js +24 -20
  66. package/dist/plugin/react-server/plugin.js.map +1 -1
  67. package/dist/plugin/transformer/plugin.d.ts.map +1 -1
  68. package/dist/plugin/transformer/plugin.js +65 -52
  69. package/dist/plugin/transformer/plugin.js.map +1 -1
  70. package/dist/plugin/types.d.ts +5 -0
  71. package/dist/plugin/types.d.ts.map +1 -1
  72. package/dist/plugin/utils/logger.d.ts +9 -0
  73. package/dist/plugin/utils/logger.d.ts.map +1 -0
  74. package/dist/plugin/utils/logger.js +68 -0
  75. package/dist/plugin/utils/logger.js.map +1 -0
  76. package/dist/plugin/worker/createWorker.d.ts +1 -0
  77. package/dist/plugin/worker/createWorker.d.ts.map +1 -1
  78. package/dist/plugin/worker/createWorker.js +23 -36
  79. package/dist/plugin/worker/createWorker.js.map +1 -1
  80. package/dist/plugin/worker/html/html-worker.production.js +5 -1
  81. package/dist/plugin/worker/html/html-worker.production.js.map +1 -1
  82. package/dist/plugin/worker/html/messageHandler.d.ts.map +1 -1
  83. package/dist/plugin/worker/html/messageHandler.js +10 -19
  84. package/dist/plugin/worker/html/messageHandler.js.map +1 -1
  85. package/dist/plugin/worker/html/renderPages.d.ts +2 -2
  86. package/dist/plugin/worker/html/renderPages.d.ts.map +1 -1
  87. package/dist/plugin/worker/html/renderPages.js +130 -131
  88. package/dist/plugin/worker/html/renderPages.js.map +1 -1
  89. package/dist/plugin/worker/rsc/index.d.ts +1 -3
  90. package/dist/plugin/worker/rsc/index.d.ts.map +1 -1
  91. package/dist/plugin/worker/rsc/index.js +1 -9
  92. package/dist/plugin/worker/rsc/index.js.map +1 -1
  93. package/dist/plugin/worker/rsc/messageHandler.d.ts +3 -0
  94. package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -0
  95. package/dist/plugin/worker/rsc/messageHandler.js +107 -0
  96. package/dist/plugin/worker/rsc/messageHandler.js.map +1 -0
  97. package/dist/plugin/worker/rsc/plugin.d.ts.map +1 -1
  98. package/dist/plugin/worker/rsc/plugin.js +74 -80
  99. package/dist/plugin/worker/rsc/rsc-worker.development.d.ts +32 -0
  100. package/dist/plugin/worker/rsc/rsc-worker.development.d.ts.map +1 -0
  101. package/dist/plugin/worker/rsc/rsc-worker.development.js +43 -0
  102. package/dist/plugin/worker/rsc/rsc-worker.development.js.map +1 -0
  103. package/dist/plugin/worker/rsc/rsc-worker.js +4 -106
  104. package/dist/plugin/worker/rsc/rsc-worker.production.d.ts +2 -0
  105. package/dist/plugin/worker/rsc/rsc-worker.production.d.ts.map +1 -0
  106. package/dist/plugin/worker/rsc/rsc-worker.production.js +14 -0
  107. package/dist/plugin/worker/rsc/rsc-worker.production.js.map +1 -0
  108. package/dist/plugin/worker/rsc/state.d.ts +11 -0
  109. package/dist/plugin/worker/rsc/state.d.ts.map +1 -0
  110. package/dist/plugin/worker/rsc/state.js +12 -0
  111. package/dist/plugin/worker/rsc/state.js.map +1 -0
  112. package/dist/plugin/worker/types.d.ts +60 -46
  113. package/dist/plugin/worker/types.d.ts.map +1 -1
  114. package/dist/tsconfig.tsbuildinfo +1 -1
  115. package/package.json +15 -11
  116. package/plugin/checkFilesExist.ts +42 -62
  117. package/plugin/collect-css-manifest.ts +5 -1
  118. package/plugin/config/createModuleIdGenerator.ts +1 -1
  119. package/plugin/config/defaults.ts +13 -15
  120. package/plugin/config/resolveOptions.ts +134 -76
  121. package/plugin/config/resolveUserConfig.ts +75 -76
  122. package/plugin/helpers/getBundleManifest.ts +69 -31
  123. package/plugin/helpers/inputNormalizer.ts +82 -70
  124. package/plugin/helpers/tryManifest.ts +1 -1
  125. package/plugin/loader/createBuildLoader.ts +38 -41
  126. package/plugin/loader/css-loader.ts +96 -0
  127. package/plugin/loader/react-loader.ts +945 -0
  128. package/plugin/loader/rsc/messageHandler.tsx +1 -0
  129. package/plugin/loader/rsc/rsc-worker.development.ts +1 -0
  130. package/plugin/react-client/index.ts +1 -1
  131. package/plugin/react-client/plugin.ts +266 -41
  132. package/plugin/react-server/createHandler.ts +9 -5
  133. package/plugin/react-server/createRscStream.ts +75 -54
  134. package/plugin/react-server/plugin.ts +26 -21
  135. package/plugin/transformer/plugin.ts +67 -76
  136. package/plugin/types/global.d.ts +8 -0
  137. package/plugin/types.ts +2 -0
  138. package/plugin/utils/logger.ts +52 -0
  139. package/plugin/worker/createWorker.ts +43 -44
  140. package/plugin/worker/html/html-worker.production.tsx +7 -2
  141. package/plugin/worker/html/messageHandler.ts +13 -21
  142. package/plugin/worker/html/renderPages.ts +146 -179
  143. package/plugin/worker/rsc/index.ts +4 -13
  144. package/plugin/worker/rsc/messageHandler.tsx +143 -0
  145. package/plugin/worker/rsc/plugin.ts +38 -37
  146. package/plugin/worker/rsc/rsc-worker.development.ts +107 -0
  147. package/plugin/worker/rsc/rsc-worker.production.ts +13 -0
  148. package/plugin/worker/rsc/rsc-worker.tsx +5 -128
  149. package/plugin/worker/rsc/state.ts +37 -0
  150. package/plugin/worker/types.ts +79 -55
  151. package/scripts/check-react-version.mjs +17 -7
  152. package/scripts/react+0.0.0-experimental-b3a95caf-20250113.patch +143 -4170
  153. package/scripts/react-dom+0.0.0-experimental-b3a95caf-20250113.patch +14271 -90079
  154. package/dist/plugin/components.js.map +0 -1
  155. package/dist/plugin/helpers/createClientInputNormalizer.d.ts +0 -8
  156. package/dist/plugin/helpers/createClientInputNormalizer.d.ts.map +0 -1
  157. package/dist/plugin/helpers/createClientInputNormalizer.js +0 -35
  158. package/dist/plugin/helpers/createServerInputNormalizer.d.ts +0 -9
  159. package/dist/plugin/helpers/createServerInputNormalizer.d.ts.map +0 -1
  160. package/dist/plugin/helpers/createServerInputNormalizer.js +0 -37
  161. package/dist/plugin/helpers/createStaticInputNormalizer.d.ts +0 -7
  162. package/dist/plugin/helpers/createStaticInputNormalizer.d.ts.map +0 -1
  163. package/dist/plugin/helpers/createStaticInputNormalizer.js +0 -18
  164. package/dist/plugin/helpers/getModuleManifest.d.ts +0 -17
  165. package/dist/plugin/helpers/getModuleManifest.d.ts.map +0 -1
  166. package/dist/plugin/helpers/getModuleManifest.js +0 -23
  167. package/dist/plugin/helpers/inputNormalizerWorker.d.ts +0 -12
  168. package/dist/plugin/helpers/inputNormalizerWorker.d.ts.map +0 -1
  169. package/dist/plugin/helpers/inputNormalizerWorker.js +0 -33
  170. package/dist/plugin/helpers/normalizedRelativePath.d.ts +0 -11
  171. package/dist/plugin/helpers/normalizedRelativePath.d.ts.map +0 -1
  172. package/dist/plugin/helpers/normalizedRelativePath.js +0 -36
  173. package/dist/plugin/helpers/resolveFilePath.d.ts +0 -13
  174. package/dist/plugin/helpers/resolveFilePath.d.ts.map +0 -1
  175. package/dist/plugin/helpers/resolveFilePath.js +0 -74
  176. package/dist/plugin/helpers/resolveWorkerModule.d.ts +0 -6
  177. package/dist/plugin/helpers/resolveWorkerModule.d.ts.map +0 -1
  178. package/dist/plugin/helpers/resolveWorkerModule.js +0 -24
  179. package/dist/plugin/helpers/validateModuleBase.d.ts +0 -3
  180. package/dist/plugin/helpers/validateModuleBase.d.ts.map +0 -1
  181. package/dist/plugin/helpers/validateModuleBase.js +0 -16
  182. package/dist/plugin/helpers/validateResolvedConfig.d.ts +0 -3
  183. package/dist/plugin/helpers/validateResolvedConfig.d.ts.map +0 -1
  184. package/dist/plugin/helpers/validateResolvedConfig.js +0 -17
  185. package/dist/plugin/transformer/transformer-client-components.d.ts +0 -30
  186. package/dist/plugin/transformer/transformer-client-components.d.ts.map +0 -1
  187. package/dist/plugin/transformer/transformer-client-components.js +0 -122
  188. package/dist/plugin/transformer/transformer-client-components.js.map +0 -1
  189. package/dist/plugin/transformer/transformer-server-actions.d.ts +0 -29
  190. package/dist/plugin/transformer/transformer-server-actions.d.ts.map +0 -1
  191. package/dist/plugin/transformer/transformer-server-actions.js +0 -90
  192. package/dist/plugin/worker/rsc/createRscStream.d.ts +0 -5
  193. package/dist/plugin/worker/rsc/createRscStream.d.ts.map +0 -1
  194. package/dist/plugin/worker/rsc/createRscStream.js +0 -39
  195. package/dist/plugin/worker/rsc/createRscStream.js.map +0 -1
  196. package/dist/plugin/worker/rsc/development.d.ts +0 -5
  197. package/dist/plugin/worker/rsc/development.d.ts.map +0 -1
  198. package/dist/plugin/worker/rsc/development.js +0 -13
  199. package/dist/plugin/worker/rsc/development.js.map +0 -1
  200. package/dist/plugin/worker/rsc/plugin.js.map +0 -1
  201. package/dist/plugin/worker/rsc/production.d.ts +0 -5
  202. package/dist/plugin/worker/rsc/production.d.ts.map +0 -1
  203. package/dist/plugin/worker/rsc/production.js +0 -13
  204. package/dist/plugin/worker/rsc/production.js.map +0 -1
  205. package/plugin/helpers/createClientInputNormalizer.ts +0 -48
  206. package/plugin/helpers/createServerInputNormalizer.ts +0 -52
  207. package/plugin/helpers/createStaticInputNormalizer.ts +0 -26
  208. package/plugin/helpers/getModuleManifest.ts +0 -36
  209. package/plugin/helpers/inputNormalizerWorker.ts +0 -52
  210. package/plugin/helpers/normalizedRelativePath.ts +0 -59
  211. package/plugin/helpers/resolveFilePath.ts +0 -108
  212. package/plugin/helpers/resolveWorkerModule.ts +0 -41
  213. package/plugin/helpers/validateModuleBase.ts +0 -30
  214. package/plugin/helpers/validateResolvedConfig.ts +0 -21
  215. package/plugin/transformer/transformer-client-components.ts +0 -168
  216. package/plugin/transformer/transformer-server-actions.ts +0 -125
  217. package/plugin/worker/rsc/createRscStream.ts +0 -42
  218. package/plugin/worker/rsc/development.ts +0 -6
  219. package/plugin/worker/rsc/production.ts +0 -6
  220. package/scripts/react-server-dom-esm+0.0.1.patch +0 -24775
@@ -1,23 +1,20 @@
1
- import { appendFile, mkdirSync } from "node:fs";
1
+ import { mkdirSync } from "node:fs";
2
2
  import { mkdir, writeFile } from "node:fs/promises";
3
- import { dirname, join, resolve, resolve as resolvePath } from "node:path";
3
+ import { dirname, join, resolve as resolvePath } from "node:path";
4
4
  import { Transform } from "node:stream";
5
5
  import type { Worker } from "node:worker_threads";
6
6
  import { createHandler } from "../../react-server/createHandler.js";
7
- import type { ResolvedUserConfig, ResolvedUserOptions } from "../../types.js";
7
+ import type { CheckFilesExistReturn, ResolvedUserConfig, ResolvedUserOptions } from "../../types.js";
8
8
  import type {
9
- HtmlWorkerMessage,
10
9
  HtmlWorkerResponse,
11
10
  WorkerRscChunkMessage,
12
11
  } from "../types.js";
13
12
  import type { Manifest } from "vite";
14
13
  import type {
15
- EmittedFile,
16
- EmittedPrebuiltChunk,
17
14
  PluginContext,
18
- ResolvedId,
19
15
  } from "rollup";
20
- import { createInputNormalizer } from "../../helpers/inputNormalizer.js";
16
+ import React from "react";
17
+ import { collectManifestCss } from "../../collect-css-manifest.js";
21
18
 
22
19
  interface PipeableStreamOptions {
23
20
  bootstrapModules?: string[];
@@ -53,217 +50,187 @@ type RenderPagesOptions = {
53
50
  export async function renderPages(
54
51
  pluginContext: PluginContext,
55
52
  routes: string[],
53
+ files: CheckFilesExistReturn,
56
54
  options: RenderPagesOptions
57
55
  ) {
58
- const root =
59
- pluginContext.environment.config.root ??
60
- options.userConfig.root ??
61
- options.pluginOptions.projectRoot ??
62
- process.cwd();
63
- const outDir =
64
- pluginContext.environment.config.build.outDir ??
65
- options.userConfig.build.outDir ??
66
- options.pluginOptions.build.outDir;
67
- const assetsDir =
68
- pluginContext.environment.config.build.assetsDir ??
69
- options.userConfig.build.assetsDir ??
70
- options.pluginOptions.build.assetsDir;
71
-
72
- const isServer = outDir.endsWith(options.pluginOptions.build.server);
73
- const isClient = outDir.endsWith(options.pluginOptions.build.client);
74
- if (!isServer && !isClient) {
75
- throw new Error("Invalid outDir directory");
76
- }
77
-
78
- const destinationRoot = isServer
79
- ? resolvePath(
80
- root,
81
- options.pluginOptions.build.outDir,
82
- options.pluginOptions.build.client
83
- )
84
- : join(root, outDir);
56
+ const root = pluginContext.environment.config.root;
57
+ const outDir = pluginContext.environment.config.build.outDir;
85
58
  const failedRoutes = new Map<string, Error>();
86
- const moduleRootPath =
87
- join(
88
- root,
89
- options.pluginOptions.build.outDir,
90
- options.pluginOptions.build.client
91
- ) + "/";
92
- const moduleBaseURL = `file://${root}`;
93
- const htmlRoot = destinationRoot;
94
- const rscRoot = destinationRoot;
95
- const streamStarted = new Set<string>();
96
59
  const completedRoutes = new Set<string>();
97
- const htmlContent = new Map<string, string>();
98
- const transforms = new Map<string, Transform>();
99
60
  const writePromises = new Map<string, Promise<void>>();
100
- const pipableStreamOptions = options.pipableStreamOptions ?? {};
101
- pipableStreamOptions.importMap = pipableStreamOptions?.importMap ?? {};
102
- pipableStreamOptions.importMap.imports =
103
- pipableStreamOptions.importMap.imports ?? {};
104
- if (!("react" in pipableStreamOptions.importMap.imports)) {
105
- pipableStreamOptions.importMap.imports["react"] = 'https://esm.sh/react@experimental?pin=v124&dev'
106
- }
107
- if (!("react-dom" in pipableStreamOptions.importMap.imports)) {
108
- pipableStreamOptions.importMap.imports["react-dom"] = 'https://esm.sh/react-dom@experimental?pin=v124&dev'
109
- }
110
- if (!("react-dom/" in pipableStreamOptions.importMap.imports)) {
111
- pipableStreamOptions.importMap.imports["react-dom/"] = 'https://esm.sh/react-dom@experimental&pin=v124&dev/'
112
- }
113
- if (!("react-server-dom-esm/client.browser" in pipableStreamOptions.importMap.imports)) {
114
- pipableStreamOptions.importMap.imports["react-server-dom-esm/client.browser"] = `/node_modules/react-server-dom-esm/esm/react-server-dom-esm-client.browser.${options.userConfig.mode}.js`
115
- }
116
- // Find matching client components by their source paths
117
- for (const [key, serverEntry] of Object.entries(options.serverManifest)) {
118
- // Skip non-client components
119
- if (!key.includes(".client.")) continue;
120
-
121
- // Find matching client entry by source path
122
- const clientEntry = Object.entries(options.clientManifest).find(
123
- ([_, entry]) => entry.src === serverEntry.src
124
- );
125
-
126
- if (!clientEntry) continue;
127
-
128
- const [_, entry] = clientEntry;
129
- const serverPath = serverEntry.src as string;
130
- const clientPath = entry.file
131
-
132
- pipableStreamOptions.importMap.imports[serverPath] = '/' + clientPath;
133
-
134
- }
135
- for(const [key, value] of Object.entries(options.clientManifest)) {
136
- if(value.isEntry) {
137
- if(Array.isArray(pipableStreamOptions.bootstrapModules)) {
138
- pipableStreamOptions.bootstrapModules.push('/'+value.file);
139
- } else {
140
- pipableStreamOptions.bootstrapModules = ['/'+value.file];
141
- }
142
- }
143
- }
144
-
145
- // Remove the initial empty file writes - we'll create directories as needed
146
- await mkdir(htmlRoot, { recursive: true });
147
- await mkdir(rscRoot, { recursive: true });
148
61
 
149
62
  try {
150
- const allRoutesComplete = new Promise<void>((resolve) => {
63
+ // Set up worker message handling
64
+ const allRoutesComplete = new Promise<void>((resolve, reject) => {
151
65
  options.worker.on("message", (msg: HtmlWorkerResponse) => {
152
66
  switch (msg.type) {
153
67
  case "ALL_READY": {
154
68
  const { id, html, outputPath } = msg;
155
69
  mkdirSync(dirname(outputPath), { recursive: true });
156
70
 
157
- const writePromise = writeFile(outputPath, html)
71
+ writeFile(outputPath, html)
158
72
  .then(() => {
159
73
  completedRoutes.add(id);
160
- writePromises.delete(id);
161
-
162
- // Only resolve when all routes are complete
163
74
  if (completedRoutes.size === routes.length) {
164
75
  resolve();
165
76
  }
166
77
  })
167
78
  .catch((error) => {
79
+ console.error('Write error for route:', id, error);
168
80
  failedRoutes.set(id, error as Error);
81
+ reject(error);
169
82
  });
170
-
171
- writePromises.set(id, writePromise);
172
83
  break;
173
84
  }
174
85
  case "ERROR": {
86
+ console.error('Worker error for route:', msg.id, msg.error);
175
87
  failedRoutes.set(msg.id, new Error(msg.error));
88
+ reject(new Error(msg.error));
176
89
  break;
177
90
  }
178
91
  }
179
92
  });
180
93
  });
181
94
 
182
- const renderPromises = routes.map(async (route) => {
183
- try {
184
- const result = await createHandler(route, options.pluginOptions, {
185
- loader: options.loader,
186
- clientManifest: options.clientManifest,
187
- serverManifest: options.serverManifest,
188
- pipableStreamOptions: options.pipableStreamOptions,
189
- });
190
-
191
- if (result.type !== "success") {
192
- failedRoutes.set(route, new Error(`Handler failed for ${route}`));
193
- return;
194
- }
95
+ // Process routes sequentially
96
+ for (const route of routes) {
97
+ const routeFiles = files.urlMap.get(route);
98
+ if (!routeFiles) {
99
+ console.error('No files found for route:', route);
100
+ failedRoutes.set(route, new Error(`No files found for ${route}`));
101
+ continue;
102
+ }
195
103
 
196
- const htmlOutputPath = route === "/"
197
- ? join(htmlRoot, "index.html")
198
- : join(htmlRoot, route, "index.html");
104
+ const cssFiles = collectManifestCss(
105
+ options.serverManifest,
106
+ options.moduleBasePath,
107
+ routeFiles.page,
108
+ options.onCssFile
109
+ );
110
+
111
+ // Create handler for pure RSC output
112
+ const rscResult = await createHandler(route, {
113
+ ...options.pluginOptions,
114
+ Html: React.Fragment // Use Fragment for pure RSC output
115
+ }, {
116
+ loader: options.loader,
117
+ clientManifest: options.clientManifest,
118
+ serverManifest: options.serverManifest,
119
+ pipableStreamOptions: {
120
+ ...options.pipableStreamOptions,
121
+ importMap: {
122
+ imports: {
123
+ ...options.pipableStreamOptions?.importMap?.imports,
124
+ ...Object.fromEntries(Array.from(cssFiles.entries()))
125
+ }
126
+ }
127
+ },
128
+ });
199
129
 
200
- transforms.set(route, new Transform({
201
- transform(chunk, _encoding, callback) {
202
- options.worker.postMessage({
203
- type: "RSC_CHUNK",
204
- id: route,
205
- chunk: chunk,
206
- moduleRootPath: moduleRootPath,
207
- moduleBaseURL: moduleBaseURL,
208
- htmlOutputPath: htmlOutputPath,
209
- outDir: options.userConfig.build.outDir,
210
- pipableStreamOptions: pipableStreamOptions,
211
- clientManifest: options.clientManifest,
212
- serverManifest: options.serverManifest,
213
- } satisfies WorkerRscChunkMessage);
130
+ // Create handler for HTML output
131
+ const htmlResult = await createHandler(route, options.pluginOptions, {
132
+ loader: options.loader,
133
+ clientManifest: options.clientManifest,
134
+ serverManifest: options.serverManifest,
135
+ pipableStreamOptions: {
136
+ ...options.pipableStreamOptions,
137
+ importMap: {
138
+ imports: {
139
+ ...options.pipableStreamOptions?.importMap?.imports,
140
+ ...Object.fromEntries(Array.from(cssFiles.entries()))
141
+ }
142
+ }
143
+ },
144
+ });
214
145
 
215
- const rscOutputPath = route === "/"
216
- ? join(rscRoot, "index.rsc")
217
- : join(rscRoot, route, "index.rsc");
146
+ if (rscResult.type !== "success" || htmlResult.type !== "success") {
147
+ console.error('Handler failed for route:', route);
148
+ failedRoutes.set(route, new Error(`Handler failed for ${route}`));
149
+ continue;
150
+ }
218
151
 
219
- mkdirSync(dirname(rscOutputPath), { recursive: true });
220
-
221
- // Track RSC file write
222
- const writePromise = writeFile(rscOutputPath, chunk)
223
- .catch((error) => {
224
- failedRoutes.set(route, error as Error);
152
+ // Process both streams
153
+ await Promise.all([
154
+ // Save RSC stream to .rsc file in client directory
155
+ new Promise<void>((resolve, reject) => {
156
+ const chunks: Buffer[] = [];
157
+ const rscTransform = new Transform({
158
+ transform(chunk, _encoding, callback) {
159
+ try {
160
+ chunks.push(Buffer.from(chunk));
161
+ callback(null, chunk);
162
+ } catch (error) {
163
+ callback(error as Error);
164
+ }
165
+ },
166
+ flush(callback) {
167
+ try {
168
+ const rscPath = join(options.pluginOptions.build.outDir, options.pluginOptions.build.client, route, 'index.rsc');
169
+
170
+ // Ensure directory exists
171
+ mkdirSync(dirname(rscPath), { recursive: true });
172
+
173
+ // Write complete file
174
+ writeFile(rscPath, Buffer.concat(chunks))
175
+ .then(() => {
176
+ callback();
177
+ resolve();
178
+ })
179
+ .catch(error => {
180
+ console.error('RSC write error:', error);
181
+ callback(error as Error);
182
+ reject(error);
183
+ });
184
+ } catch (error) {
185
+ callback(error as Error);
186
+ reject(error);
187
+ }
188
+ }
189
+ });
190
+
191
+ rscResult.stream.pipe(rscTransform);
192
+ }),
193
+
194
+ // Send HTML stream to worker
195
+ new Promise<void>((resolve, reject) => {
196
+ const htmlTransform = new Transform({
197
+ transform(chunk, _encoding, callback) {
198
+ try {
199
+ options.worker.postMessage({
200
+ type: "RSC_CHUNK",
201
+ id: route,
202
+ chunk: chunk.toString(),
203
+ moduleRootPath: join(root, options.pluginOptions.build.outDir),
204
+ moduleBaseURL: options.moduleBaseURL,
205
+ htmlOutputPath: join(options.pluginOptions.build.outDir, options.pluginOptions.build.client, route, 'index.html'),
206
+ pipableStreamOptions: options.pipableStreamOptions,
207
+ });
208
+ callback(null, chunk);
209
+ } catch (error) {
210
+ callback(error as Error);
211
+ }
212
+ },
213
+ flush(callback) {
214
+ options.worker.postMessage({
215
+ type: "RSC_END",
216
+ id: route,
225
217
  });
218
+ callback();
219
+ resolve();
220
+ }
221
+ });
222
+
223
+ htmlResult.stream.pipe(htmlTransform);
224
+ })
225
+ ]);
226
+ }
226
227
 
227
- writePromises.set(`${route}:rsc`, writePromise);
228
- callback(null, chunk);
229
- },
230
- flush(callback) {
231
- options.worker.postMessage({
232
- type: "RSC_END",
233
- id: route,
234
- });
235
- callback();
236
- },
237
- }));
238
-
239
- result.stream.pipe(transforms.get(route) as Transform);
240
- await new Promise<void>((resolve) => {
241
- transforms.get(route)?.on("finish", resolve);
242
- });
243
- } catch (error) {
244
- failedRoutes.set(route, error as Error);
245
- }
246
- });
247
-
248
- // Wait for everything to complete
249
- await Promise.all(renderPromises);
250
- await Promise.all(writePromises.values());
251
228
  await allRoutesComplete;
252
229
 
253
- } finally {
254
- for (const transform of transforms.values()) {
255
- transform.destroy();
256
- }
257
- transforms.clear();
258
- writePromises.clear();
259
-
260
- options.worker.postMessage({
261
- type: "SHUTDOWN",
262
- });
230
+ } catch (error) {
231
+ console.error('Render error:', error);
232
+ throw error;
263
233
  }
264
234
 
265
- return {
266
- failedRoutes,
267
- completedRoutes,
268
- };
235
+ return { failedRoutes, completedRoutes };
269
236
  }
@@ -1,14 +1,5 @@
1
- export { reactRscWorkerPlugin } from "./plugin.js";
2
-
3
- // Dynamic import based on NODE_ENV
4
- export const worker = await (
5
- process.env['NODE_ENV'] === 'production'
6
- ? import('./production.js')
7
- : import('./development.js')
1
+ await(
2
+ process.env["NODE_ENV"] === "production"
3
+ ? import("./rsc-worker.production.js")
4
+ : import("./rsc-worker.development.js")
8
5
  );
9
-
10
- // Re-export worker functions
11
- export const {
12
- createRscStream,
13
- createWorker
14
- } = worker;
@@ -0,0 +1,143 @@
1
+ import { createWriteStream } from "node:fs";
2
+ import { mkdir } from "node:fs/promises";
3
+ import { dirname, join } from "node:path";
4
+ import { parentPort } from "node:worker_threads";
5
+ import { PassThrough } from "node:stream";
6
+ import {
7
+ renderToPipeableStream,
8
+ // @ts-ignore
9
+ } from "react-server-dom-esm/server.node";
10
+ import type {
11
+ RscChunkMessage,
12
+ RscEndMessage,
13
+ RscWorkerMessage,
14
+ } from "../types.js";
15
+ import { createLogger } from "../../utils/logger.js";
16
+ import {
17
+ cssFiles,
18
+ clientFiles,
19
+ serverActionFiles,
20
+ addCssFile,
21
+ clearCssFiles,
22
+ } from "./state.js";
23
+ import type { WriteStream } from "node:fs";
24
+ import React from "react";
25
+
26
+ const log = createLogger("rsc-worker");
27
+
28
+ // CSS collector component
29
+ function CssCollector({
30
+ children,
31
+ cssFiles,
32
+ }: {
33
+ children: React.ReactNode;
34
+ cssFiles: Map<string, string>;
35
+ }) {
36
+ return (
37
+ <>
38
+ {Array.from(cssFiles.entries()).map(([id, css]) => {
39
+ return (
40
+ <style key={id} data-source={id}>
41
+ {css}
42
+ </style>
43
+ );
44
+ })}
45
+ {children}
46
+ </>
47
+ );
48
+ }
49
+
50
+ export async function messageHandler(message: RscWorkerMessage) {
51
+
52
+ if (message.type === "RSC_RENDER") {
53
+ const {
54
+ id,
55
+ pageImport,
56
+ propsImport,
57
+ pageExportName,
58
+ propsExportName,
59
+ url,
60
+ outDir,
61
+ projectRoot,
62
+ moduleBaseURL,
63
+ moduleBasePath,
64
+ pipableStreamOptions,
65
+ } = message;
66
+
67
+ try {
68
+ // Load modules which will trigger CSS loading
69
+ const [Component, propsModule] = await Promise.all([
70
+ import(join(projectRoot, pageImport)),
71
+ import(join(projectRoot, propsImport)),
72
+ ]);
73
+
74
+ const propsAtExport = propsModule[propsExportName];
75
+ const props = await Promise.resolve(
76
+ typeof propsAtExport === "function" ? propsAtExport(url) : propsAtExport
77
+ );
78
+
79
+ const PageComponent = Component[pageExportName];
80
+ // Now render with collected CSS
81
+ const stream = renderToPipeableStream(
82
+ <CssCollector cssFiles={cssFiles}>
83
+ <PageComponent {...props} />
84
+ </CssCollector>,
85
+ moduleBaseURL,
86
+ {
87
+ onError: (error: Error) => {
88
+ log.error(`Stream error at ${id}:`, error);
89
+ parentPort?.postMessage({
90
+ type: "ERROR",
91
+ id,
92
+ error: error instanceof Error ? error.message : String(error),
93
+ });
94
+ },
95
+ onPostpone: log?.info ?? console.info,
96
+ environmentName: "Server",
97
+ importMap: {
98
+ imports: {
99
+ ...pipableStreamOptions?.importMap?.imports,
100
+ "/": moduleBasePath,
101
+ },
102
+ },
103
+ ...pipableStreamOptions,
104
+ }
105
+ );
106
+
107
+ // Listen for data and end events
108
+ const passThrough = new PassThrough();
109
+
110
+ stream.pipe(passThrough);
111
+
112
+ passThrough.on("data", (chunk) => {
113
+ // Send to parent
114
+ parentPort?.postMessage({
115
+ type: "RSC_CHUNK",
116
+ id,
117
+ chunk: chunk.toString(),
118
+ moduleRootPath: moduleBasePath,
119
+ moduleBaseURL,
120
+ outDir,
121
+ rscOutputPath: `${outDir}/${id}.rsc`,
122
+ cssFiles: Array.from(cssFiles.entries()),
123
+ } satisfies RscChunkMessage);
124
+ });
125
+
126
+ passThrough.on("end", () => {
127
+ parentPort?.postMessage({
128
+ type: "RSC_END",
129
+ id,
130
+ } satisfies RscEndMessage);
131
+ });
132
+ } catch (error) {
133
+ console.trace(error);
134
+ parentPort?.postMessage({
135
+ type: "ERROR",
136
+ id,
137
+ error: error instanceof Error ? error.message : String(error),
138
+ });
139
+ }
140
+ } else if (message.type === "CSS_FILE") {
141
+ addCssFile(message.id, message.cssFile);
142
+ }
143
+ }
@@ -1,6 +1,6 @@
1
1
  import type { Plugin } from "vite";
2
2
  import { resolve } from "path";
3
- import type { ModuleFormat } from 'rollup';
3
+ import type { ModuleFormat } from "rollup";
4
4
  import type { StreamPluginOptions } from "../../types.js";
5
5
  import { DEFAULT_CONFIG } from "../../config/defaults.js";
6
6
  import { getPluginRoot } from "../../config/getPaths.js";
@@ -11,72 +11,73 @@ export function reactRscWorkerPlugin(options: StreamPluginOptions): Plugin {
11
11
  config(config) {
12
12
  const root = config.root ?? process.cwd();
13
13
  const pluginRoot = getPluginRoot();
14
- const rscWorkerPath = typeof options.rscWorkerPath === 'string'
15
- ? resolve(root, options.rscWorkerPath)
16
- : resolve(pluginRoot, DEFAULT_CONFIG.RSC_WORKER_PATH);
17
-
18
- const format: ModuleFormat = 'esm';
14
+ const rscWorkerPath =
15
+ typeof options.rscWorkerPath === "string"
16
+ ? resolve(root, options.rscWorkerPath)
17
+ : resolve(pluginRoot, DEFAULT_CONFIG.RSC_WORKER_PATH);
18
+
19
+ const format: ModuleFormat = "esm";
19
20
 
20
21
  // Single worker output for server build
21
22
  const workerConfig = {
22
23
  input: {
23
- 'rsc-worker': rscWorkerPath,
24
+ "rsc-worker": rscWorkerPath,
24
25
  },
25
26
  output: {
26
27
  format,
27
- dir: options.build?.server ?? 'dist/server', // Output to server directory
28
- entryFileNames: '[name].js',
28
+ dir: options.build?.server ?? "dist/server", // Output to server directory
29
+ entryFileNames: "[name].js",
29
30
  preserveModules: true,
30
31
  manualChunks: {
31
- 'rsc-worker': [rscWorkerPath]
32
+ "rsc-worker": [rscWorkerPath],
32
33
  },
33
34
  resolve: {
34
- conditions: ['react-server'],
35
- }
36
- }
35
+ conditions: ["react-server"],
36
+ },
37
+ },
37
38
  };
38
39
 
39
40
  return {
40
41
  build: {
41
42
  rollupOptions: {
42
- preserveEntrySignatures: 'strict',
43
+ preserveEntrySignatures: "strict",
43
44
  input: {
44
45
  ...workerConfig.input,
45
- ...(typeof config.build?.rollupOptions?.input === 'object'
46
- ? config.build?.rollupOptions?.input
46
+ ...(typeof config.build?.rollupOptions?.input === "object"
47
+ ? config.build?.rollupOptions?.input
47
48
  : {}),
48
49
  },
49
50
  external: [
50
- 'vite',
51
- 'rollup',
52
- 'react',
53
- 'react-dom',
54
- 'react-dom/server',
55
- 'react-server-dom-esm',
56
- 'react-server-dom-esm/client.node',
57
- 'react-server-dom-esm/server.node',
58
- 'react-server-dom-esm/node-loader',
59
- 'source-map',
60
- 'acorn-loose',
61
- 'webpack-sources',
62
- 'stream',
63
- 'util',
64
- 'crypto',
65
- 'async_hooks',
66
- 'fs',
67
- 'path',
68
- 'worker_threads',
51
+ "vite",
52
+ "rollup",
53
+ "react",
54
+ "react-dom",
55
+ "react-dom/server",
56
+ "react-server-dom-esm",
57
+ "react-server-dom-esm/client.node",
58
+ "react-server-dom-esm/server.node",
59
+ "react-server-dom-esm/node-loader",
60
+ "source-map",
61
+ "acorn-loose",
62
+ "webpack-sources",
63
+ "stream",
64
+ "util",
65
+ "crypto",
66
+ "async_hooks",
67
+ "fs",
68
+ "path",
69
+ "worker_threads",
69
70
  // if we use node: paths in our code, it should always be catched by below rule.
70
71
  /^node:.*/,
71
72
  ],
72
73
  output: {
73
74
  ...workerConfig.output,
74
- }
75
+ },
75
76
  },
76
77
  manifest: true, // Ensure manifest is generated
77
78
  minify: false,
78
79
  sourcemap: true,
79
- }
80
+ },
80
81
  };
81
82
  },
82
83
  };