vite-plugin-react-server 0.3.11 → 0.3.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.
Files changed (221) 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 +1 -1
  7. package/dist/plugin/collect-css-manifest.d.ts.map +1 -1
  8. package/dist/plugin/collect-css-manifest.js +8 -3
  9. package/dist/plugin/collect-css-manifest.js.map +1 -1
  10. package/dist/plugin/components.js +10 -15
  11. package/dist/plugin/config/createModuleIdGenerator.js +1 -1
  12. package/dist/plugin/config/createModuleIdGenerator.js.map +1 -1
  13. package/dist/plugin/config/defaults.d.ts +5 -14
  14. package/dist/plugin/config/defaults.d.ts.map +1 -1
  15. package/dist/plugin/config/defaults.js +12 -12
  16. package/dist/plugin/config/defaults.js.map +1 -1
  17. package/dist/plugin/config/getPaths.js +1 -1
  18. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  19. package/dist/plugin/config/resolveOptions.js +73 -52
  20. package/dist/plugin/config/resolveOptions.js.map +1 -1
  21. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  22. package/dist/plugin/config/resolveUserConfig.js +53 -65
  23. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  24. package/dist/plugin/helpers/getBundleManifest.d.ts +6 -1
  25. package/dist/plugin/helpers/getBundleManifest.d.ts.map +1 -1
  26. package/dist/plugin/helpers/getBundleManifest.js +48 -19
  27. package/dist/plugin/helpers/getBundleManifest.js.map +1 -1
  28. package/dist/plugin/helpers/inputNormalizer.d.ts +1 -2
  29. package/dist/plugin/helpers/inputNormalizer.d.ts.map +1 -1
  30. package/dist/plugin/helpers/inputNormalizer.js +52 -46
  31. package/dist/plugin/helpers/inputNormalizer.js.map +1 -1
  32. package/dist/plugin/helpers/tryManifest.d.ts +1 -1
  33. package/dist/plugin/helpers/tryManifest.d.ts.map +1 -1
  34. package/dist/plugin/helpers/tryManifest.js.map +1 -1
  35. package/dist/plugin/loader/createBuildLoader.d.ts +1 -1
  36. package/dist/plugin/loader/createBuildLoader.d.ts.map +1 -1
  37. package/dist/plugin/loader/createBuildLoader.js +29 -26
  38. package/dist/plugin/loader/createBuildLoader.js.map +1 -1
  39. package/dist/plugin/loader/css-loader.d.ts +16 -0
  40. package/dist/plugin/loader/css-loader.d.ts.map +1 -0
  41. package/dist/plugin/loader/css-loader.js +70 -0
  42. package/dist/plugin/loader/css-loader.js.map +1 -0
  43. package/dist/plugin/loader/react-loader.d.ts +17 -0
  44. package/dist/plugin/loader/react-loader.d.ts.map +1 -0
  45. package/dist/plugin/loader/react-loader.js +647 -0
  46. package/dist/plugin/loader/react-loader.js.map +1 -0
  47. package/dist/plugin/loader/rsc/messageHandler.d.ts +2 -0
  48. package/dist/plugin/loader/rsc/messageHandler.d.ts.map +1 -0
  49. package/dist/plugin/loader/rsc/messageHandler.js +1 -0
  50. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts +2 -0
  51. package/dist/plugin/loader/rsc/rsc-worker.development.d.ts.map +1 -0
  52. package/dist/plugin/loader/rsc/rsc-worker.development.js +1 -0
  53. package/dist/plugin/react-client/index.js +2 -2
  54. package/dist/plugin/react-client/index.js.map +1 -1
  55. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  56. package/dist/plugin/react-client/plugin.js +202 -25
  57. package/dist/plugin/react-client/plugin.js.map +1 -1
  58. package/dist/plugin/react-server/createHandler.d.ts.map +1 -1
  59. package/dist/plugin/react-server/createHandler.js +13 -7
  60. package/dist/plugin/react-server/createHandler.js.map +1 -1
  61. package/dist/plugin/react-server/createRscStream.d.ts +15 -3
  62. package/dist/plugin/react-server/createRscStream.d.ts.map +1 -1
  63. package/dist/plugin/react-server/createRscStream.js +52 -49
  64. package/dist/plugin/react-server/createRscStream.js.map +1 -1
  65. package/dist/plugin/react-server/plugin.d.ts.map +1 -1
  66. package/dist/plugin/react-server/plugin.js +76 -27
  67. package/dist/plugin/react-server/plugin.js.map +1 -1
  68. package/dist/plugin/transformer/plugin.d.ts.map +1 -1
  69. package/dist/plugin/transformer/plugin.js +65 -52
  70. package/dist/plugin/transformer/plugin.js.map +1 -1
  71. package/dist/plugin/types.d.ts +6 -1
  72. package/dist/plugin/types.d.ts.map +1 -1
  73. package/dist/plugin/utils/logger.d.ts +9 -0
  74. package/dist/plugin/utils/logger.d.ts.map +1 -0
  75. package/dist/plugin/utils/logger.js +68 -0
  76. package/dist/plugin/utils/logger.js.map +1 -0
  77. package/dist/plugin/worker/createWorker.d.ts +1 -0
  78. package/dist/plugin/worker/createWorker.d.ts.map +1 -1
  79. package/dist/plugin/worker/createWorker.js +23 -36
  80. package/dist/plugin/worker/createWorker.js.map +1 -1
  81. package/dist/plugin/worker/html/html-worker.production.js +5 -1
  82. package/dist/plugin/worker/html/html-worker.production.js.map +1 -1
  83. package/dist/plugin/worker/html/messageHandler.d.ts.map +1 -1
  84. package/dist/plugin/worker/html/messageHandler.js +10 -19
  85. package/dist/plugin/worker/html/messageHandler.js.map +1 -1
  86. package/dist/plugin/worker/html/renderPages.d.ts +3 -3
  87. package/dist/plugin/worker/html/renderPages.d.ts.map +1 -1
  88. package/dist/plugin/worker/html/renderPages.js +148 -131
  89. package/dist/plugin/worker/html/renderPages.js.map +1 -1
  90. package/dist/plugin/worker/rsc/index.d.ts +1 -3
  91. package/dist/plugin/worker/rsc/index.d.ts.map +1 -1
  92. package/dist/plugin/worker/rsc/index.js +1 -9
  93. package/dist/plugin/worker/rsc/index.js.map +1 -1
  94. package/dist/plugin/worker/rsc/messageHandler.d.ts +3 -0
  95. package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -0
  96. package/dist/plugin/worker/rsc/messageHandler.js +107 -0
  97. package/dist/plugin/worker/rsc/messageHandler.js.map +1 -0
  98. package/dist/plugin/worker/rsc/plugin.d.ts.map +1 -1
  99. package/dist/plugin/worker/rsc/plugin.js +74 -80
  100. package/dist/plugin/worker/rsc/rsc-worker.development.d.ts +32 -0
  101. package/dist/plugin/worker/rsc/rsc-worker.development.d.ts.map +1 -0
  102. package/dist/plugin/worker/rsc/rsc-worker.development.js +43 -0
  103. package/dist/plugin/worker/rsc/rsc-worker.development.js.map +1 -0
  104. package/dist/plugin/worker/rsc/rsc-worker.js +4 -106
  105. package/dist/plugin/worker/rsc/rsc-worker.production.d.ts +2 -0
  106. package/dist/plugin/worker/rsc/rsc-worker.production.d.ts.map +1 -0
  107. package/dist/plugin/worker/rsc/rsc-worker.production.js +14 -0
  108. package/dist/plugin/worker/rsc/rsc-worker.production.js.map +1 -0
  109. package/dist/plugin/worker/rsc/state.d.ts +11 -0
  110. package/dist/plugin/worker/rsc/state.d.ts.map +1 -0
  111. package/dist/plugin/worker/rsc/state.js +12 -0
  112. package/dist/plugin/worker/rsc/state.js.map +1 -0
  113. package/dist/plugin/worker/types.d.ts +60 -46
  114. package/dist/plugin/worker/types.d.ts.map +1 -1
  115. package/dist/tsconfig.tsbuildinfo +1 -1
  116. package/package.json +15 -11
  117. package/plugin/checkFilesExist.ts +42 -62
  118. package/plugin/collect-css-manifest.ts +9 -4
  119. package/plugin/config/createModuleIdGenerator.ts +1 -1
  120. package/plugin/config/defaults.ts +13 -15
  121. package/plugin/config/resolveOptions.ts +134 -76
  122. package/plugin/config/resolveUserConfig.ts +75 -76
  123. package/plugin/helpers/getBundleManifest.ts +69 -31
  124. package/plugin/helpers/inputNormalizer.ts +82 -70
  125. package/plugin/helpers/tryManifest.ts +1 -1
  126. package/plugin/loader/createBuildLoader.ts +38 -41
  127. package/plugin/loader/css-loader.ts +96 -0
  128. package/plugin/loader/react-loader.ts +945 -0
  129. package/plugin/loader/rsc/messageHandler.tsx +1 -0
  130. package/plugin/loader/rsc/rsc-worker.development.ts +1 -0
  131. package/plugin/react-client/index.ts +1 -1
  132. package/plugin/react-client/plugin.ts +266 -41
  133. package/plugin/react-server/createHandler.ts +12 -8
  134. package/plugin/react-server/createRscStream.ts +75 -54
  135. package/plugin/react-server/plugin.ts +86 -35
  136. package/plugin/transformer/plugin.ts +67 -76
  137. package/plugin/types/global.d.ts +8 -0
  138. package/plugin/types.ts +3 -1
  139. package/plugin/utils/logger.ts +52 -0
  140. package/plugin/worker/createWorker.ts +43 -44
  141. package/plugin/worker/html/html-worker.production.tsx +7 -2
  142. package/plugin/worker/html/messageHandler.ts +13 -21
  143. package/plugin/worker/html/renderPages.ts +166 -181
  144. package/plugin/worker/rsc/index.ts +4 -13
  145. package/plugin/worker/rsc/messageHandler.tsx +143 -0
  146. package/plugin/worker/rsc/plugin.ts +38 -37
  147. package/plugin/worker/rsc/rsc-worker.development.ts +107 -0
  148. package/plugin/worker/rsc/rsc-worker.production.ts +13 -0
  149. package/plugin/worker/rsc/rsc-worker.tsx +5 -128
  150. package/plugin/worker/rsc/state.ts +37 -0
  151. package/plugin/worker/types.ts +79 -55
  152. package/scripts/check-react-version.mjs +17 -7
  153. package/scripts/react+0.0.0-experimental-b3a95caf-20250113.patch +143 -4170
  154. package/scripts/react-dom+0.0.0-experimental-b3a95caf-20250113.patch +14271 -90079
  155. package/dist/plugin/components.js.map +0 -1
  156. package/dist/plugin/helpers/createClientInputNormalizer.d.ts +0 -8
  157. package/dist/plugin/helpers/createClientInputNormalizer.d.ts.map +0 -1
  158. package/dist/plugin/helpers/createClientInputNormalizer.js +0 -35
  159. package/dist/plugin/helpers/createServerInputNormalizer.d.ts +0 -9
  160. package/dist/plugin/helpers/createServerInputNormalizer.d.ts.map +0 -1
  161. package/dist/plugin/helpers/createServerInputNormalizer.js +0 -37
  162. package/dist/plugin/helpers/createStaticInputNormalizer.d.ts +0 -7
  163. package/dist/plugin/helpers/createStaticInputNormalizer.d.ts.map +0 -1
  164. package/dist/plugin/helpers/createStaticInputNormalizer.js +0 -18
  165. package/dist/plugin/helpers/getModuleManifest.d.ts +0 -17
  166. package/dist/plugin/helpers/getModuleManifest.d.ts.map +0 -1
  167. package/dist/plugin/helpers/getModuleManifest.js +0 -23
  168. package/dist/plugin/helpers/inputNormalizerWorker.d.ts +0 -12
  169. package/dist/plugin/helpers/inputNormalizerWorker.d.ts.map +0 -1
  170. package/dist/plugin/helpers/inputNormalizerWorker.js +0 -33
  171. package/dist/plugin/helpers/normalizedRelativePath.d.ts +0 -11
  172. package/dist/plugin/helpers/normalizedRelativePath.d.ts.map +0 -1
  173. package/dist/plugin/helpers/normalizedRelativePath.js +0 -36
  174. package/dist/plugin/helpers/resolveFilePath.d.ts +0 -13
  175. package/dist/plugin/helpers/resolveFilePath.d.ts.map +0 -1
  176. package/dist/plugin/helpers/resolveFilePath.js +0 -74
  177. package/dist/plugin/helpers/resolveWorkerModule.d.ts +0 -6
  178. package/dist/plugin/helpers/resolveWorkerModule.d.ts.map +0 -1
  179. package/dist/plugin/helpers/resolveWorkerModule.js +0 -24
  180. package/dist/plugin/helpers/validateModuleBase.d.ts +0 -3
  181. package/dist/plugin/helpers/validateModuleBase.d.ts.map +0 -1
  182. package/dist/plugin/helpers/validateModuleBase.js +0 -16
  183. package/dist/plugin/helpers/validateResolvedConfig.d.ts +0 -3
  184. package/dist/plugin/helpers/validateResolvedConfig.d.ts.map +0 -1
  185. package/dist/plugin/helpers/validateResolvedConfig.js +0 -17
  186. package/dist/plugin/transformer/transformer-client-components.d.ts +0 -30
  187. package/dist/plugin/transformer/transformer-client-components.d.ts.map +0 -1
  188. package/dist/plugin/transformer/transformer-client-components.js +0 -122
  189. package/dist/plugin/transformer/transformer-client-components.js.map +0 -1
  190. package/dist/plugin/transformer/transformer-server-actions.d.ts +0 -29
  191. package/dist/plugin/transformer/transformer-server-actions.d.ts.map +0 -1
  192. package/dist/plugin/transformer/transformer-server-actions.js +0 -90
  193. package/dist/plugin/worker/rsc/createRscStream.d.ts +0 -5
  194. package/dist/plugin/worker/rsc/createRscStream.d.ts.map +0 -1
  195. package/dist/plugin/worker/rsc/createRscStream.js +0 -39
  196. package/dist/plugin/worker/rsc/createRscStream.js.map +0 -1
  197. package/dist/plugin/worker/rsc/development.d.ts +0 -5
  198. package/dist/plugin/worker/rsc/development.d.ts.map +0 -1
  199. package/dist/plugin/worker/rsc/development.js +0 -13
  200. package/dist/plugin/worker/rsc/development.js.map +0 -1
  201. package/dist/plugin/worker/rsc/plugin.js.map +0 -1
  202. package/dist/plugin/worker/rsc/production.d.ts +0 -5
  203. package/dist/plugin/worker/rsc/production.d.ts.map +0 -1
  204. package/dist/plugin/worker/rsc/production.js +0 -13
  205. package/dist/plugin/worker/rsc/production.js.map +0 -1
  206. package/plugin/helpers/createClientInputNormalizer.ts +0 -48
  207. package/plugin/helpers/createServerInputNormalizer.ts +0 -52
  208. package/plugin/helpers/createStaticInputNormalizer.ts +0 -26
  209. package/plugin/helpers/getModuleManifest.ts +0 -36
  210. package/plugin/helpers/inputNormalizerWorker.ts +0 -52
  211. package/plugin/helpers/normalizedRelativePath.ts +0 -59
  212. package/plugin/helpers/resolveFilePath.ts +0 -108
  213. package/plugin/helpers/resolveWorkerModule.ts +0 -41
  214. package/plugin/helpers/validateModuleBase.ts +0 -30
  215. package/plugin/helpers/validateResolvedConfig.ts +0 -21
  216. package/plugin/transformer/transformer-client-components.ts +0 -168
  217. package/plugin/transformer/transformer-server-actions.ts +0 -125
  218. package/plugin/worker/rsc/createRscStream.ts +0 -42
  219. package/plugin/worker/rsc/development.ts +0 -6
  220. package/plugin/worker/rsc/production.ts +0 -6
  221. 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[];
