vite-plugin-react-server 1.2.2 → 1.2.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-react-server",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Vite plugin for React Server Components (RSC)",
5
5
  "type": "module",
6
6
  "main": "./dist/plugin/index.js",
@@ -38,7 +38,7 @@ export async function createSharedLoader({
38
38
  buildServerDir,
39
39
  // Direct import options
40
40
  isBuildMode = false,
41
- isServeMode = false,
41
+ isServeMode: _isServeMode = false,
42
42
  effectiveProjectRoot,
43
43
  build,
44
44
  }: {
@@ -99,66 +99,32 @@ export async function createSharedLoader({
99
99
  });
100
100
 
101
101
  if (manifestResolution.manifestEntry && manifestResolution.resolvedPath) {
102
- // Found in manifest - use the resolved path (it's already a full absolute path)
103
102
  resolvedModuleID = manifestResolution.resolvedPath;
104
- if (verbose) {
105
- logger?.info(
106
- `[createSharedLoader] Build mode: resolved via manifest to: ${resolvedModuleID}`
107
- );
108
- }
109
103
  } else {
110
- // Not in manifest - use the builtModuleId from resolution
111
104
  resolvedModuleID = manifestResolution.builtModuleId;
112
- if (verbose) {
113
- logger?.info(
114
- `[createSharedLoader] Build mode: not in manifest, using builtModuleId: ${resolvedModuleID}`
115
- );
116
- }
117
105
 
118
- // Check if we need to prefix with build directory
119
- // A source path starts with moduleBase (e.g., "src/"), a built path doesn't
120
- // Also check if it's already an absolute path or starts with file://
106
+ // Prefix non-source, non-absolute paths with server build directory
121
107
  const isSourcePath = moduleId.startsWith(moduleBase + "/") ||
122
108
  moduleId.startsWith("./" + moduleBase + "/") ||
123
109
  (isAbsolute(moduleId) && moduleId.includes(moduleBase));
124
110
 
125
- // If it's not a source path and not already absolute, prefix with server build directory
126
111
  if (!isSourcePath && !isAbsolute(resolvedModuleID) && effectiveProjectRoot && build) {
127
- const serverBuildPath = join(
112
+ resolvedModuleID = join(
128
113
  effectiveProjectRoot,
129
114
  build.outDir || "dist",
130
- build.server || "server"
131
- );
132
- resolvedModuleID = join(serverBuildPath, resolvedModuleID);
133
- if (verbose) {
134
- logger?.info(
135
- `[createSharedLoader] Build mode: prefixing with ${serverBuildPath}: ${resolvedModuleID}`
136
- );
137
- }
138
- }
139
- }
140
- } else if (isServeMode) {
141
- // Dev mode: load directly from source files, no build path prefixing
142
- if (verbose) {
143
- logger?.info(
144
- `[createSharedLoader] Dev mode: loading directly from source`
145
- );
146
- }
147
- } else if (isBuildMode && effectiveProjectRoot && build) {
148
- // Build mode fallback: prefix with server build directory even without manifest/normalizer
149
- if (!isAbsolute(resolvedModuleID)) {
150
- const serverBuildPath = join(
151
- effectiveProjectRoot,
152
- build.outDir || "dist",
153
- build.server || "server"
154
- );
155
- resolvedModuleID = join(serverBuildPath, resolvedModuleID);
156
- if (verbose) {
157
- logger?.info(
158
- `[createSharedLoader] Build mode fallback: prefixing with ${serverBuildPath}: ${resolvedModuleID}`
115
+ build.server || "server",
116
+ resolvedModuleID
159
117
  );
160
118
  }
161
119
  }
120
+ } else if (isBuildMode && effectiveProjectRoot && build && !isAbsolute(resolvedModuleID)) {
121
+ // Build mode fallback without manifest
122
+ resolvedModuleID = join(
123
+ effectiveProjectRoot,
124
+ build.outDir || "dist",
125
+ build.server || "server",
126
+ resolvedModuleID
127
+ );
162
128
  }
163
129
 
164
130
  // Step 3: Construct the full path and import
@@ -168,40 +134,21 @@ export async function createSharedLoader({
168
134
  ? join(effectiveProjectRoot, resolvedModuleID)
169
135
  : resolvedModuleID;
170
136
 
171
- if (verbose) {
172
- logger?.info(`[createSharedLoader] Importing from: ${fullPath}`);
173
- }
174
-
175
- // Step 4: Import the module
137
+ // Import the module
176
138
  const fileUrl = isAbsolute(fullPath) ? pathToFileURL(fullPath).href : fullPath;
177
139
  const result = await import(fileUrl);
178
140
 
179
- // Step 5: Validate exports
141
+ // Validate exports
180
142
  if (result == null) {
181
143
  throw new Error(`Module "${moduleId}" does not have any exports`);
182
144
  }
183
-
184
145
  if (!Object.keys(result).length && exportName?.length) {
185
- throw new Error(
186
- `Module "${moduleId}" is a module, but does not have any exports so it can't find ${exportName}`
187
- );
146
+ throw new Error(`Module "${moduleId}" has no exports, can't find ${exportName}`);
188
147
  }
189
-
190
148
  if (exportName && !(exportName in result)) {
191
- throw new Error(
192
- `Module "${moduleId}" exists, but does not export "${exportName}"`
193
- );
194
- }
195
-
196
- if (verbose) {
197
- logger?.info(
198
- `[createSharedLoader] Module loaded successfully, exports: ${Object.keys(
199
- result
200
- ).join(", ")}`
201
- );
149
+ throw new Error(`Module "${moduleId}" does not export "${exportName}"`);
202
150
  }
203
151
 
204
- // Import always returns a module object (not a Promise), so return it directly
205
152
  return result;
206
153
  }
207
154
 
@@ -67,11 +67,15 @@ export function analyzeDirectives(
67
67
  ? optionsOrMatches.logger ?? _logger ?? createLogger()
68
68
  : _logger ?? createLogger();
69
69
  // Check if this looks like Vite-injected code
70
+ // During build, Vite may prepend imports (e.g., __vitePreload for dynamic imports)
71
+ // before "use client"/"use server" directives
70
72
  const isViteInjectedCode =
71
73
  source.includes("__vite__createHotContext") ||
72
74
  source.includes("import.meta.hot") ||
73
75
  source.includes("import.meta.env") ||
74
- source.includes("/@vite/client");
76
+ source.includes("/@vite/client") ||
77
+ source.includes("__vitePreload") ||
78
+ source.includes("\0vite/");
75
79
 
76
80
  for (const node of ast.body) {
77
81
  // Debug logging
@@ -119,30 +119,11 @@ export const load: LoadHook = async (url, context, nextLoad) => {
119
119
  });
120
120
  }
121
121
  const verbose = userOptions?.verbose ?? false;
122
- if (verbose) {
123
- logger.info(`Attempting to load: ${url}`);
124
- logger.info(`Context: ${JSON.stringify({
125
- format: context.format,
126
- conditions: context.conditions,
127
- })}`);
128
- }
129
122
 
130
123
  const { format } = context;
131
124
  if (format === "module" || format === "module-typescript") {
132
- if (verbose) {
133
- logger.info(`Loading module: ${url}`);
134
- }
135
-
136
125
  // Load the URL normally
137
126
  const result = await nextLoad(url, context);
138
-
139
- if (verbose) {
140
- logger.info(`Next load result: ${JSON.stringify({
141
- format: result.format,
142
- shortCircuit: result.shortCircuit,
143
- source: typeof result.source,
144
- })}`);
145
- }
146
127
 
147
128
  let source =
148
129
  typeof result.source === "string"
@@ -187,45 +168,18 @@ export const load: LoadHook = async (url, context, nextLoad) => {
187
168
  ? isClientComponent(source, url)
188
169
  : false);
189
170
 
190
- if (verbose) {
191
- let startPreviewIndex = 0;
192
- let startLine = 0;
193
- const lines = source.split("\n");
194
- while (
195
- lines[startLine].trim() === "" || lines[startLine].trim() === "\r" ||
196
- // comment lines
197
- lines[startLine].trim().startsWith("//")
198
- || lines[startLine].trim().startsWith("/**")
199
- || lines[startLine].trim().startsWith("*")
200
- ) {
201
- startPreviewIndex += lines[startLine].length;
202
- startLine++;
203
- }
204
- logger.info(`Module analysis: ${JSON.stringify({
205
- url,
206
- isServer,
207
- isClient,
208
- hasFileLevelServerDirective,
209
- hasFileLevelClientDirective,
210
- sourceLength: source.length,
211
- sourcePreview: source.slice(startPreviewIndex, startPreviewIndex + 100) + "...",
212
- })}`);
213
- }
214
-
215
171
  if (!isServer && !isClient) {
216
- if (verbose) {
217
- logger.info(`Skipping non-server/non-client module: ${url}`);
218
- }
219
172
  // Return modified source if CJS React imports were rewritten
220
173
  return { ...result, source };
221
174
  }
222
175
 
223
- // Handle file URLs
224
- const filePath = url.startsWith("file://") ? fileURLToPath(url) : url;
225
176
  if (verbose) {
226
- logger.info(`File path: ${filePath}`);
177
+ logger.info(`[react-loader] ${isServer ? 'server' : 'client'} module: ${url}`);
227
178
  }
228
179
 
180
+ // Handle file URLs
181
+ const filePath = url.startsWith("file://") ? fileURLToPath(url) : url;
182
+
229
183
  if(typeof userOptions.moduleID !== "function") {
230
184
  // Ensure we have proper build context for RSC worker
231
185
  // If configEnv is not available or doesn't indicate build mode, create a build-compatible configEnv
@@ -249,27 +203,11 @@ export const load: LoadHook = async (url, context, nextLoad) => {
249
203
  const [, value] = userOptions.normalizer(filePath);
250
204
  moduleID = join(userOptions.moduleBasePath, value);
251
205
  finalID = userOptions.moduleID?.(moduleID) || moduleID;
252
- if (verbose) {
253
- logger.info(`Normalized IDs: ${moduleID} -> ${finalID}`);
254
- logger.info(`userOptions: ${JSON.stringify(userOptions)}`);
255
- }
256
206
  }
257
207
 
258
208
  const { code: transformed, map } = await transformer(source, moduleID, finalID);
259
209
 
260
- if (verbose) {
261
- logger.info(`Transformation result: ${JSON.stringify({
262
- originalLength: source.length,
263
- transformedLength: transformed.length,
264
- wasTransformed: source !== transformed,
265
- hasSourceMap: !!map,
266
- })}`);
267
- }
268
-
269
210
  if (loaderPort) {
270
- if (verbose) {
271
- logger.info("Sending SERVER_MODULE message");
272
- }
273
211
  loaderPort.postMessage({
274
212
  type: "SERVER_MODULE",
275
213
  id: finalID,
@@ -285,21 +223,9 @@ export const load: LoadHook = async (url, context, nextLoad) => {
285
223
  };
286
224
  }
287
225
 
288
- if (verbose) {
289
- logger.info(`Skipping non-module format: ${format}`);
290
- }
291
226
  return nextLoad(url, context);
292
227
  };
293
228
 
294
229
  export const resolve: ResolveHook = async (specifier, context, nextResolve) => {
295
- verbose = userOptions?.verbose ?? false;
296
- if (verbose) {
297
- logger.info(`Resolving: ${specifier}`);
298
- logger.info(`Resolve context: ${JSON.stringify(context)}`);
299
- }
300
- const result = await nextResolve(specifier, context);
301
- if (verbose) {
302
- logger.info(`Resolve result: ${JSON.stringify(result)}`);
303
- }
304
- return result;
230
+ return nextResolve(specifier, context);
305
231
  };
@@ -4,15 +4,11 @@ import type { GenericModuleLoader } from "../../types.js";
4
4
  import { createSharedLoader } from "../../helpers/createSharedLoader.js";
5
5
 
6
6
  /**
7
- * Creates a simple GenericModuleLoader for the RSC worker
8
- *
9
- * This follows the same pattern as the main thread server version:
10
- * - Simple dynamic import-based loading
11
- * - Proper export name resolution
12
- * - Works in both dev and build scenarios
7
+ * Creates a GenericModuleLoader for the RSC worker.
8
+ * Uses createSharedLoader for virtual modules, manifest resolution, and imports.
13
9
  */
14
10
  export const createRscWorkerLoader = ({
15
- verbose = false, // Disable verbose for performance
11
+ verbose = false,
16
12
  logger = createLogger(workerData.resolvedConfig?.logLevel ?? "info", {
17
13
  prefix: "vite:plugin-react-server/worker/rsc",
18
14
  }),
@@ -31,57 +27,14 @@ export const createRscWorkerLoader = ({
31
27
  };
32
28
  manifest?: Record<string, any>;
33
29
  } = {}): GenericModuleLoader => {
34
- // Debug log the build config
35
- if (verbose) {
36
- logger.info(`[createRscWorkerLoader] build config: ${JSON.stringify(build)}`);
37
- }
38
-
39
- // Determine projectRoot based on configEnv if not provided
40
- // In dev mode, configEnv.command should be "serve", but if it's undefined,
41
- // we can detect dev mode by checking if we're in a dev server environment
42
30
  const isBuildMode = workerData.configEnv?.command === "build";
43
- const isServeMode = !isBuildMode
31
+ const isServeMode = !isBuildMode;
44
32
  const effectiveProjectRoot =
45
33
  projectRoot || workerData.userOptions?.projectRoot || process.cwd();
46
34
 
47
- // Log build config for debugging
48
- if (verbose) {
49
- logger.info(
50
- `[createRscWorkerLoader] build config: ${JSON.stringify(build)}`
51
- );
52
- logger.info(
53
- `[createRscWorkerLoader] manifest: ${JSON.stringify(manifest)}`
54
- );
55
- }
56
-
57
- if (verbose) {
58
- logger.info(
59
- `[createRscWorkerLoader] configEnv: ${JSON.stringify(
60
- workerData.configEnv
61
- )}`
62
- );
63
- logger.info(
64
- `[createRscWorkerLoader] config.env: ${JSON.stringify(
65
- workerData.resolvedConfig?.env
66
- )}`
67
- );
68
- logger.info(
69
- `[createRscWorkerLoader] mode: ${workerData.resolvedConfig?.mode}`
70
- );
71
- logger.info(`[createRscWorkerLoader] NODE_ENV: ${process.env.NODE_ENV}`);
72
- logger.info(`[createRscWorkerLoader] isServeMode: ${isServeMode}`);
73
- logger.info(`[createRscWorkerLoader] projectRoot: ${effectiveProjectRoot}`);
74
- }
75
-
76
- // Simple GenericModuleLoader using shared loader utility
77
35
  return async (id: string) => {
78
- if (verbose) {
79
- logger.info(`[RSC Worker Loader] Loading module: ${id}`);
80
- }
81
-
82
36
  const [moduleID, exportName] = id.split("#");
83
37
 
84
- // Use shared loader utility - it handles virtual modules, manifest resolution, and imports
85
38
  return await createSharedLoader({
86
39
  moduleId: moduleID,
87
40
  exportName,