vite-plugin-react-server 1.1.18 → 1.1.20

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 (71) hide show
  1. package/README.md +7 -3
  2. package/dist/package.json +1 -1
  3. package/dist/plugin/config/defaults.d.ts +1 -1
  4. package/dist/plugin/config/defaults.d.ts.map +1 -1
  5. package/dist/plugin/config/defaults.js +2 -2
  6. package/dist/plugin/config/defaults.js.map +1 -1
  7. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  8. package/dist/plugin/config/resolveOptions.js +4 -4
  9. package/dist/plugin/config/resolveOptions.js.map +1 -1
  10. package/dist/plugin/helpers/handleServerAction.d.ts +34 -0
  11. package/dist/plugin/helpers/handleServerAction.d.ts.map +1 -0
  12. package/dist/plugin/helpers/handleServerAction.js +48 -0
  13. package/dist/plugin/helpers/handleServerAction.js.map +1 -0
  14. package/dist/plugin/loader/handleExports.d.ts +16 -10
  15. package/dist/plugin/loader/handleExports.d.ts.map +1 -1
  16. package/dist/plugin/loader/handleExports.js +32 -16
  17. package/dist/plugin/loader/handleExports.js.map +1 -1
  18. package/dist/plugin/loader/transformModuleIfNeeded.d.ts.map +1 -1
  19. package/dist/plugin/loader/transformModuleIfNeeded.js +22 -11
  20. package/dist/plugin/loader/transformModuleIfNeeded.js.map +1 -1
  21. package/dist/plugin/loader/transformModuleWithPreservedFunctions.d.ts +21 -0
  22. package/dist/plugin/loader/transformModuleWithPreservedFunctions.d.ts.map +1 -1
  23. package/dist/plugin/loader/transformModuleWithPreservedFunctions.js +395 -73
  24. package/dist/plugin/loader/transformModuleWithPreservedFunctions.js.map +1 -1
  25. package/dist/plugin/loader/types.d.ts +9 -3
  26. package/dist/plugin/loader/types.d.ts.map +1 -1
  27. package/dist/plugin/react-client/configureWorkerRequestHandler.d.ts.map +1 -1
  28. package/dist/plugin/react-client/configureWorkerRequestHandler.js +12 -69
  29. package/dist/plugin/react-client/configureWorkerRequestHandler.js.map +1 -1
  30. package/dist/plugin/react-client/handleWorkerServerAction.d.ts +12 -0
  31. package/dist/plugin/react-client/handleWorkerServerAction.d.ts.map +1 -0
  32. package/dist/plugin/react-client/handleWorkerServerAction.js +47 -0
  33. package/dist/plugin/react-client/handleWorkerServerAction.js.map +1 -0
  34. package/dist/plugin/react-server/configureReactServer.js.map +1 -1
  35. package/dist/plugin/react-server/handleServerAction.d.ts +1 -1
  36. package/dist/plugin/react-server/handleServerAction.d.ts.map +1 -1
  37. package/dist/plugin/react-server/handleServerAction.js +42 -6
  38. package/dist/plugin/react-server/handleServerAction.js.map +1 -1
  39. package/dist/plugin/react-server/plugin.js +2 -2
  40. package/dist/plugin/react-server/plugin.js.map +1 -1
  41. package/dist/plugin/react-static/plugin.d.ts.map +1 -1
  42. package/dist/plugin/react-static/plugin.js +10 -2
  43. package/dist/plugin/react-static/plugin.js.map +1 -1
  44. package/dist/plugin/source-map/createMappingsSerializer.js +128 -157
  45. package/dist/plugin/source-map/createMappingsSerializer.js.map +1 -0
  46. package/dist/plugin/types.d.ts +5 -7
  47. package/dist/plugin/types.d.ts.map +1 -1
  48. package/dist/plugin/vendor/types.js +1 -0
  49. package/dist/plugin/worker/rsc/handleRender.d.ts.map +1 -1
  50. package/dist/plugin/worker/rsc/handleRender.js +0 -1
  51. package/dist/plugin/worker/rsc/handleRender.js.map +1 -1
  52. package/dist/plugin/worker/rsc/handlers.js.map +1 -1
  53. package/dist/tsconfig.tsbuildinfo +1 -1
  54. package/package.json +1 -1
  55. package/plugin/config/defaults.tsx +5 -2
  56. package/plugin/config/resolveOptions.ts +9 -10
  57. package/plugin/helpers/handleServerAction.ts +79 -0
  58. package/plugin/loader/handleExports.ts +50 -40
  59. package/plugin/loader/transformModuleIfNeeded.ts +50 -15
  60. package/plugin/loader/transformModuleWithPreservedFunctions.ts +494 -127
  61. package/plugin/loader/types.ts +12 -4
  62. package/plugin/react-client/configureWorkerRequestHandler.ts +11 -87
  63. package/plugin/react-client/handleWorkerServerAction.ts +74 -0
  64. package/plugin/react-server/configureReactServer.ts +1 -1
  65. package/plugin/react-server/handleServerAction.ts +49 -12
  66. package/plugin/react-server/plugin.ts +2 -2
  67. package/plugin/react-static/plugin.ts +10 -2
  68. package/plugin/types.ts +6 -7
  69. package/plugin/vendor/types.ts +1 -0
  70. package/plugin/worker/rsc/handleRender.ts +0 -2
  71. package/plugin/worker/rsc/handlers.ts +3 -3
