vite-plugin-react-server 1.1.13 → 1.1.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 (159) hide show
  1. package/dist/package.json +3 -1
  2. package/dist/plugin/config/defaults.d.ts +2 -2
  3. package/dist/plugin/config/defaults.d.ts.map +1 -1
  4. package/dist/plugin/config/defaults.js +2 -2
  5. package/dist/plugin/config/defaults.js.map +1 -1
  6. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  7. package/dist/plugin/config/resolveOptions.js +98 -61
  8. package/dist/plugin/config/resolveOptions.js.map +1 -1
  9. package/dist/plugin/error/toError.d.ts.map +1 -1
  10. package/dist/plugin/error/toError.js +0 -1
  11. package/dist/plugin/error/toError.js.map +1 -1
  12. package/dist/plugin/helpers/collectManifestCss.d.ts +1 -2
  13. package/dist/plugin/helpers/collectManifestCss.d.ts.map +1 -1
  14. package/dist/plugin/helpers/collectManifestCss.js +3 -5
  15. package/dist/plugin/helpers/collectManifestCss.js.map +1 -1
  16. package/dist/plugin/helpers/collectViteModuleGraphCss.d.ts +1 -1
  17. package/dist/plugin/helpers/collectViteModuleGraphCss.d.ts.map +1 -1
  18. package/dist/plugin/helpers/collectViteModuleGraphCss.js +6 -2
  19. package/dist/plugin/helpers/collectViteModuleGraphCss.js.map +1 -1
  20. package/dist/plugin/helpers/createCssProps.d.ts +1 -1
  21. package/dist/plugin/helpers/createCssProps.d.ts.map +1 -1
  22. package/dist/plugin/helpers/createCssProps.js +11 -32
  23. package/dist/plugin/helpers/createCssProps.js.map +1 -1
  24. package/dist/plugin/helpers/createRscStream.d.ts.map +1 -1
  25. package/dist/plugin/helpers/createRscStream.js +1 -0
  26. package/dist/plugin/helpers/createRscStream.js.map +1 -1
  27. package/dist/plugin/loader/createDefaultLoader.d.ts.map +1 -1
  28. package/dist/plugin/loader/createDefaultLoader.js +68 -4
  29. package/dist/plugin/loader/css-loader.development.d.ts +2 -15
  30. package/dist/plugin/loader/css-loader.development.d.ts.map +1 -1
  31. package/dist/plugin/loader/css-loader.development.js +16 -15
  32. package/dist/plugin/loader/css-loader.development.js.map +1 -1
  33. package/dist/plugin/loader/css-loader.production.d.ts +1 -1
  34. package/dist/plugin/loader/css-loader.production.d.ts.map +1 -1
  35. package/dist/plugin/loader/css-loader.production.js +1 -1
  36. package/dist/plugin/loader/css-loader.production.js.map +1 -1
  37. package/dist/plugin/loader/env-loader.development.d.ts +1 -0
  38. package/dist/plugin/loader/env-loader.development.d.ts.map +1 -1
  39. package/dist/plugin/loader/env-loader.development.js +17 -9
  40. package/dist/plugin/loader/handleExports.d.ts +1 -0
  41. package/dist/plugin/loader/handleExports.d.ts.map +1 -1
  42. package/dist/plugin/loader/handleExports.js +27 -8
  43. package/dist/plugin/loader/handleExports.js.map +1 -1
  44. package/dist/plugin/loader/react-loader.server.d.ts +2 -2
  45. package/dist/plugin/loader/react-loader.server.d.ts.map +1 -1
  46. package/dist/plugin/loader/react-loader.server.js +88 -26
  47. package/dist/plugin/loader/transformModuleIfNeeded.d.ts.map +1 -1
  48. package/dist/plugin/loader/transformModuleIfNeeded.js +1 -1
  49. package/dist/plugin/loader/transformModuleIfNeeded.js.map +1 -1
  50. package/dist/plugin/loader/transformModuleWithPreservedFunctions.d.ts.map +1 -1
  51. package/dist/plugin/loader/transformModuleWithPreservedFunctions.js +86 -13
  52. package/dist/plugin/loader/transformModuleWithPreservedFunctions.js.map +1 -1
  53. package/dist/plugin/plugin.client.d.ts.map +1 -1
  54. package/dist/plugin/plugin.client.js +0 -1
  55. package/dist/plugin/plugin.client.js.map +1 -1
  56. package/dist/plugin/react-client/configureWorkerRequestHandler.d.ts.map +1 -1
  57. package/dist/plugin/react-client/configureWorkerRequestHandler.js +85 -6
  58. package/dist/plugin/react-client/configureWorkerRequestHandler.js.map +1 -1
  59. package/dist/plugin/react-client/createMessageHandlers.d.ts.map +1 -1
  60. package/dist/plugin/react-client/createMessageHandlers.js +3 -0
  61. package/dist/plugin/react-client/createMessageHandlers.js.map +1 -1
  62. package/dist/plugin/react-client/createWorkerStream.d.ts +2 -2
  63. package/dist/plugin/react-client/createWorkerStream.d.ts.map +1 -1
  64. package/dist/plugin/react-client/createWorkerStream.js +13 -2
  65. package/dist/plugin/react-client/createWorkerStream.js.map +1 -1
  66. package/dist/plugin/react-client/handleWorkerRscStream.d.ts.map +1 -1
  67. package/dist/plugin/react-client/handleWorkerRscStream.js +10 -3
  68. package/dist/plugin/react-client/handleWorkerRscStream.js.map +1 -1
  69. package/dist/plugin/react-client/restartWorker.d.ts.map +1 -1
  70. package/dist/plugin/react-client/restartWorker.js +2 -1
  71. package/dist/plugin/react-client/restartWorker.js.map +1 -1
  72. package/dist/plugin/react-server/configureReactServer.d.ts.map +1 -1
  73. package/dist/plugin/react-server/configureReactServer.js +1 -2
  74. package/dist/plugin/react-server/configureReactServer.js.map +1 -1
  75. package/dist/plugin/react-server/handleServerAction.d.ts.map +1 -1
  76. package/dist/plugin/react-server/handleServerAction.js +0 -16
  77. package/dist/plugin/react-server/handleServerAction.js.map +1 -1
  78. package/dist/plugin/react-static/createBuildLoader.d.ts.map +1 -0
  79. package/dist/plugin/react-static/createBuildLoader.js.map +1 -0
  80. package/dist/plugin/react-static/plugin.d.ts.map +1 -1
  81. package/dist/plugin/react-static/plugin.js +9 -12
  82. package/dist/plugin/react-static/plugin.js.map +1 -1
  83. package/dist/plugin/react-static/temporaryReferences.d.ts.map +1 -0
  84. package/dist/plugin/react-static/temporaryReferences.js.map +1 -0
  85. package/dist/plugin/transformer/plugin.server.js +2 -2
  86. package/dist/plugin/transformer/plugin.server.js.map +1 -1
  87. package/dist/plugin/types.d.ts +14 -3
  88. package/dist/plugin/types.d.ts.map +1 -1
  89. package/dist/plugin/worker/rsc/handleRender.d.ts.map +1 -1
  90. package/dist/plugin/worker/rsc/handleRender.js +1 -0
  91. package/dist/plugin/worker/rsc/handleRender.js.map +1 -1
  92. package/dist/plugin/worker/rsc/handlers.d.ts +3 -0
  93. package/dist/plugin/worker/rsc/handlers.d.ts.map +1 -0
  94. package/dist/plugin/worker/rsc/handlers.js +223 -0
  95. package/dist/plugin/worker/rsc/handlers.js.map +1 -0
  96. package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -1
  97. package/dist/plugin/worker/rsc/messageHandler.js +5 -110
  98. package/dist/plugin/worker/rsc/messageHandler.js.map +1 -1
  99. package/dist/plugin/worker/rsc/rsc-worker.development.js +13 -16
  100. package/dist/plugin/worker/rsc/rsc-worker.development.js.map +1 -1
  101. package/dist/plugin/worker/rsc/state.d.ts +1 -2
  102. package/dist/plugin/worker/rsc/state.d.ts.map +1 -1
  103. package/dist/plugin/worker/rsc/state.js +1 -2
  104. package/dist/plugin/worker/rsc/state.js.map +1 -1
  105. package/dist/plugin/worker/rsc/userOptions.d.ts +2 -0
  106. package/dist/plugin/worker/rsc/userOptions.d.ts.map +1 -0
  107. package/dist/plugin/worker/rsc/userOptions.js +17 -0
  108. package/dist/plugin/worker/rsc/userOptions.js.map +1 -0
  109. package/dist/plugin/worker/types.d.ts +2 -1
  110. package/dist/plugin/worker/types.d.ts.map +1 -1
  111. package/dist/tsconfig.tsbuildinfo +1 -1
  112. package/package.json +5 -1
  113. package/plugin/config/defaults.tsx +5 -2
  114. package/plugin/config/resolveOptions.ts +101 -67
  115. package/plugin/error/toError.ts +0 -2
  116. package/plugin/helpers/collectManifestCss.ts +2 -6
  117. package/plugin/helpers/collectViteModuleGraphCss.ts +6 -0
  118. package/plugin/helpers/createCssProps.tsx +17 -46
  119. package/plugin/helpers/createRscStream.tsx +1 -0
  120. package/plugin/loader/createDefaultLoader.ts +80 -4
  121. package/plugin/loader/css-loader.development.ts +17 -34
  122. package/plugin/loader/css-loader.production.ts +2 -4
  123. package/plugin/loader/env-loader.development.ts +38 -15
  124. package/plugin/loader/handleExports.ts +36 -13
  125. package/plugin/loader/react-loader.server.ts +110 -32
  126. package/plugin/loader/transformModuleIfNeeded.ts +2 -2
  127. package/plugin/loader/transformModuleWithPreservedFunctions.ts +128 -21
  128. package/plugin/plugin.client.ts +0 -2
  129. package/plugin/react-client/configureWorkerRequestHandler.ts +107 -4
  130. package/plugin/react-client/createMessageHandlers.ts +3 -0
  131. package/plugin/react-client/createWorkerStream.ts +15 -1
  132. package/plugin/react-client/handleWorkerRscStream.ts +12 -3
  133. package/plugin/react-client/restartWorker.ts +1 -0
  134. package/plugin/react-server/configureReactServer.ts +1 -2
  135. package/plugin/react-server/handleServerAction.ts +1 -19
  136. package/plugin/react-static/plugin.ts +9 -12
  137. package/plugin/transformer/plugin.server.ts +2 -2
  138. package/plugin/types.ts +25 -2
  139. package/plugin/worker/rsc/handleRender.ts +1 -0
  140. package/plugin/worker/rsc/handlers.ts +243 -0
  141. package/plugin/worker/rsc/messageHandler.tsx +4 -118
  142. package/plugin/worker/rsc/rsc-worker.development.ts +17 -20
  143. package/plugin/worker/rsc/state.ts +2 -6
  144. package/plugin/worker/rsc/userOptions.ts +8 -0
  145. package/plugin/worker/types.ts +2 -0
  146. package/dist/plugin/loader/createBuildLoader.d.ts.map +0 -1
  147. package/dist/plugin/loader/createBuildLoader.js.map +0 -1
  148. package/dist/plugin/loader/plugin.d.ts +0 -22
  149. package/dist/plugin/loader/plugin.d.ts.map +0 -1
  150. package/dist/plugin/loader/plugin.js +0 -27
  151. package/dist/plugin/loader/temporaryReferences.d.ts.map +0 -1
  152. package/dist/plugin/loader/temporaryReferences.js.map +0 -1
  153. package/plugin/loader/plugin.ts +0 -33
  154. /package/dist/plugin/{loader → react-static}/createBuildLoader.d.ts +0 -0
  155. /package/dist/plugin/{loader → react-static}/createBuildLoader.js +0 -0
  156. /package/dist/plugin/{loader → react-static}/temporaryReferences.d.ts +0 -0
  157. /package/dist/plugin/{loader → react-static}/temporaryReferences.js +0 -0
  158. /package/plugin/{loader → react-static}/createBuildLoader.ts +0 -0
  159. /package/plugin/{loader → react-static}/temporaryReferences.ts +0 -0