@@ -44,7 +41,7 @@ type RenderPagesOptions = {
44
41
  worker: Worker;
45
42
  pipableStreamOptions?: PipeableStreamOptions;
46
43
  loader: (id: string) => Promise<Record<string, any>>;
47
- onCssFile?: (path: string) => void;
44
+ onCssFile?: (url: string, parentUrl: string) => void;
48
45
  clientCss?: string[];
49
46
  moduleBasePath: string;
50
47
  moduleBaseURL: string;
@@ -53,217 +50,205 @@ type RenderPagesOptions = {
53
50
  export async function renderPages(
54
51
  pluginContext: PluginContext,
55
52
  routes: string[],
56
- options: RenderPagesOptions
53
+ files: CheckFilesExistReturn,
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
+ const clientCss = options.clientCss ?? [];
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;
95
+ 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);
194
103
  }
104
+ },
105
+ join(root, options.pluginOptions.build.outDir, options.pluginOptions.build.client)
106
+ );
195
107
 
196
- const htmlOutputPath = route === "/"
197
- ? join(htmlRoot, "index.html")
198
- : join(htmlRoot, route, "index.html");
199
-
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);
214
-
215
- const rscOutputPath = route === "/"
216
- ? join(rscRoot, "index.rsc")
217
- : join(rscRoot, route, "index.rsc");
108
+ // Process routes sequentially
109
+ for (const route of routes) {
110
+ const routeFiles = files.urlMap.get(route);
111
+ if (!routeFiles) {
112
+ console.error('No files found for route:', route);
113
+ failedRoutes.set(route, new Error(`No files found for ${route}`));
114
+ continue;
115
+ }
218
116
 
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);
225
- });
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
+ }
126
+ }
127
+ );
128
+
129
+ // Create handler for pure RSC output
130
+ const rscResult = await createHandler(route, {
131
+ ...options.pluginOptions,
132
+ Html: React.Fragment // Use Fragment for pure RSC output
133
+ }, {
134
+ loader: options.loader,
135
+ clientManifest: options.clientManifest,
136
+ serverManifest: options.serverManifest,
137
+ cssFiles: clientCss,
138
+ pipableStreamOptions: {
139
+ ...options.pipableStreamOptions,
140
+ importMap: {
141
+ imports: {
142
+ ...options.pipableStreamOptions?.importMap?.imports,
143
+ }
144
+ }
145
+ },
146
+ });
226
147
 
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
- }));
148
+ // Create handler for HTML output
149
+ const htmlResult = await createHandler(route, options.pluginOptions, {
150
+ loader: options.loader,
151
+ clientManifest: options.clientManifest,
152
+ serverManifest: options.serverManifest,
153
+ cssFiles: clientCss,
154
+ pipableStreamOptions: {
155
+ ...options.pipableStreamOptions,
156
+ importMap: {
157
+ imports: {
158
+ ...options.pipableStreamOptions?.importMap?.imports
159
+ }
160
+ }
161
+ },
162
+ });
238
163
 
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);
164
+ if (rscResult.type !== "success" || htmlResult.type !== "success") {
165
+ console.error('Handler failed for route:', route);
166
+ failedRoutes.set(route, new Error(`Handler failed for ${route}`));
167
+ continue;
245
168
  }
