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
@@ -104,7 +104,7 @@ export const resolveOptions = <
104
104
  typeof options.moduleBasePath === "string"
105
105
  ? options.moduleBasePath
106
106
  : process.env.VITE_BASE_URL ?? DEFAULT_CONFIG.MODULE_BASE_PATH;
107
-
107
+
108
108
  const moduleBaseURL =
109
109
  typeof options.moduleBaseURL === "string"
110
110
  ? options.moduleBaseURL
@@ -234,24 +234,23 @@ export const resolveOptions = <
234
234
  );
235
235
 
236
236
  const isServerFunctionCode = resolveAutoDiscoverMatcher(
237
- options.autoDiscover?.isServerFunction,
237
+ options.autoDiscover?.isServerFunctionCode,
238
238
  options.autoDiscover?.serverDirective
239
239
  ? (code: string, moduleId?: string) =>
240
240
  code.match(options.autoDiscover?.serverDirective!) != null ||
241
241
  (moduleId && serverFunctions(moduleId)) ||
242
242
  false
243
- : (code: string, moduleId?: string) =>
244
- code.match(DEFAULT_CONFIG.AUTO_DISCOVER.serverDirective) != null ||
245
- (moduleId && serverFunctions(moduleId)) ||
246
- false
243
+ : DEFAULT_CONFIG.AUTO_DISCOVER.isServerFunctionCode
247
244
  );
248
245
 
249
246
  const isClientComponentCode = resolveAutoDiscoverMatcher(
250
- options.autoDiscover?.isClientComponent,
247
+ options.autoDiscover?.isClientComponentCode,
251
248
  options.autoDiscover?.clientDirective
252
- ? (code: string) =>
253
- code.match(options.autoDiscover?.clientDirective!) != null
254
- : DEFAULT_CONFIG.AUTO_DISCOVER.clientDirective
249
+ ? (code: string, moduleId?: string) =>
250
+ code.match(options.autoDiscover?.clientDirective!) != null ||
251
+ (moduleId && clientComponents(moduleId)) ||
252
+ false
253
+ : DEFAULT_CONFIG.AUTO_DISCOVER.isClientComponentCode
255
254
  );
256
255
 
257
256
  const hashOption =