@@ -18,6 +18,7 @@
18
18
  */
19
19
  import { handleExports } from "./handleExports.js";
20
20
  import type { Program } from "./types.js";
21
+ import createMappingsSerializer from "webpack-sources/lib/helpers/createMappingsSerializer.js";
21
22
 
22
23
  export interface TransformOptions {
23
24
  id: string;
@@ -56,16 +57,53 @@ export function transformModuleWithPreservedFunctions(
56
57
  moduleId: string,
57
58
  program: Program,
58
59
  isServerFunction: boolean | RegExpMatchArray | null,
59
- isClientComponent: boolean | RegExpMatchArray | null,
60
+ isClientComponent: boolean | RegExpMatchArray | null
60
61
  ): string {
62
+ // Find and remove directives using AST
63
+ let sourceWithoutDirective = source;
64
+ let directiveEnd = 0;
65
+
66
+ // Only look at top-level directives
67
+ for (const node of program.body) {
68
+ if (node.type !== "ExpressionStatement") {
69
+ break;
70
+ }
71
+
72
+ let directive: string | null = null;
73
+ if ("directive" in node && typeof node.directive === "string") {
74
+ directive = node.directive;
75
+ } else if (
76
+ node.expression.type === "Literal" &&
77
+ typeof node.expression.value === "string" &&
78
+ (node.expression.value === "use server" || node.expression.value === "use client")
79
+ ) {
80
+ directive = node.expression.value;
81
+ }
82
+
83
+ if (directive && "start" in node && "end" in node) {
84
+ directiveEnd = node.end;
85
+ }
86
+ }
87
+
88
+ // Remove the directive and any whitespace after it
89
+ if (directiveEnd > 0) {
90
+ sourceWithoutDirective = source.slice(directiveEnd).trim();
91
+ }
61
92
 
62
93
  // Get export names and create module ID literal
63
- const { exportNames, exports } = handleExports(source, program, isServerFunction, isClientComponent);
94
+ const { exportNames, exports } = handleExports(
95
+ sourceWithoutDirective,
96
+ program,
97
+ isServerFunction,
98
+ isClientComponent
99
+ );
64
100
  const moduleIdLiteral = JSON.stringify(moduleId);
65
101
 
66
102
  // For server modules in server environment, register server references
67
- if (isServerFunction) {
68
- const imports = ['import { registerServerReference } from "react-server-dom-esm/server.node";'];
103
+ if (Boolean(isServerFunction)) {
104
+ const imports = [
105
+ 'import { registerServerReference } from "react-server-dom-esm/server.node";',
106
+ ];
69
107
  const registrations: string[] = [];
70
108
 
71
109
  // Register each export
@@ -73,47 +111,116 @@ export function transformModuleWithPreservedFunctions(
73
111
  const exportInfo = exports.get(name);
74
112
  if (exportInfo) {
75
113
  // For default exports, use the localName if available
76
- const exportName = name === "default" && exportInfo.localName ? exportInfo.localName : name;
114
+ const exportName =
115
+ name === "default" && exportInfo.localName
116
+ ? exportInfo.localName
117
+ : name;
77
118
  // Register all exports in server modules
78
119
  registrations.push(
79
- `registerServerReference(${exportName}, ${moduleIdLiteral}, ${JSON.stringify(name)});`
120
+ `registerServerReference(${exportName}, ${moduleIdLiteral}, ${JSON.stringify(
121
+ name
122
+ )});`
80
123
  );
81
124
  }
82
125
  }
83
126
 
84
127
  // Create new source with registrations
85
128
  // First, add the imports at the top
86
- const newSource = [...imports, source].join("\n\n");
87
- // Then, add the registrations at the end
88
- const finalSource = newSource + "\n\n" + registrations.join("\n");
129
+ const newSource = [...imports, sourceWithoutDirective, ...registrations].join("\n\n");
89
130
 
90
- return finalSource;
91
- }
131
+ // Handle source maps
132
+ let mappings = "";
133
+ const createMapping = createMappingsSerializer();
134
+ let generatedLine = 1;
135
+
136
+ // Map the import line to the first line of the original source
137
+ createMapping(generatedLine, 0, 0, 0, 0, -1);
138
+ generatedLine++;
139
+
140
+ // Map the registration lines to the first line of the original source
141
+ for (let i = 0; i < registrations.length; i++) {
142
+ createMapping(generatedLine, 0, 0, 1, 0, -1);
143
+ generatedLine++;
144
+ }
92
145
 
93
- // For client modules in server environment, register client references
94
- if (isClientComponent) {
95
- const imports = ['import { registerClientReference } from "react-server-dom-esm/server.node";'];
146
+ // Map the original source lines, skipping the directive line
147
+ const sourceLines = source.split("\n");
148
+ for (let i = 0; i < sourceLines.length; i++) {
149
+ createMapping(generatedLine, 0, 0, i + 1, 0, -1); // +1 because we skip directive line
150
+ generatedLine++;
151
+ }
152
+
153
+ // Add source map to the output with original source content
154
+ const sourceMap = {
155
+ version: 3,
156
+ file: moduleId,
157
+ sources: [moduleId],
158
+ sourcesContent: [newSource], // Use transformed source content
159
+ mappings,
160
+ sourceRoot: "",
161
+ names: [],
162
+ };
163
+
164
+ return (
165
+ newSource +
166
+ "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," +
167
+ Buffer.from(JSON.stringify(sourceMap)).toString("base64")
168
+ );
169
+ // end of server module
170
+ }
171
+ if (!!isClientComponent) {
172
+ // For client modules in server environment, register client references
173
+ const imports = [
174
+ 'import { registerClientReference } from "react-server-dom-esm/server.node";',
175
+ ];
96
176
  const declarations: string[] = [];
97
177
 
98
178
  for (const name of exportNames) {
99
179
  const errorMessage = createClientReferenceError(name);
100
180
  if (name === "default") {
101
181
  declarations.push(`export default registerClientReference(function() {
102
- throw new Error("${errorMessage}");
182
+ throw new Error("${errorMessage}");
103
183
  }, ${moduleIdLiteral}, "default");`);
104
184
  } else {
105
185
  declarations.push(`export const ${name} = registerClientReference(function() {
106
- throw new Error("${errorMessage}");
186
+ throw new Error("${errorMessage}");
107
187
  }, ${moduleIdLiteral}, ${JSON.stringify(name)});`);
108
188
  }
109
189
  }
110
-
111
190
  // Create new source with declarations
112
191
  const newSource = [...imports, ...declarations].join("\n\n");
113
192
 
114
- return newSource;
115
- }
193
+ // Handle source maps for client modules
194
+ let mappings = "";
195
+ const createMapping = createMappingsSerializer();
196
+ let generatedLine = 1;
116
197
 
117
- // For other cases, return original source
118
- return source;
198
+ // Map the import line to the first line of the original source
199
+ createMapping(generatedLine, 0, 0, 0, 0, -1);
200
+ generatedLine++;
201
+
202
+ // Map the declaration lines to the first line of the original source
203
+ for (let i = 0; i < declarations.length; i++) {
204
+ createMapping(generatedLine, 0, 0, 1, 0, -1);
205
+ generatedLine++;
206
+ }
207
+
208
+ // Add source map to the output with original source content
209
+ const sourceMap = {
210
+ version: 3,
211
+ file: moduleId,
212
+ sources: [moduleId],
213
+ sourcesContent: [newSource], // Use transformed source content
214
+ mappings,
215
+ sourceRoot: "",
216
+ names: [],
217
+ };
218
+
219
+ return (
220
+ newSource +
221
+ "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," +
222
+ Buffer.from(JSON.stringify(sourceMap)).toString("base64")
223
+ );
224
+ }
225
+ throw new Error("Invalid module type");
119
226
  }
@@ -6,7 +6,6 @@ import type {
6
6
  } from "../types.js";
7
7
  import { reactClientPlugin } from "./react-client/plugin.js";
8
8
  import { envPlugin } from "./env/plugin.js";
9
- //import { reactTransformPlugin } from "./transformer/plugin.client.js";
10
9
 
11
10
  export function vitePluginReactServer<
12
11
  T extends PagePropOpt = PagePropOpt,
@@ -14,7 +13,6 @@ export function vitePluginReactServer<
14
13
  >(options = {} as StreamPluginOptions<T, InlineCSS>): import("vite").Plugin[] {
15
14
  return [
16
15
  envPlugin(),
17
- //reactTransformPlugin(options),
18
16
  reactClientPlugin(options),
19
17
  reactPreservePlugin(options),
20
18
  ];
@@ -18,6 +18,7 @@ import { getRouteFiles } from "../helpers/getRouteFiles.js";
18
18
  import type { RscWorkerInputMessage } from "../worker/types.js";
19
19
  import { Readable } from "node:stream";
20
20
  import type { ReadableStream } from "node:stream/web";
21
+ import { PassThrough } from "node:stream";
21
22
 
22
23
  /**
23
24
  * Configures the worker request handler.
@@ -51,6 +52,9 @@ export async function configureWorkerRequestHandler<
51
52
  moduleBaseURL: server.config.base,
52
53
  moduleBasePath: server.config.base,
53
54
  projectRoot: server.config.root,
55
+ moduleID: (id: string) => {
56
+ return id
57
+ }
54
58
  });
55
59
 
56
60
  // Start the worker
@@ -85,6 +89,109 @@ export async function configureWorkerRequestHandler<
85
89
 
86
90
  const info = requestInfo(req, handlerOptions, "", server.config.logger);
87
91
 
92
+ // Serialize user options for worker
93
+ const serializedUserOptions = serializedOptions<T, InlineCSS>(
94
+ handlerOptions,
95
+ autoDiscoveredFiles
96
+ );
97
+
98
+ // Handle server action requests
99
+ if (info.isServerActionRequest) {
100
+ try {
101
+ // Read request body
102
+ const chunks: Buffer[] = [];
103
+ for await (const chunk of req) {
104
+ chunks.push(chunk);
105
+ }
106
+ const body = Buffer.concat(chunks).toString();
107
+ const parsed = JSON.parse(body);
108
+
109
+ // Get action ID and args from the request body
110
+ let id: string;
111
+ let args: unknown[];
112
+ if (Array.isArray(parsed)) {
113
+ // Format 1: Direct args array
114
+ args = parsed;
115
+ id = req.url?.split("?")[0] ?? "";
116
+ } else if (parsed && typeof parsed === "object" && "id" in parsed) {
117
+ // Format 2: Object with id and args
118
+ id = parsed.id;
119
+ args = parsed.args ?? [];
120
+ } else {
121
+ throw new Error("Invalid server action request format");
122
+ }
123
+
124
+ // Set up response headers for streaming
125
+ res.setHeader("Content-Type", "text/x-component; charset=utf-8");
126
+ res.setHeader("Transfer-Encoding", "chunked");
127
+ res.setHeader("Connection", "keep-alive");
128
+
129
+ if (!currentWorker) {
130
+ currentWorker = await restartWorker({
131
+ server,
132
+ autoDiscoveredFiles,
133
+ userOptions: serializedUserOptions,
134
+ hmrChannel,
135
+ });
136
+ }
137
+
138
+ // Send server action request to worker
139
+ currentWorker!.postMessage({
140
+ type: "SERVER_ACTION",
141
+ id,
142
+ args,
143
+ } satisfies RscWorkerInputMessage);
144
+
145
+ // Create a pass-through stream for the response
146
+ const passThrough = new PassThrough();
147
+ passThrough.pipe(res);
148
+
149
+ // Handle worker messages
150
+ const messageHandler = (message: any) => {
151
+ if (message.type === "RSC_CHUNK") {
152
+ passThrough.write(message.chunk);
153
+ } else if (message.type === "RSC_END") {
154
+ passThrough.end();
155
+ currentWorker!.removeListener("message", messageHandler);
156
+ } else if (message.type === "ERROR") {
157
+ passThrough.end();
158
+ currentWorker!.removeListener("message", messageHandler);
159
+ server.config.logger.error(message.error.message + (message.error.stack ?? ""), {
160
+ error: message.error,
161
+ });
162
+ }
163
+ };
164
+
165
+ currentWorker!.on("message", messageHandler);
166
+
167
+ // Handle errors
168
+ passThrough.on("error", (error) => {
169
+ server.config.logger.error(error.message + (error.stack ?? ""), {
170
+ error,
171
+ });
172
+ res.end();
173
+ });
174
+
175
+ return;
176
+ } catch (error) {
177
+ if (error instanceof Error) {
178
+ server.config.logger.error(error.message + (error.stack ?? ""), {
179
+ error,
180
+ });
181
+ }
182
+ res.statusCode = 500;
183
+ res.end(JSON.stringify({
184
+ type: "server-action-response",
185
+ returnValue: {
186
+ success: false,
187
+ error: error instanceof Error ? error.message : String(error)
188
+ }
189
+ }));
190
+ return;
191
+ }
192
+ }
193
+
194
+ // Handle RSC requests
88
195
  if (!info.isRscRequest) {
89
196
  return next();
90
197
  }
@@ -106,10 +213,6 @@ export async function configureWorkerRequestHandler<
106
213
  res.setHeader("Transfer-Encoding", "chunked");
107
214
  res.setHeader("Connection", "keep-alive");
108
215
 
109
- const serializedUserOptions = serializedOptions<T, InlineCSS>(
110
- handlerOptions,
111
- autoDiscoveredFiles
112
- );
113
216
  const userOnMetrics =
114
217
  typeof onMetrics === "function"
115
218
  ? (metrics: StreamMetrics) => {
@@ -50,6 +50,9 @@ export function createMessageHandler({
50
50
  case "SERVER_MODULE":
51
51
  handlers.onServerModule?.(message.id, message.url, message.source);
52
52
  break;
53
+ case "CSS_FILE":
54
+ handlers.onCssFile?.(message.id, message.content);
55
+ break;
53
56
  default:
54
57
  logger.warn(`Unknown worker output message type: ${(message as { type: string }).type}`);
55
58
  }
@@ -32,6 +32,7 @@ export async function* createWorkerStream({
32
32
  onEnd,
33
33
  onServerAction,
34
34
  onServerActionResponse,
35
+ onCssFile,
35
36
  },
36
37
  verbose = false,
37
38
  }: {
@@ -48,6 +49,7 @@ export async function* createWorkerStream({
48
49
  | "onEnd"
49
50
  | "onServerAction"
50
51
  | "onServerActionResponse"
52
+ | "onCssFile"
51
53
  >
52
54
  >;
53
55
  verbose?: boolean;
@@ -114,6 +116,12 @@ export async function* createWorkerStream({
114
116
  onHmrUpdate(id, routes);
115
117
  }
116
118
  },
119
+ onCssFile: (id: string, code: string) => {
120
+ if (verbose) logger.info(`[react-client] received css file ${id}`);
121
+ if (typeof onCssFile === "function") {
122
+ onCssFile(id, code);
123
+ }
124
+ },
117
125
  onServerAction: (id: string, args: unknown[]) => {
118
126
  if (verbose) logger.info(`[react-client] received server action ${id}`);
119
127
  if (typeof onServerAction === "function") {
@@ -124,7 +132,13 @@ export async function* createWorkerStream({
124
132
  if (verbose)
125
133
  logger.info(`[react-client] received server action response ${id}`);
126
134
  if (typeof onServerActionResponse === "function") {
127
- onServerActionResponse(id, result, error);
135
+ const response = {
136
+ type: "server-action-response",
137
+ returnValue: error
138
+ ? { success: false, error }
139
+ : result
140
+ };
141
+ onServerActionResponse(id, response);
128
142
  }
129
143
  },
130
144
  };
@@ -37,12 +37,21 @@ export function handleWorkerRscStream({
37
37
  handlers: {
38
38
  ...handlers,
39
39
  onServerAction: (id: string, args: unknown[]) => {
40
- if (verbose) logger.info(`[react-client] Received server action ${id}`);
40
+ if (verbose) logger.info(`[react-client] Forwarding server action ${id} to worker`);
41
41
  handlers.onServerAction?.(id, args);
42
42
  },
43
43
  onServerActionResponse: (id: string, result?: unknown, error?: string) => {
44
- if (verbose) logger.info(`[react-client] Received server action response ${id}`);
45
- handlers.onServerActionResponse?.(id, result, error);
44
+ if (verbose) logger.info(`[react-client] Forwarding server action response ${id} from worker`);
45
+ if (typeof handlers.onServerActionResponse === "function") {
46
+ // Ensure consistent response format
47
+ const response = {
48
+ type: "server-action-response",
49
+ returnValue: error
50
+ ? { success: false, error }
51
+ : result // Direct result, no success/data wrapper
52
+ };
53
+ handlers.onServerActionResponse(id, response);
54
+ }
46
55
  }
47
56
  },
48
57
  verbose
@@ -62,6 +62,7 @@ export async function restartWorker({
62
62
  hmrPort: workerHmrChannel.port2,
63
63
  resolvedConfig: serializedDevServerConfig(server.config),
64
64
  userOptions: serializedOptions(userOptions, autoDiscoveredFiles),
65
+ serverActions: autoDiscoveredFiles.serverActions,
65
66
  },
66
67
  transferList: [workerHmrChannel.port2],
67
68
  });
@@ -35,13 +35,12 @@ export async function configureReactServer<
35
35
  Html: _UserHtmlComponent,
36
36
  onEvent,
37
37
  // remove these
38
- moduleBaseURL: _moduleBaseURL,
39
- projectRoot: _projectRoot,
40
38
  ...handlerUserOptions
41
39
  } = _userOptions;
42
40
  const handlerOptions = {
43
41
  ...handlerUserOptions,
44
42
  moduleBaseURL: server.config.base,
43
+ moduleBasePath: server.config.base,
45
44
  projectRoot: server.config.root,
46
45
  Html: React.Fragment,
47
46
  onEvent: createEventHandler(onEvent),
@@ -140,7 +140,7 @@ export async function handleServerAction<
140
140
  const { pipe } = ReactDOMServer.renderToPipeableStream(
141
141
  {
142
142
  type: "server-action-response",
143
- returnValue: result,
143
+ returnValue: result
144
144
  },
145
145
  handlerOptions.moduleBasePath,
146
146
  {
@@ -155,23 +155,5 @@ export async function handleServerAction<
155
155
  pipe(res);
156
156
  } catch (error) {
157
157
  logError(error, server.config.logger);
158
- res.statusCode = 500;
159
- res.setHeader("Content-Type", "text/x-component; charset=utf-8");
160
-
161
- const { pipe } = ReactDOMServer.renderToPipeableStream(
162
- {
163
- type: "server-action-response",
164
- error: toError(error).message,
165
- },
166
- handlerOptions.moduleBasePath,
167
- {
168
- onError(error: Error) {
169
- logError(error, server.config.logger);
170
- res.end();
171
- },
172
- }
173
- );
174
-
175
- pipe(res);
176
158
  }
177
159
  }
@@ -24,7 +24,7 @@ import {
24
24
  } from "vite";
25
25
  import { resolveOptions } from "../config/resolveOptions.js";
26
26
  import { resolveUserConfig } from "../config/resolveUserConfig.js";
27
- import { createBuildLoader } from "../loader/createBuildLoader.js";
27
+ import { createBuildLoader } from "./createBuildLoader.js";
28
28
  import type {
29
29
  BuildTiming,
30
30
  ReactStreamPluginMeta,
@@ -204,8 +204,7 @@ export function reactStaticPlugin<
204
204
  // First collect global styles from index.html
205
205
  const globalCssInputs = collectManifestCss(
206
206
  autoDiscoveredFiles?.staticManifest ?? {},
207
- "index.html",
208
- userOptions
207
+ "index.html"
209
208
  );
210
209
 
211
210
  const globalCss: Map<string, CssContent<InlineCSS>> = new Map();
@@ -229,8 +228,7 @@ export function reactStaticPlugin<
229
228
  );
230
229
  const cssInputs = collectManifestCss(
231
230
  transformedServerManifest,
232
- props ? [page, props] : page,
233
- userOptions
231
+ props ? [page, props] : page
234
232
  );
235
233
 
236
234
  // Create a map for this page's CSS files
@@ -247,16 +245,16 @@ export function reactStaticPlugin<
247
245
  userOptions.projectRoot,
248
246
  userOptions.build.outDir,
249
247
  userOptions.build.static,
250
- key + ".css"
248
+ key
251
249
  ),
252
250
  "utf-8"
253
251
  ) ?? ""
254
252
  }
255
253
  if (cssContent) {
256
254
  globalCss.set(
257
- value,
255
+ key,
258
256
  createCssProps<T, InlineCSS>({
259
- id: value,
257
+ id: key,
260
258
  code: cssContent,
261
259
  userOptions: userOptions,
262
260
  })
@@ -266,7 +264,7 @@ export function reactStaticPlugin<
266
264
  }
267
265
 
268
266
  // Add page-specific styles
269
- for (const [, value] of Object.entries(cssInputs)) {
267
+ for (const [key, value] of Object.entries(cssInputs)) {
270
268
  try {
271
269
  const { default: cssContent } = await buildLoader(
272
270
  value + "?inline"
@@ -276,11 +274,10 @@ export function reactStaticPlugin<
276
274
  }
277
275
  if (cssContent) {
278
276
  // Ensure the CSS file path is properly resolved
279
- const cssPath = value.startsWith("/") ? value.slice(1) : value;
280
277
  pageCssMap.set(
281
- cssPath,
278
+ key,
282
279
  createCssProps({
283
- id: cssPath,
280
+ id: key,
284
281
  code: cssContent,
285
282
  userOptions: userOptions,
286
283
  })
@@ -128,8 +128,8 @@ export function reactTransformPlugin<
128
128
  const transformed = transformModuleIfNeeded(
129
129
  code,
130
130
  finalID,
131
- userOptions.autoDiscover.isServerFunction(code),
132
- userOptions.autoDiscover.isClientComponent(code),
131
+ userOptions.autoDiscover.isServerFunctionCode(code),
132
+ userOptions.autoDiscover.isClientComponentCode(code),
133
133
  true
134
134
  );
135
135
  if (userOptions.verbose)
package/plugin/types.ts CHANGED
@@ -138,6 +138,12 @@ export type SerializedUserConfig = Extract<
138
138
  ResolvedUserConfig,
139
139
  SerializableRecord
140
140
  >;
141
+
142
+ export type SerializedUserOptions = Extract<
143
+ ResolvedUserOptions,
144
+ SerializableRecord
145
+ >;
146
+
141
147
  // Client plugin options
142
148
  export interface StreamPluginOptionsClient {
143
149
  outDir?: string;
@@ -197,6 +203,11 @@ export type ResolvedUserOptions<
197
203
  moduleExtension: RegExp;
198
204
  serverDirective: RegExp;
199
205
  clientDirective: RegExp;
206
+ cssExtension: string;
207
+ jsonExtension: string;
208
+ htmlExtension: string;
209
+ rscExtension: string;
210
+ jsExtension: string;
200
211
  modulePattern: (path: string) => boolean;
201
212
  cssPattern: (path: string) => boolean;
202
213
  jsonPattern: (path: string) => boolean;
@@ -211,8 +222,8 @@ export type ResolvedUserOptions<
211
222
  nodeOnly: (path: string) => boolean;
212
223
  dotFiles: (path: string) => boolean;
213
224
  virtualPattern: (path: string) => boolean;
214
- isServerFunction: (code: string) => boolean;
215
- isClientComponent: (code: string) => boolean;
225
+ isServerFunctionCode: (code: string) => boolean;
226
+ isClientComponentCode: (code: string) => boolean;
216
227
  };
217
228
  };
218
229
 
@@ -446,6 +457,16 @@ export interface StreamPluginOptions<
446
457
  serverDirective?: RegExp;
447
458
  // default: /^"use client"[\s;]*\n?/m
448
459
  clientDirective?: RegExp;
460
+ // css extension
461
+ cssExtension?: string;
462
+ // json extension
463
+ jsonExtension?: string;
464
+ // html extension
465
+ htmlExtension?: string;
466
+ // rsc extension
467
+ rscExtension?: string;
468
+ // .js extension
469
+ jsExtension?: string;
449
470
  // default: /\.(m|c)?(j|t)sx?$/
450
471
  modulePattern?: RegExpOpt;
451
472
  // default: [Pp]age.tsx
@@ -538,6 +559,8 @@ export type CreateHandlerOptions<
538
559
  | "onEvent"
539
560
  | "onMetrics"
540
561
  | "projectRoot"
562
+ | "normalizer"
563
+ | "moduleID"
541
564
  > & {
542
565
  logger: Logger;
543
566
  loader: ModuleLoader;
@@ -47,6 +47,7 @@ export async function handleRender<
47
47
  // Clear the HMR state for this module
48
48
  hmrState.delete(id);
49
49
  // Force a reload by using a unique query parameter
50
+ console.log("LOADING", id);
50
51
  return import(join(projectRoot, id) + `?t=${Date.now()}`);
51
52
  }
52
53
  return import(join(projectRoot, id));