@@ -30,12 +30,80 @@ export interface TransformOptions {
30
30
  program?: Program;
31
31
  }
32
32
 
33
+ // Helper type for mapping info
34
+ interface MappingInfo {
35
+ generatedLine: number;
36
+ originalLine: number;
37
+ originalColumn: number;
38
+ }
39
+
40
+ function generateSourceMap(
41
+ moduleId: string,
42
+ source: string,
43
+ lines: string[],
44
+ mappingInfos: MappingInfo[],
45
+ originalSourceMap?: any
46
+ ) {
47
+ const createMapping = createMappingsSerializer();
48
+ let mappings = '';
49
+
50
+ // Create a mapping for each line
51
+ for (let i = 0; i < lines.length; i++) {
52
+ const info = mappingInfos[i] || { generatedLine: i + 1, originalLine: 1, originalColumn: 0 };
53
+ mappings += createMapping(
54
+ info.generatedLine,
55
+ 0,
56
+ 0, // sourceIndex
57
+ info.originalLine,
58
+ info.originalColumn,
59
+ -1 // nameIndex
60
+ );
61
+ }
62
+
63
+ // Add a final mapping for the end of the file
64
+ mappings += createMapping(
65
+ lines.length + 1,
66
+ 0,
67
+ 0,
68
+ source.split('\n').length,
69
+ 0,
70
+ -1
71
+ );
72
+
73
+ const sourceMap = {
74
+ version: 3,
75
+ file: moduleId,
76
+ sources: originalSourceMap?.sources || [moduleId],
77
+ sourcesContent: originalSourceMap?.sourcesContent || [source],
78
+ mappings,
79
+ sourceRoot: originalSourceMap?.sourceRoot || "",
80
+ names: originalSourceMap?.names || [],
81
+ };
82
+
83
+ return `data:application/json;charset=utf-8;base64,${Buffer.from(JSON.stringify(sourceMap)).toString("base64")}`;
84
+ }
85
+
33
86
  /**
34
- * Creates a client reference error message
87
+ * --- React RSC Directive Handling ---
88
+ *
89
+ * 1. 'use client' at file top:
90
+ * - Pass through code as-is (after removing directive).
91
+ * - Do not transform or register anything.
92
+ * - Required for React client features to work.
93
+ * - See: https://react.dev/reference/rsc/use-client
94
+ *
95
+ * 2. 'use server' at file top:
96
+ * - Register all exported async functions as server actions.
97
+ * - See: https://react.dev/reference/rsc/use-server#caveats
98
+ *
99
+ * 3. 'use server' at function top:
100
+ * - Register only that async function as a server action.
101
+ * - See: https://react.dev/reference/rsc/use-server#caveats
102
+ *
103
+ * 4. No directive:
104
+ * - Treat as a normal shared or server-only module.
105
+ * - No special registration or transformation.
35
106
  */
36
- function createClientReferenceError(name: string): string {
37
- return `Attempted to call ${name}() from the server but ${name} is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.`;
38
- }
39
107
 