@@ -0,0 +1,79 @@
1
+ import type { Logger } from "vite";
2
+ import { toError } from "../error/toError.js";
3
+ import { PassThrough } from "node:stream";
4
+
5
+ export interface ServerActionRequest {
6
+ id: string;
7
+ args: unknown[];
8
+ }
9
+
10
+ export interface ServerActionResponse {
11
+ type: "server-action-response";
12
+ returnValue: unknown;
13
+ }
14
+
15
+ /**
16
+ * Parses a server action request from the request body.
17
+ * Supports two formats:
18
+ * 1. Direct args array: [arg1, arg2, ...]
19
+ * 2. Object with id and args: { id: string, args: unknown[] }
20
+ */
21
+ export function parseServerActionRequest(body: string, url?: string): ServerActionRequest {
22
+ const parsed = JSON.parse(body);
23
+
24
+ if (Array.isArray(parsed)) {
25
+ // Format 1: Direct args array
26
+ return {
27
+ args: parsed,
28
+ id: url?.split("?")[0] ?? "",
29
+ };
30
+ } else if (parsed && typeof parsed === "object" && "id" in parsed) {
31
+ // Format 2: Object with id and args
32
+ return {
33
+ id: parsed.id,
34
+ args: parsed.args ?? [],
35
+ };
36
+ }
37
+
38
+ throw new Error("Invalid server action request format");
39
+ }
40
+
41
+ /**
42
+ * Creates a server action response with the given result or error.
43
+ */
44
+ export function createServerActionResponse(result?: unknown, error?: string): ServerActionResponse {
45
+ return {
46
+ type: "server-action-response",
47
+ returnValue: error
48
+ ? { success: false, error }
49
+ : result
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Handles errors in server action processing.
55
+ */
56
+ export function handleServerActionError(error: unknown, res: any, logger: Logger) {
57
+ const err = toError(error);
58
+ logger.error(err.message + (err.stack ?? ""), { error: err });
59
+ res.statusCode = 500;
60
+ res.end(JSON.stringify(createServerActionResponse(undefined, err.message)));
61
+ }
62
+
63
+ /**
64
+ * Sets up common response headers for server actions.
65
+ */
66
+ export function setupServerActionHeaders(res: any) {
67
+ res.setHeader("Content-Type", "text/x-component; charset=utf-8");
68
+ res.setHeader("Transfer-Encoding", "chunked");
69
+ res.setHeader("Connection", "keep-alive");
70
+ }
71
+
72
+ /**
73
+ * Creates a pass-through stream for server action responses.
74
+ */
75
+ export function createServerActionStream(res: any): PassThrough {
76
+ const passThrough = new PassThrough();
77
+ passThrough.pipe(res);
78
+ return passThrough;
79
+ }
@@ -1,5 +1,20 @@
1
- import type { Program } from "./types.js";
2
- import type { FunctionDeclaration, VariableDeclaration, VariableDeclarator } from "acorn";
1
+ import type { Program, Node } from "./types.js";
2
+ import type {
3
+ FunctionDeclaration, VariableDeclaration,
4
+ VariableDeclarator
5
+ } from "acorn";
6
+
7
+ export interface ExportInfo {
8
+ name: string;
9
+ localName?: string;
10
+ type: "function" | "variable" | "class" | "unknown" | "all";
11
+ node?: Node;
12
+ declaration?: string;
13
+ before?: string[];
14
+ after?: string[];
15
+ isAsync?: boolean;
16
+ loc?: { line: number; column: number };
17
+ }
3
18
 
4
19
  /**
5
20
  * Collects and organizes export information from a module.
@@ -28,40 +43,31 @@ export function handleExports(
28
43
  imports: string[];
29
44
  declarations: string[];
30
45
  exportNames: string[];
31
- exports: Map<
32
- string,
33
- {
34
- type: "function" | "class" | "variable" | "default" | "all";
35
- declaration?: string;
36
- localName?: string;
37
- before?: string[];
38
- after?: string[];
39
- isAsync?: boolean;
40
- isServerAction?: boolean;
41
- }
42
- >;
46
+ exports: Map<string, ExportInfo>;
43
47
  } {
44
48
  const imports: string[] = [];
45
49
  const declarations: string[] = [];
46
50
  const exportNames: string[] = [];
47
- // Track exports and their types
48
- const exports = new Map<
49
- string,
50
- {
51
- type: "function" | "class" | "variable" | "default" | "all";
52
- declaration?: string;
53
- localName?: string;
54
- before?: string[];
55
- after?: string[];
56
- isAsync?: boolean;
57
- isServerAction?: boolean;
58
- }
59
- >();
51
+ const exports = new Map<string, ExportInfo>();
60
52
 
61
53
  let lastEnd = 0;
62
54
  let currentBefore: string[] = [];
63
55
  let foundFirstExport = false;
64
56
 
57
+ // Helper function to get function type
58
+ function getFunctionType(node: Node): "function" | "variable" | "class" | "unknown" {
59
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
60
+ return "function";
61
+ }
62
+ if (node.type === "ClassDeclaration") {
63
+ return "class";
64
+ }
65
+ if (node.type === "VariableDeclaration") {
66
+ return "variable";
67
+ }
68
+ return "unknown";
69
+ }
70
+
65
71
  // First pass: collect all exports and code between them
66
72
  for (const node of program.body) {
67
73
  // Add any code before this node
@@ -85,9 +91,9 @@ export function handleExports(
85
91
  const importedName = spec.imported.type === "Identifier" ? spec.imported.name : "";
86
92
  if (localName && importedName) {
87
93
  exports.set(localName, {
94
+ name: localName,
88
95
  type: "function",
89
96
  localName,
90
- isServerAction: true,
91
97
  before: [...currentBefore],
92
98
  });
93
99
  exportNames.push(localName);
@@ -98,6 +104,7 @@ export function handleExports(
98
104
  } else if (node.type === "ExportAllDeclaration") {
99
105
  // For export * from './other', just add the * export
100
106
  exports.set("*", {
107
+ name: "*",
101
108
  type: "all",
102
109
  before: [...currentBefore],
103
110
  });
@@ -116,11 +123,11 @@ export function handleExports(
116
123
  ) {
117
124
  const name = node.declaration.id.name;
118
125
  exports.set(name, {
119
- type: "function",
126
+ name,
127
+ type: getFunctionType(node.declaration),
120
128
  declaration: source.slice(node.declaration.start, node.declaration.end),
121
129
  before: [...currentBefore],
122
130
  isAsync: node.declaration.async,
123
- isServerAction: isServerFunction === true,
124
131
  });
125
132
  exportNames.push(name);
126
133
  currentBefore = [];
@@ -130,7 +137,8 @@ export function handleExports(
130
137
  ) {
131
138
  const name = node.declaration.id.name;
132
139
  exports.set(name, {
133
- type: "class",
140
+ name,
141
+ type: getFunctionType(node.declaration),
134
142
  declaration: source.slice(node.declaration.start, node.declaration.end),
135
143
  before: [...currentBefore],
136
144
  });
@@ -141,7 +149,7 @@ export function handleExports(
141
149
  if (decl.id && decl.id.type === "Identifier") {
142
150
  const name = decl.id.name;
143
151
  const init = decl.init;
144
- const isFunction = init && (
152
+ const isFunction = init != null && (
145
153
  init.type === "FunctionExpression" ||
146
154
  init.type === "ArrowFunctionExpression"
147
155
  );
@@ -150,11 +158,11 @@ export function handleExports(
150
158
  (init.type === "ArrowFunctionExpression" && init.async === true)
151
159
  );
152
160
  exports.set(name, {
161
+ name,
153
162
  type: isFunction ? "function" : "variable",
154
163
  declaration: source.slice(decl.start, decl.end),
155
164
  before: [...currentBefore],
156
165
  isAsync: isAsync || false,
157
- isServerAction: isFunction != null && isServerFunction === true,
158
166
  });
159
167
  exportNames.push(name);
160
168
  currentBefore = [];
@@ -177,12 +185,12 @@ export function handleExports(
177
185
 
178
186
  if (functionDecl) {
179
187
  exports.set(exportedName, {
180
- type: "function",
188
+ name: exportedName,
189
+ type: getFunctionType(functionDecl),
181
190
  localName,
182
191
  declaration: source.slice(functionDecl.start, functionDecl.end),
183
192
  before: [...currentBefore],
184
193
  isAsync: functionDecl.async,
185
- isServerAction: isServerFunction === true,
186
194
  });
187
195
  exportNames.push(exportedName);
188
196
  } else {
@@ -208,17 +216,18 @@ export function handleExports(
208
216
  const isAsync = decl.init.type === "FunctionExpression" ? decl.init.async :
209
217
  decl.init.type === "ArrowFunctionExpression" ? decl.init.async : false;
210
218
  exports.set(exportedName, {
219
+ name: exportedName,
211
220
  type: "function",
212
221
  localName,
213
222
  declaration: source.slice(decl.start, decl.end),
214
223
  before: [...currentBefore],
215
224
  isAsync,
216
- isServerAction: isServerFunction === true,
217
225
  });
218
226
  exportNames.push(exportedName);
219
227
  }
220
228
  } else {
221
229
  exports.set(exportedName, {
230
+ name: exportedName,
222
231
  type: "variable",
223
232
  localName,
224
233
  before: [...currentBefore],
@@ -233,14 +242,15 @@ export function handleExports(
233
242
  } else if (node.type === "ExportDefaultDeclaration") {
234
243
  if (node.declaration && node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
235
244
  exports.set("default", {
236
- type: "default",
237
- before: [...currentBefore],
245
+ name: "default",
246
+ type: getFunctionType(node.declaration),
238
247
  localName: node.declaration.id.name, // Capture the function name
239
- isAsync: node.declaration.async
248
+ isAsync: node.declaration.async,
240
249
  });
241
250
  } else {
242
251
  exports.set("default", {
243
- type: "default",
252
+ name: "default",
253
+ type: "unknown",
244
254
  before: [...currentBefore]
245
255
  });
246
256
  }
@@ -3,28 +3,63 @@ import { transformModuleWithPreservedFunctions } from "./transformModuleWithPres
3
3
  import { parse } from "./parse.js";
4
4
  import { DEFAULT_CONFIG } from "../config/defaults.js";
5
5
 
6
+ // --- React RSC Directive Handling ---
7
+ //
8
+ // 1. 'use client' at file top:
9
+ // - Pass through code as-is (after removing directive).
10
+ // - Do not transform or register anything.
11
+ // - Required for React client features to work.
12
+ // - See: https://react.dev/reference/rsc/use-client
13
+ //
14
+ // 2. 'use server' at file top:
15
+ // - Register all exported async functions as server actions.
16
+ // - See: https://react.dev/reference/rsc/use-server
17
+ //
18
+ // 3. 'use server' at function top:
19
+ // - Register only that async function as a server action.
20
+ // - See: https://react.dev/reference/rsc/use-server
21
+ //
22
+ // 4. No directive:
23
+ // - Treat as a normal shared or server-only module.
24
+ // - No special registration or transformation.
25
+
6
26
  export function transformModuleIfNeeded(
7
27
  source: string,
8
28
  moduleId: string,
9
29
  isServerFunction: boolean | RegExpMatchArray | null = DEFAULT_CONFIG.AUTO_DISCOVER.isServerFunctionCode(source, moduleId),
10
- isClientComponent: boolean | RegExpMatchArray | null = DEFAULT_CONFIG.AUTO_DISCOVER.isClientComponentCode(source),
30
+ isClientComponent: boolean | RegExpMatchArray | null = DEFAULT_CONFIG.AUTO_DISCOVER.isClientComponentCode(source, moduleId),
11
31
  isServerEnvironment = getCondition() === "react-server"
12
32
  ) {
13
33
  // Handle environment-specific cases
14
- if (
15
- (isServerEnvironment && !isServerFunction && !isClientComponent) ||
16
- (!isServerEnvironment && isClientComponent)
17
- ) {
18
- return source
34
+ if (isServerEnvironment) {
35
+ // In server environment:
36
+ // - Server functions need transformation
37
+ // - Client components need transformation
38
+ // - Other modules can pass through
39
+ if (!isServerFunction && !isClientComponent) {
40
+ return source;
41
+ }
42
+ } else {
43
+ // In client environment:
44
+ // - Only client components should pass through
45
+ // - Server functions should be transformed
46
+ if (isClientComponent) {
47
+ return source;
48
+ }
19
49
  }
20
50
 
21
- const result = transformModuleWithPreservedFunctions(
22
- source,
23
- moduleId,
24
- parse(source),
25
- isServerFunction,
26
- isClientComponent
27
- );
28
-
29
- return result
51
+ try {
52
+ const result = transformModuleWithPreservedFunctions(
53
+ source,
54
+ moduleId,
55
+ parse(source),
56
+ isServerFunction,
57
+ isClientComponent
58
+ );
59
+ return result;
60
+ } catch (error) {
61
+ // Log the error and rethrow
62
+ console.error(`Error transforming module ${moduleId}:`, error);
63
+ throw error;
64
+ }
30
65
  }