246
- });
247
-
248
- // Wait for everything to complete
249
- await Promise.all(renderPromises);
250
- await Promise.all(writePromises.values());
251
- await allRoutesComplete;
252
169
 
253
- } finally {
254
- for (const transform of transforms.values()) {
255
- transform.destroy();
170
+ // Process both streams
171
+ await Promise.all([
172
+ // Save RSC stream to .rsc file in client directory
173
+ new Promise<void>((resolve, reject) => {
174
+ const chunks: Buffer[] = [];
175
+ const rscTransform = new Transform({
176
+ transform(chunk, _encoding, callback) {
177
+ try {
178
+ chunks.push(Buffer.from(chunk));
179
+ callback(null, chunk);
180
+ } catch (error) {
181
+ callback(error as Error);
182
+ }
183
+ },
184
+ flush(callback) {
185
+ try {
186
+ const rscPath = join(options.pluginOptions.build.outDir, options.pluginOptions.build.client, route, 'index.rsc');
187
+
188
+ // Ensure directory exists
189
+ mkdirSync(dirname(rscPath), { recursive: true });
190
+
191
+ // Write complete file
192
+ writeFile(rscPath, Buffer.concat(chunks))
193
+ .then(() => {
194
+ callback();
195
+ resolve();
196
+ })
197
+ .catch(error => {
198
+ console.error('RSC write error:', error);
199
+ callback(error as Error);
200
+ reject(error);
201
+ });
202
+ } catch (error) {
203
+ callback(error as Error);
204
+ reject(error);
205
+ }
206
+ }
207
+ });
208
+
209
+ rscResult.stream.pipe(rscTransform);
210
+ }),
211
+
212
+ // Send HTML stream to worker
213
+ new Promise<void>((resolve, reject) => {
214
+ const htmlTransform = new Transform({
215
+ transform(chunk, _encoding, callback) {
216
+ try {
217
+ options.worker.postMessage({
218
+ type: "RSC_CHUNK",
219
+ id: route,
220
+ chunk: chunk.toString(),
221
+ moduleRootPath: join(root, options.pluginOptions.build.outDir, options.pluginOptions.build.client),
222
+ moduleBaseURL: options.moduleBaseURL,
223
+ htmlOutputPath: join(options.pluginOptions.build.outDir, options.pluginOptions.build.client, route, 'index.html'),
224
+ pipableStreamOptions: options.pipableStreamOptions,
225
+ });
226
+ callback(null, chunk);
227
+ } catch (error) {
228
+ callback(error as Error);
229
+ }
230
+ },
231
+ flush(callback) {
232
+ options.worker.postMessage({
233
+ type: "RSC_END",
234
+ id: route,
235
+ });
236
+ callback();
237
+ resolve();
238
+ }
239
+ });
240
+
241
+ htmlResult.stream.pipe(htmlTransform);
242
+ })
243
+ ]);
256
244
  }
257
- transforms.clear();
258
- writePromises.clear();
259
245
 
260
- options.worker.postMessage({
261
- type: "SHUTDOWN",
262
- });
246
+ await allRoutesComplete;
247
+
248
+ } catch (error) {
249
+ console.error('Render error:', error);
250
+ throw error;
263
251
  }
264
252
 
265
- return {
266
- failedRoutes,
267
- completedRoutes,
268
- };
253
+ return { failedRoutes, completedRoutes };
269
254
  }
@@ -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
+ }