40
108
  /**
41
109
  * Transforms a module for RSC boundaries.
@@ -59,37 +127,42 @@ export function transformModuleWithPreservedFunctions(
59
127
  isServerFunction: boolean | RegExpMatchArray | null,
60
128
  isClientComponent: boolean | RegExpMatchArray | null
61
129
  ): 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
- }
130
+ // Check for existing source map
131
+ let sourceMappingURL = null;
132
+ let sourceMappingStart = 0;
133
+ let sourceMappingEnd = 0;
134
+ let sourceMappingLines = 0;
135
+ let originalSourceMap = null;
71
136
 
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
- }
137
+ // Look for source map comment
138
+ const sourceMapMatch = source.match(/\/\/[#@] sourceMappingURL=(.+)$/m);
139
+ if (sourceMapMatch) {
140
+ sourceMappingURL = sourceMapMatch[1];
141
+ sourceMappingStart = sourceMapMatch.index!;
142
+ sourceMappingEnd = sourceMapMatch.index! + sourceMapMatch[0].length;
143
+ sourceMappingLines = sourceMapMatch[0].split('\n').length - 1;
82
144
 
83
- if (directive && "start" in node && "end" in node) {
84
- directiveEnd = node.end;
145
+ // If it's a data URL, parse it
146
+ if (sourceMappingURL.startsWith('data:application/json;base64,')) {
147
+ const base64 = sourceMappingURL.slice('data:application/json;base64,'.length);
148
+ originalSourceMap = JSON.parse(Buffer.from(base64, 'base64').toString());
85
149
  }
86
150
  }
87
151
 
88
- // Remove the directive and any whitespace after it
89
- if (directiveEnd > 0) {
90
- sourceWithoutDirective = source.slice(directiveEnd).trim();
152
+ // Remove the old source map if present
153
+ let sourceWithoutMap = source;
154
+ if (sourceMappingStart > 0) {
155
+ sourceWithoutMap = source.slice(0, sourceMappingStart) + '\n'.repeat(sourceMappingLines) + source.slice(sourceMappingEnd);
91
156
  }
92
157
 
158
+ // Remove directives from source code
159
+ let sourceWithoutDirective = sourceWithoutMap;
160
+ let directiveEnd = 0;
161
+ let hasFileLevelServerDirective = false;
162
+ let hasFileLevelClientDirective = false;
163
+ let hasFunctionLevelClientDirective = false;
164
+ let hasFunctionLevelServerDirective = false;
165
+
93
166
  // Get export names and create module ID literal
94
167
  const { exportNames, exports } = handleExports(
95
168
  sourceWithoutDirective,
@@ -99,14 +172,169 @@ export function transformModuleWithPreservedFunctions(
99
172
  );
100
173
  const moduleIdLiteral = JSON.stringify(moduleId);
101
174
 
102
- // For server modules in server environment, register server references
103
- if (Boolean(isServerFunction)) {
104
- const imports = [
105
- 'import { registerServerReference } from "react-server-dom-esm/server.node";',
106
- ];
107
- const registrations: string[] = [];
175
+ // Helper function to check for directives in a node
176
+ function checkForDirective(node: any): string | null {
177
+ if (node.type === "ExpressionStatement") {
178
+ if ("directive" in node && typeof node.directive === "string") {
179
+ return node.directive;
180
+ } else if (
181
+ node.expression.type === "Literal" &&
182
+ typeof node.expression.value === "string" &&
183
+ (node.expression.value === "use server" || node.expression.value === "use client")
184
+ ) {
185
+ return node.expression.value;
186
+ }
187
+ }
188
+ return null;
189
+ }
190
+
191
+ // Check for file-level and function-level directives
192
+ for (const node of program.body) {
193
+ const directive = checkForDirective(node);
194
+ if (directive) {
195
+ if (directive === "use server") {
196
+ if (node.start === 0) {
197
+ hasFileLevelServerDirective = true;
198
+ } else {
199
+ hasFunctionLevelServerDirective = true;
200
+ }
201
+ }
202
+ if (directive === "use client") {
203
+ if (node.start === 0) {
204
+ hasFileLevelClientDirective = true;
205
+ } else {
206
+ hasFunctionLevelClientDirective = true;
207
+ }
208
+ }
209
+ if ("start" in node && "end" in node) {
210
+ directiveEnd = Math.max(directiveEnd, node.end);
211
+ }
212
+ }
213
+
214
+ // Check for function-level server directives in function bodies
215
+ if (node.type === "ExportNamedDeclaration" && node.declaration?.type === "FunctionDeclaration") {
216
+ const funcNode = node.declaration;
217
+ if (funcNode.body?.body) {
218
+ for (const stmt of funcNode.body.body) {
219
+ const directive = checkForDirective(stmt);
220
+ if (directive === "use server") {
221
+ hasFunctionLevelServerDirective = true;
222
+ // Mark this specific function as having a server directive
223
+ const name = funcNode.id?.name;
224
+ if (name) {
225
+ const exportInfo = exports.get(name);
226
+ if (exportInfo) {
227
+ exportInfo.declaration = exportInfo.declaration?.replace(
228
+ /^export\s+function\s+/,
229
+ 'export async function '
230
+ );
231
+ exportInfo.isAsync = true;
232
+ }
233
+ }
234
+ break;
235
+ }
236
+ }
237
+ }
238
+ } else if (node.type === "FunctionDeclaration") {
239
+ if (node.body?.body) {
240
+ for (const stmt of node.body.body) {
241
+ const directive = checkForDirective(stmt);
242
+ if (directive === "use server") {
243
+ hasFunctionLevelServerDirective = true;
244
+ // Mark this specific function as having a server directive
245
+ const name = node.id?.name;
246
+ if (name) {
247
+ const exportInfo = exports.get(name);
248
+ if (exportInfo) {
249
+ exportInfo.declaration = exportInfo.declaration?.replace(
250
+ /^export\s+function\s+/,
251
+ 'export async function '
252
+ );
253
+ exportInfo.isAsync = true;
254
+ }
255
+ }
256
+ break;
257
+ }
258
+ }
259
+ }
260
+ } else if (node.type === "VariableDeclaration") {
261
+ for (const decl of node.declarations) {
262
+ if (decl.init?.type === "FunctionExpression" || decl.init?.type === "ArrowFunctionExpression") {
263
+ const body = decl.init.body;
264
+ if (body.type === "BlockStatement" && body.body) {
265
+ for (const stmt of body.body) {
266
+ const directive = checkForDirective(stmt);
267
+ if (directive === "use server") {
268
+ hasFunctionLevelServerDirective = true;
269
+ const name = decl.id.type === "Identifier" ? decl.id.name : undefined;
270
+ if (name) {
271
+ const exportInfo = exports.get(name);
272
+ if (exportInfo) {
273
+ exportInfo.declaration = exportInfo.declaration?.replace(
274
+ /^export\s+function\s+/,
275
+ 'export async function '
276
+ );
277
+ exportInfo.isAsync = true;
278
+ }
279
+ }
280
+ break;
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
287
+ }
288
+
289
+ // Validate directive combinations
290
+ if (hasFileLevelClientDirective && hasFileLevelServerDirective) {
291
+ throw new Error(`Module ${moduleId} cannot have both "use client" and "use server" directives`);
292
+ }
293
+
294
+ if (hasFunctionLevelClientDirective) {
295
+ throw new Error(`Module ${moduleId} cannot have function-level "use client" directives - only file-level is allowed`);
296
+ }
297
+
298
+ // Validate against user's explicit intent
299
+ if (Boolean(isClientComponent) && !hasFileLevelClientDirective) {
300
+ throw new Error(`Module ${moduleId} is marked as a client component but has no "use client" directive`);
301
+ }
302
+
303
+ if (Boolean(isServerFunction) && !hasFileLevelServerDirective && !hasFunctionLevelServerDirective) {
304
+ if(process.env['NODE_ENV'] !== "production") {
305
+ console.log("Error for file", moduleId, source);
306
+ }
307
+ throw new Error(`Module ${moduleId} is marked as a server function but has no "use server" directive`);
308
+ }
309
+
310
+ // Remove the directive and any whitespace after it
311
+ if (directiveEnd > 0) {
312
+ sourceWithoutDirective = source.slice(directiveEnd).trim();
313
+ }
314
+
315
+ // Validate that there are exports to transform if explicitly marked
316
+ if (Boolean(isClientComponent) && exportNames.length === 0) {
317
+ throw new Error(`Module ${moduleId} is marked as a client component but has no exports to transform`);
318
+ }
319
+
320
+ if (Boolean(isServerFunction) && exportNames.length === 0) {
321
+ throw new Error(`Module ${moduleId} is marked as a server function but has no exports to transform`);
322
+ }
323
+
324
+ // For client modules in server environment, replace with client references
325
+ if (Boolean(isClientComponent)) {
326
+ const output: string[] = [];
327
+ const mappingInfos: MappingInfo[] = [];
328
+
329
+ // Add registerClientReference import
330
+ const clientImport = process.env['NODE_ENV'] === 'production'
331
+ ? 'import { registerClientReference } from "react-server-dom-esm/server";'
332
+ : 'import { registerClientReference } from "react-server-dom-esm/server.node";';
333
+ output.push(clientImport);
334
+ mappingInfos.push({ generatedLine: 1, originalLine: 1, originalColumn: 0 });
108
335
 
109
336
  // Register each export
337
+ let lineNum = 2;
110
338
  for (const name of exportNames) {
111
339
  const exportInfo = exports.get(name);
112
340
  if (exportInfo) {
@@ -115,112 +343,251 @@ export function transformModuleWithPreservedFunctions(
115
343
  name === "default" && exportInfo.localName
116
344
  ? exportInfo.localName
117
345
  : name;
118
- // Register all exports in server modules
119
- registrations.push(
120
- `registerServerReference(${exportName}, ${moduleIdLiteral}, ${JSON.stringify(
121
- name
122
- )});`
123
- );
346
+ if (name === 'default') {
347
+ output.push(
348
+ `export default registerClientReference(function() {` +
349
+ `throw new Error("Attempted to call the default export of ${moduleIdLiteral} from the server but it's on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.");` +
350
+ `}, ${moduleIdLiteral}, "default");`
351
+ );
352
+ } else {
353
+ output.push(
354
+ `export const ${exportName} = registerClientReference(function() {` +
355
+ `throw new Error("Attempted to call ${exportName}() from the server but ${exportName} is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.");` +
356
+ `}, ${moduleIdLiteral}, ${JSON.stringify(name)});`
357
+ );
358
+ }
359
+ // Create a mapping for each registration line
360
+ mappingInfos.push({
361
+ generatedLine: lineNum,
362
+ originalLine: exportInfo.loc?.line || 1,
363
+ originalColumn: exportInfo.loc?.column || 0
364
+ });
365
+ lineNum++;
124
366
  }
125
367
  }
126
368
 
127
- // Create new source with registrations
128
- // First, add the imports at the top
129
- const newSource = [...imports, sourceWithoutDirective, ...registrations].join("\n\n");
130
-
131
- // Handle source maps
132
- let mappings = "";
133
- const createMapping = createMappingsSerializer();
134
- let generatedLine = 1;
369
+ const newClientSource = output.join("\n\n");
370
+ const sourceMapBase64 = generateSourceMap(
371
+ moduleId,
372
+ source,
373
+ output,
374
+ mappingInfos,
375
+ originalSourceMap
376
+ );
377
+ return `${newClientSource}\n//# sourceMappingURL=${sourceMapBase64}`;
378
+ }
135
379
 
136
- // Map the import line to the first line of the original source
137
- createMapping(generatedLine, 0, 0, 0, 0, -1);
138
- generatedLine++;
380
+ // For server modules in client environment, replace with server references
381
+ if (Boolean(isServerFunction)) {
382
+ // First collect all exports that need registration
383
+ const exportedEntries: Array<{ localName: string; exportedName: string; type: string; loc?: { line: number; column: number } }> = [];
384
+ const localNames = new Set();
139
385
 
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++;
386
+ // Helper to check if a function has a "use server" directive
387
+ function hasServerDirective(node: any): boolean {
388
+ if (hasFileLevelServerDirective) return true;
389
+ if (node.body?.body) {
390
+ for (const stmt of node.body.body) {
391
+ const directive = checkForDirective(stmt);
392
+ if (directive === "use server") return true;
393
+ }
394
+ }
395
+ return false;
144
396
  }
145
397
 
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
- }
398
+ // First pass: collect exports and remove directives
399
+ let newSource = source;
400
+ let directiveEnd = 0;
152
401
 
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
- ];
176
- const declarations: string[] = [];
402
+ for (const node of program.body) {
403
+ // Handle directives
404
+ const directive = checkForDirective(node);
405
+ if (directive === "use server" || directive === "use client") {
406
+ if (node.start === 0) {
407
+ directiveEnd = node.end;
408
+ } else {
409
+ // Remove function-level directive
410
+ newSource = newSource.slice(0, node.start) + newSource.slice(node.end);
411
+ }
412
+ continue;
413
+ }
177
414
 
178
- for (const name of exportNames) {
179
- const errorMessage = createClientReferenceError(name);
180
- if (name === "default") {
181
- declarations.push(`export default registerClientReference(function() {
182
- throw new Error("${errorMessage}");
183
- }, ${moduleIdLiteral}, "default");`);
184
- } else {
185
- declarations.push(`export const ${name} = registerClientReference(function() {
186
- throw new Error("${errorMessage}");
187
- }, ${moduleIdLiteral}, ${JSON.stringify(name)});`);
415
+ // Collect exports that need registration, with loc
416
+ switch (node.type) {
417
+ case 'ExportDefaultDeclaration':
418
+ if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
419
+ const name = node.declaration.id.name;
420
+ if (hasServerDirective(node.declaration)) {
421
+ exportedEntries.push({
422
+ localName: name,
423
+ exportedName: 'default',
424
+ type: 'function',
425
+ loc: node.declaration.id.loc?.start || { line: 1, column: 0 }
426
+ });
427
+ localNames.add(name);
428
+ }
429
+ } else if (node.declaration.type === 'ClassDeclaration' && node.declaration.id) {
430
+ const name = node.declaration.id.name;
431
+ exportedEntries.push({
432
+ localName: name,
433
+ exportedName: 'default',
434
+ type: 'class',
435
+ loc: node.declaration.id.loc?.start || { line: 1, column: 0 }
436
+ });
437
+ localNames.add(name);
438
+ }
439
+ break;
440
+ case 'ExportNamedDeclaration':
441
+ if (node.declaration) {
442
+ if (node.declaration.type === 'FunctionDeclaration' && node.declaration.id) {
443
+ const name = node.declaration.id.name;
444
+ if (hasServerDirective(node.declaration)) {
445
+ exportedEntries.push({
446
+ localName: name,
447
+ exportedName: name,
448
+ type: 'function',
449
+ loc: node.declaration.id.loc?.start || { line: 1, column: 0 }
450
+ });
451
+ localNames.add(name);
452
+ }
453
+ } else if (node.declaration.type === 'ClassDeclaration' && node.declaration.id) {
454
+ const name = node.declaration.id.name;
455
+ exportedEntries.push({
456
+ localName: name,
457
+ exportedName: name,
458
+ type: 'class',
459
+ loc: node.declaration.id.loc?.start || { line: 1, column: 0 }
460
+ });
461
+ localNames.add(name);
462
+ } else if (node.declaration.type === 'VariableDeclaration') {
463
+ for (const decl of node.declaration.declarations) {
464
+ if (decl.id.type === 'Identifier') {
465
+ const name = decl.id.name;
466
+ if (decl.init) {
467
+ if (decl.init.type === 'FunctionExpression' || decl.init.type === 'ArrowFunctionExpression') {
468
+ if (hasServerDirective(decl.init)) {
469
+ exportedEntries.push({
470
+ localName: name,
471
+ exportedName: name,
472
+ type: 'function',
473
+ loc: decl.id.loc?.start || { line: 1, column: 0 }
474
+ });
475
+ localNames.add(name);
476
+ }
477
+ } else {
478
+ // Register non-function values
479
+ exportedEntries.push({
480
+ localName: name,
481
+ exportedName: name,
482
+ type: 'value',
483
+ loc: decl.id.loc?.start || { line: 1, column: 0 }
484
+ });
485
+ localNames.add(name);
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+ }
492
+ if (node.specifiers) {
493
+ for (const spec of node.specifiers) {
494
+ if (spec.type === 'ExportSpecifier') {
495
+ const localName = spec.local.type === 'Identifier' ? spec.local.name : '';
496
+ const exportedName = spec.exported.type === 'Identifier' ? spec.exported.name : '';
497
+ if (localName && exportedName) {
498
+ // Find the original declaration to check for directive
499
+ const originalDecl = program.body.find(n =>
500
+ (n.type === 'FunctionDeclaration' && n.id?.name === localName) ||
501
+ (n.type === 'ClassDeclaration' && n.id?.name === localName) ||
502
+ (n.type === 'VariableDeclaration' && n.declarations.some(d =>
503
+ d.id.type === 'Identifier' && d.id.name === localName
504
+ ))
505
+ );
506
+ let loc = { line: 1, column: 0 };
507
+ if (originalDecl) {
508
+ if (originalDecl.type === 'FunctionDeclaration' && hasServerDirective(originalDecl)) {
509
+ loc = originalDecl.id?.loc?.start || loc;
510
+ exportedEntries.push({
511
+ localName,
512
+ exportedName,
513
+ type: 'function',
514
+ loc
515
+ });
516
+ localNames.add(localName);
517
+ } else if (originalDecl.type === 'ClassDeclaration') {
518
+ loc = originalDecl.id?.loc?.start || loc;
519
+ exportedEntries.push({
520
+ localName,
521
+ exportedName,
522
+ type: 'class',
523
+ loc
524
+ });
525
+ localNames.add(localName);
526
+ } else if (originalDecl.type === 'VariableDeclaration') {
527
+ // Find the right declaration
528
+ const decl = originalDecl.declarations.find(d => d.id.type === 'Identifier' && d.id.name === localName);
529
+ loc = decl?.id?.loc?.start || loc;
530
+ exportedEntries.push({
531
+ localName,
532
+ exportedName,
533
+ type: 'value',
534
+ loc
535
+ });
536
+ localNames.add(localName);
537
+ }
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+ break;
188
544
  }
189
545
  }
190
- // Create new source with declarations
191
- const newSource = [...imports, ...declarations].join("\n\n");
192
-
193
- // Handle source maps for client modules
194
- let mappings = "";
195
- const createMapping = createMappingsSerializer();
196
- let generatedLine = 1;
197
-
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++;
546
+
547
+ // Remove file-level directive if present
548
+ if (directiveEnd > 0) {
549
+ newSource = newSource.slice(directiveEnd).trim();
206
550
  }
207
551
 
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")
552
+ // Add import and registrations
553
+ const lines: string[] = [];
554
+ const mappingInfos: MappingInfo[] = [];
555
+
556
+ // Add import statement
557
+ const serverImport = process.env['NODE_ENV'] === 'production'
558
+ ? 'import { registerServerReference } from "react-server-dom-esm/server";'
559
+ : 'import { registerServerReference } from "react-server-dom-esm/server.node";';
560
+ lines.push(serverImport);
561
+ mappingInfos.push({ generatedLine: 1, originalLine: 1, originalColumn: 0 });
562
+
563
+ // Add the original source code
564
+ lines.push(newSource);
565
+ mappingInfos.push({ generatedLine: 2, originalLine: 1, originalColumn: 0 });
566
+
567
+ // Add registrations after the source code
568
+ let lineNum = lines.length + 1;
569
+ for (const entry of exportedEntries) {
570
+ lines.push(`registerServerReference(${entry.localName}, ${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exportedName)});`);
571
+ // Create a mapping for each registration line
572
+ mappingInfos.push({
573
+ generatedLine: lineNum,
574
+ originalLine: entry.loc?.line || 1,
575
+ originalColumn: entry.loc?.column || 0
576
+ });
577
+ lineNum++;
578
+ }
579
+
580
+ const newTransformedSource = lines.join('\n');
581
+ const sourceMapBase64 = generateSourceMap(
582
+ moduleId,
583
+ source,
584
+ lines,
585
+ mappingInfos,
586
+ originalSourceMap
223
587
  );
588
+ return `${newTransformedSource}\n//# sourceMappingURL=${sourceMapBase64}`;
224
589
  }
225
- throw new Error("Invalid module type");
590
+
591
+ // For non-server, non-client modules, return as is
592
+ return sourceWithoutMap;
226
593
  }