vite-plugin-react-server 1.1.3 → 1.1.5

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 (68) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/plugin/config/autoDiscover/resolveBuildPages.d.ts +1 -1
  3. package/dist/plugin/config/autoDiscover/resolveBuildPages.d.ts.map +1 -1
  4. package/dist/plugin/config/autoDiscover/resolveBuildPages.js.map +1 -1
  5. package/dist/plugin/config/defaults.d.ts +1 -1
  6. package/dist/plugin/config/defaults.d.ts.map +1 -1
  7. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  8. package/dist/plugin/config/resolveOptions.js +1 -1
  9. package/dist/plugin/config/resolveOptions.js.map +1 -1
  10. package/dist/plugin/config/resolveUrlOption.d.ts +2 -2
  11. package/dist/plugin/config/resolveUrlOption.d.ts.map +1 -1
  12. package/dist/plugin/config/resolveUrlOption.js +4 -1
  13. package/dist/plugin/config/resolveUrlOption.js.map +1 -1
  14. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  15. package/dist/plugin/config/resolveUserConfig.js +11 -1
  16. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  17. package/dist/plugin/helpers/createRscStream.js +2 -1
  18. package/dist/plugin/helpers/createRscStream.js.map +1 -1
  19. package/dist/plugin/helpers/requestToRoute.d.ts +5 -0
  20. package/dist/plugin/helpers/requestToRoute.d.ts.map +1 -0
  21. package/dist/plugin/helpers/requestToRoute.js +24 -0
  22. package/dist/plugin/helpers/requestToRoute.js.map +1 -0
  23. package/dist/plugin/html.d.ts +1 -1
  24. package/dist/plugin/html.d.ts.map +1 -1
  25. package/dist/plugin/html.js +3 -2
  26. package/dist/plugin/html.js.map +1 -1
  27. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  28. package/dist/plugin/react-client/plugin.js.map +1 -1
  29. package/dist/plugin/react-client/server.d.ts +1 -1
  30. package/dist/plugin/react-client/server.d.ts.map +1 -1
  31. package/dist/plugin/react-client/server.js +51 -39
  32. package/dist/plugin/react-client/server.js.map +1 -1
  33. package/dist/plugin/react-server/server.d.ts +1 -1
  34. package/dist/plugin/react-server/server.d.ts.map +1 -1
  35. package/dist/plugin/react-server/server.js +36 -20
  36. package/dist/plugin/react-server/server.js.map +1 -1
  37. package/dist/plugin/react-static/plugin.d.ts.map +1 -1
  38. package/dist/plugin/react-static/plugin.js +27 -8
  39. package/dist/plugin/react-static/plugin.js.map +1 -1
  40. package/dist/plugin/react-static/renderPage.d.ts.map +1 -1
  41. package/dist/plugin/react-static/renderPage.js.map +1 -1
  42. package/dist/plugin/transformer/plugin.client.d.ts.map +1 -1
  43. package/dist/plugin/transformer/plugin.client.js +13 -3
  44. package/dist/plugin/transformer/plugin.client.js.map +1 -1
  45. package/dist/plugin/transformer/plugin.server.d.ts.map +1 -1
  46. package/dist/plugin/transformer/plugin.server.js +13 -3
  47. package/dist/plugin/transformer/plugin.server.js.map +1 -1
  48. package/dist/plugin/worker/createWorker.d.ts +1 -0
  49. package/dist/plugin/worker/createWorker.d.ts.map +1 -1
  50. package/dist/plugin/worker/createWorker.js +9 -16
  51. package/dist/plugin/worker/createWorker.js.map +1 -1
  52. package/dist/tsconfig.tsbuildinfo +1 -1
  53. package/package.json +1 -1
  54. package/plugin/config/autoDiscover/resolveBuildPages.ts +1 -1
  55. package/plugin/config/resolveOptions.ts +1 -3
  56. package/plugin/config/resolveUrlOption.ts +19 -10
  57. package/plugin/config/resolveUserConfig.ts +19 -1
  58. package/plugin/helpers/createRscStream.tsx +2 -2
  59. package/plugin/helpers/requestToRoute.ts +23 -0
  60. package/plugin/html.tsx +2 -0
  61. package/plugin/react-client/plugin.ts +1 -0
  62. package/plugin/react-client/server.ts +62 -40
  63. package/plugin/react-server/server.ts +50 -23
  64. package/plugin/react-static/plugin.ts +34 -12
  65. package/plugin/react-static/renderPage.ts +0 -1
  66. package/plugin/transformer/plugin.client.ts +13 -3
  67. package/plugin/transformer/plugin.server.ts +14 -4
  68. package/plugin/worker/createWorker.ts +19 -21
@@ -8,7 +8,6 @@ import type {
8
8
  RscWorkerOutputMessage,
9
9
  RscRenderMessage,
10
10
  } from "../worker/types.js";
11
- import { join } from "node:path";
12
11
  import type { Worker as NodeWorker } from "node:worker_threads";
13
12
  import { MessageChannel } from "node:worker_threads";
14
13
  import {
@@ -17,6 +16,7 @@ import {
17
16
  } from "../helpers/serializeUserOptions.js";
18
17
  import { createWorker } from "../worker/createWorker.js";
19
18
  import { getRouteFiles } from "../helpers/getRouteFiles.js";
19
+ import { requestToRoute } from "../helpers/requestToRoute.js";
20
20
 
21
21
  let currentWorker: NodeWorker | null = null;
22
22
  let isRestarting = false;
@@ -169,7 +169,7 @@ export function handleWorkerRscStream(
169
169
  export async function configureWorkerRequestHandler({
170
170
  server,
171
171
  autoDiscoveredFiles,
172
- userOptions,
172
+ userOptions: _userOptions,
173
173
  hmrChannel,
174
174
  }: {
175
175
  server: ViteDevServer;
@@ -177,15 +177,30 @@ export async function configureWorkerRequestHandler({
177
177
  userOptions: ResolvedUserOptions;
178
178
  hmrChannel: MessageChannel;
179
179
  }) {
180
- if(server.config.root !== userOptions.projectRoot) {
181
- server.config.logger.error("[react-client] Project root mismatch", {
182
- error: new Error(`Server root ${server.config.root} does not match user options root ${userOptions.projectRoot}`)
183
- });
184
- return;
185
- }
180
+ let {
181
+ // remove these
182
+ moduleBaseURL: _moduleBaseURL,
183
+ projectRoot: _projectRoot,
184
+ ...handlerUserOptions
185
+ } = _userOptions;
186
+ const handlerOptions = Object.assign({}, handlerUserOptions, {
187
+ moduleBaseURL:
188
+ typeof server.config.server.host === "string"
189
+ ? `${server.config.server.https ? "https" : "http"}://${
190
+ server.config.server.host
191
+ }:${server.config.server.port}`
192
+ : "",
193
+ moduleBasePath:
194
+ server.config.base === "/"
195
+ ? ""
196
+ : server.config.base.endsWith("/")
197
+ ? server.config.base.slice(0, -1)
198
+ : server.config.base,
199
+ projectRoot: server.config.root,
200
+ });
186
201
 
187
202
  // Start the worker
188
- await restartWorker(server, autoDiscoveredFiles, userOptions, hmrChannel);
203
+ await restartWorker(server, autoDiscoveredFiles, handlerOptions, hmrChannel);
189
204
 
190
205
  // Create the request handler
191
206
  const handler: RequestHandler = async (req, res, next) => {
@@ -197,18 +212,24 @@ export async function configureWorkerRequestHandler({
197
212
  }
198
213
 
199
214
  // Get the route from the request
200
- let route = req.url;
201
- if (!route || route === "") route = "/";
215
+ let route = requestToRoute(req, {
216
+ moduleBasePath: handlerOptions.moduleBasePath,
217
+ build: handlerOptions.build
218
+ });
219
+ if (!route) {
220
+ return next();
221
+ }
202
222
  // in the case of the no build.pages and a async Page and or props userOption, we need to await those
203
223
  // if they are already autoDiscovered then the promise will resolve immediately
204
224
  const routeFiles = await getRouteFiles(
205
225
  route,
206
226
  autoDiscoveredFiles,
207
- userOptions
227
+ handlerOptions
208
228
  );
209
229
  if (routeFiles.type === "error") {
210
- server.config.logger.error("[react-client] Error getting route files", {
230
+ server.config.logger.error(routeFiles.error.message, {
211
231
  error: routeFiles.error,
232
+ timestamp: true,
212
233
  });
213
234
  return next();
214
235
  }
@@ -218,12 +239,8 @@ export async function configureWorkerRequestHandler({
218
239
  res.setHeader("Content-Type", "text/x-component; charset=utf-8");
219
240
  res.setHeader("Transfer-Encoding", "chunked");
220
241
  res.setHeader("Connection", "keep-alive");
221
- let timeout = setTimeout(() => {
222
- server.config.logger.error("[react-client] RSC render timeout");
223
- res.end();
224
- }, 5000);
225
242
  const serializedUserOptions = serializedOptions(
226
- userOptions,
243
+ handlerOptions,
227
244
  autoDiscoveredFiles
228
245
  );
229
246
  const stream = handleWorkerRscStream(currentWorker, {
@@ -234,37 +251,42 @@ export async function configureWorkerRequestHandler({
234
251
  propsPath: props,
235
252
  // override these at all times to ensure the settings will work for the dev server
236
253
  projectRoot: server.config.root,
237
- moduleRootPath: join(server.config.root, userOptions.moduleBase),
238
- moduleBaseURL: "",
239
- moduleBasePath: "",
240
254
  build: serializedUserOptions.build,
241
255
  manifest: autoDiscoveredFiles.staticManifest,
242
256
  cssFiles: new Map(),
243
257
  globalCss: new Map(),
244
258
  });
259
+ const writeStream = new WritableStream({
260
+ write(chunk) {
261
+ res.write(chunk);
262
+ },
245
263
 
246
- // Pipe the stream to the response
247
- stream.pipeTo(
248
- new WritableStream({
249
- write(chunk) {
250
- res.write(chunk);
251
- },
264
+ close() {
265
+ clearTimeout(timeout);
266
+ res.end();
267
+ },
268
+ abort() {
269
+ clearTimeout(timeout);
270
+ // Restart worker on error
271
+ restartWorker(
272
+ server,
273
+ autoDiscoveredFiles,
274
+ handlerOptions,
275
+ hmrChannel
276
+ );
277
+ res.end();
278
+ },
279
+ })
280
+ let timeout = setTimeout(() => {
281
+ server.config.logger.error("[react-client] RSC render timeout");
282
+ res.end();
283
+ }, 5000);
252
284
 
253
- close() {
254
- clearTimeout(timeout);
255
- res.end();
256
- },
257
- abort() {
258
- clearTimeout(timeout);
259
- // Restart worker on error
260
- restartWorker(server, autoDiscoveredFiles, userOptions, hmrChannel);
261
- res.end();
262
- },
263
- })
264
- );
285
+ // Pipe the stream to the response
286
+ stream.pipeTo(writeStream);
265
287
  } catch (error) {
266
288
  if (error instanceof Error) {
267
- server.config.logger.error("[react-client] Error handling request", {
289
+ server.config.logger.error(error.message, {
268
290
  error,
269
291
  });
270
292
  }
@@ -1,4 +1,4 @@
1
- import type { Manifest, ViteDevServer } from "vite";
1
+ import type { Manifest, ViteDevServer } from "vite";
2
2
  import type { ServerResponse } from "http";
3
3
  import type { AutoDiscoveredFiles, ResolvedUserOptions } from "../types.js";
4
4
  import { createEventHandler } from "../helpers/createEventHandler.js";
@@ -10,7 +10,7 @@ import React from "react";
10
10
  export async function configureReactServer({
11
11
  server,
12
12
  autoDiscoveredFiles,
13
- userOptions,
13
+ userOptions: _userOptions,
14
14
  serverManifest,
15
15
  }: {
16
16
  server: ViteDevServer;
@@ -20,6 +20,31 @@ export async function configureReactServer({
20
20
  }) {
21
21
  const activeStreams = new Set<ServerResponse>();
22
22
 
23
+ const {
24
+ Html: _UserHtmlComponent,
25
+ onEvent,
26
+ // remove these
27
+ moduleBaseURL: _moduleBaseURL,
28
+ moduleBasePath: _moduleBasePath,
29
+ projectRoot: _projectRoot,
30
+ ...handlerUserOptions
31
+ } = _userOptions;
32
+
33
+ const handlerOptions = Object.assign({}, handlerUserOptions, {
34
+ moduleBaseURL:
35
+ typeof server.config.server.host === "string"
36
+ ? `${server.config.server.https ? "https" : "http"}://${
37
+ server.config.server.host
38
+ }:${server.config.server.port}`
39
+ : "",
40
+ moduleBasePath:
41
+ server.config.base === "/"
42
+ ? ""
43
+ : server.config.base.endsWith("/")
44
+ ? server.config.base.slice(0, -1)
45
+ : server.config.base,
46
+ projectRoot: server.config.root,
47
+ });
23
48
  // Handle Vite server restarts
24
49
  server.ws.on("restart", (path) => {
25
50
  console.log(
@@ -41,10 +66,21 @@ export async function configureReactServer({
41
66
  server.middlewares.use(async (req, res, next) => {
42
67
  try {
43
68
  if (req.headers.accept !== "text/x-component") return next();
44
- let route = req.url?.replace('/'+userOptions.build.rscOutputPath, "");
69
+ let route = req.url?.replace("/" + handlerOptions.build.rscOutputPath, "");
70
+ if(!route?.startsWith(handlerOptions.moduleBasePath)) {
71
+ next();
72
+ } else {
73
+ route = route.slice(handlerOptions.moduleBasePath.length);
74
+ }
75
+ if(typeof route !== "string" ) {
76
+ throw new Error("req.url is not a string");
77
+ }
45
78
  if (!route || route === "") {
46
79
  route = "/";
47
80
  }
81
+ if(!route.startsWith("/")) {
82
+ route = "/" + route;
83
+ }
48
84
  if (!autoDiscoveredFiles.urlMap.has(route)) {
49
85
  return next();
50
86
  }
@@ -52,26 +88,19 @@ export async function configureReactServer({
52
88
  const pagePath = routeFiles.page;
53
89
  const propsPath = routeFiles.props;
54
90
 
55
- const {
56
- Html: _UserHtmlComponent,
57
- onEvent,
58
- // remove these
59
- moduleBaseURL,
60
- ...handlerUserOptions
61
- } = userOptions;
62
91
  // Create a unified event handler
63
92
  await server.warmupRequest(pagePath);
64
93
  const eventHandler = createEventHandler(onEvent);
65
94
  const cssFilesResult = await collectViteModuleGraphCss({
66
95
  moduleGraph: server.moduleGraph,
67
96
  pagePath,
68
- loader: (i)=>server.ssrLoadModule(i, {fixStacktrace: true}),
69
- // explicitly set to empty string, because we let vite handle the resolving during development
70
- moduleBaseURL: "",
71
- moduleBasePath: userOptions.moduleBasePath,
72
- moduleRootPath: userOptions.moduleRootPath,
73
- projectRoot: userOptions.projectRoot,
74
- css: userOptions.css,
97
+ loader: (i) => server.ssrLoadModule(i, { fixStacktrace: true }),
98
+ // explicitly set for development server
99
+ moduleBaseURL: handlerOptions.moduleBaseURL,
100
+ moduleBasePath: handlerOptions.moduleBasePath,
101
+ moduleRootPath: handlerOptions.moduleRootPath,
102
+ projectRoot: handlerOptions.projectRoot,
103
+ css: handlerOptions.css,
75
104
  parentUrl: pagePath,
76
105
  });
77
106
  if (cssFilesResult.type === "skip") {
@@ -85,8 +114,8 @@ export async function configureReactServer({
85
114
  propsPath,
86
115
  route,
87
116
  loader: server.ssrLoadModule,
88
- pageExportName: userOptions.pageExportName ?? "default",
89
- propsExportName: userOptions.propsExportName ?? "default",
117
+ pageExportName: handlerOptions.pageExportName ?? "default",
118
+ propsExportName: handlerOptions.propsExportName ?? "default",
90
119
  });
91
120
  if (pageAndPropsResult.type === "error") {
92
121
  throw pageAndPropsResult.error;
@@ -95,9 +124,9 @@ export async function configureReactServer({
95
124
  return next();
96
125
  }
97
126
  const { PageComponent, pageProps } = pageAndPropsResult;
98
- // Create the headless RSC stream directly
127
+ // Create the headless RSC stream directly;
99
128
  const rscResult = await createHandler({
100
- ...handlerUserOptions,
129
+ ...handlerOptions,
101
130
  PageComponent: PageComponent,
102
131
  pageProps: pageProps,
103
132
  logger: server.config.logger,
@@ -110,8 +139,6 @@ export async function configureReactServer({
110
139
  pagePath,
111
140
  propsPath,
112
141
  cssFiles: cssFilesResult.cssFiles ?? new Map(),
113
- // explicitly set to empty string, because we let vite handle the resolving during development
114
- moduleBaseURL: "",
115
142
  globalCss: new Map(),
116
143
  });
117
144
  if (rscResult.type === "success") {
@@ -138,6 +138,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
138
138
  timing.renderStart = Date.now();
139
139
  },
140
140
 
141
+
141
142
  async writeBundle(options, bundle) {
142
143
  try {
143
144
  const bundleManifest = getBundleManifest<false>({
@@ -158,7 +159,11 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
158
159
 
159
160
  const clientManifestResult = await tryManifest({
160
161
  root: userOptions.projectRoot,
161
- outDir: join(userOptions.build.outDir, userOptions.build.client),
162
+ outDir: join(
163
+ userOptions.build.outDir,
164
+ userOptions.build.client,
165
+ userOptions.moduleBasePath
166
+ ),
162
167
  ssrManifest: false,
163
168
  });
164
169
  if (clientManifestResult.type === "error") {
@@ -268,7 +273,16 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
268
273
  const pipeableStreamOptions = {
269
274
  ...userOptions.pipeableStreamOptions,
270
275
  bootstrapModules: [
271
- ...(indexHtml ? [new URL(indexHtml, userOptions.moduleBaseURL).href] : []),
276
+ ...(indexHtml
277
+ ? [
278
+ userOptions.moduleBaseURL !== ""
279
+ ? new URL(
280
+ join(userOptions.moduleBasePath, indexHtml),
281
+ userOptions.moduleBaseURL
282
+ ).href
283
+ : join(userOptions.moduleBasePath, indexHtml),
284
+ ]
285
+ : []),
272
286
  ...(userOptions.pipeableStreamOptions?.bootstrapModules ?? []),
273
287
  ],
274
288
  };
@@ -279,31 +293,37 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
279
293
  );
280
294
  // Create worker
281
295
  if (!worker) {
296
+ const viteEnvPrefix = typeof resolvedConfig.envPrefix === 'string' ? resolvedConfig.envPrefix : Array.isArray(resolvedConfig.envPrefix) ? resolvedConfig.envPrefix[0] : 'VITE_'
282
297
  const workerResult = await createWorker({
283
298
  projectRoot: userOptions.projectRoot,
284
299
  workerPath: userOptions.htmlWorkerPath,
285
300
  currentCondition: "react-server",
286
301
  reverseCondition: "react-client",
302
+ envPrefix: viteEnvPrefix,
287
303
  workerData: {
288
304
  resolvedConfig: serializeResolvedConfig(resolvedConfig),
289
- userOptions: serializedUserOptions,
305
+ userOptions: {
306
+ ...serializedUserOptions,
307
+ },
290
308
  },
291
309
  });
292
310
  if (workerResult.type === "error") {
293
311
  throw workerResult.error;
294
312
  } else if (workerResult.type === "skip") {
295
- this.environment.logger.info("Worker not created, skipping static build");
313
+ this.environment.logger.info(
314
+ "Worker not created, skipping static build"
315
+ );
296
316
  return;
297
317
  } else {
298
318
  worker = workerResult.worker;
299
319
  }
300
320
  }
301
321
  // Render pages
302
- const { onEvent, ...rest } = userOptions;
322
+ const { onEvent, ...handlerOptions } = userOptions;
303
323
  const renderPagesGenerator = renderPages(
304
324
  autoDiscoveredFiles!,
305
325
  {
306
- ...rest,
326
+ ...handlerOptions,
307
327
  loader: buildLoader,
308
328
  worker: worker,
309
329
  logger: createLogger(),
@@ -329,7 +349,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
329
349
  },
330
350
  globalCss: globalCss,
331
351
  },
332
- cssFilesByPage,
352
+ cssFilesByPage
333
353
  );
334
354
 
335
355
  // Process render results
@@ -344,11 +364,13 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
344
364
  if (!finalResult) {
345
365
  throw new Error("No render result produced");
346
366
  }
347
- finalResult.streamMetrics.duration = Math.round(performance.now() - finalResult.streamMetrics.startTime);
348
-
349
- this.environment.logger.info(`Rendered ${finalResult.completedRoutes.size} unique routes in ${
350
- finalResult.streamMetrics.duration
351
- }ms`);
367
+ finalResult.streamMetrics.duration = Math.round(
368
+ performance.now() - finalResult.streamMetrics.startTime
369
+ );
370
+
371
+ this.environment.logger.info(
372
+ `Rendered ${finalResult.completedRoutes.size} unique routes in ${finalResult.streamMetrics.duration}ms`
373
+ );
352
374
 
353
375
  // Update timing
354
376
  timing.render = Date.now() - (timing.renderStart ?? timing.start);
@@ -44,7 +44,6 @@ export async function* renderPage(
44
44
  } satisfies CreateHandlerOptions;
45
45
  // Create streams with CSS files
46
46
  const [rscFull, rscHeadless] = await renderStreams(newHandlerOptions);
47
-
48
47
  // Handle stream creation errors
49
48
  if (rscFull.type !== "success") {
50
49
  yield {
@@ -37,6 +37,15 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
37
37
  if (resolvedOptionsResult.type === "error") throw resolvedOptionsResult.error;
38
38
  userOptions = resolvedOptionsResult.userOptions;
39
39
  let staticManifest: Manifest;
40
+ const getID = (id: string) => {
41
+ if(userOptions.moduleBasePath !== '' && !id.startsWith(userOptions.moduleBasePath)) {
42
+ id = join(userOptions.moduleBasePath, id);
43
+ }
44
+ if(!id.startsWith('/')) {
45
+ id = '/' + id;
46
+ }
47
+ return id;
48
+ }
40
49
  return {
41
50
  name: "vite:react-server-action-transform",
42
51
  enforce: "pre",
@@ -73,13 +82,14 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
73
82
  }
74
83
  if (isServer && isBuild) {
75
84
  const [key] = userOptions.normalizer(id);
76
- id = "/" + key + ".js";
85
+ id = key + ".js";
77
86
  }
78
- const transformed = await transformModuleIfNeeded(code, id, null);
87
+ const finalID = getID(id);
88
+ const transformed = await transformModuleIfNeeded(code, finalID, null);
79
89
  if (!transformed) return null;
80
90
  return {
81
91
  code: transformed,
82
- id: id,
92
+ id: finalID,
83
93
  map: null,
84
94
  };
85
95
  },
@@ -38,6 +38,15 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
38
38
 
39
39
  let staticManifest: Manifest;
40
40
 
41
+ const getID = (id: string) => {
42
+ if(userOptions.moduleBasePath !== '' && !id.startsWith(userOptions.moduleBasePath)) {
43
+ id = join(userOptions.moduleBasePath, id);
44
+ }
45
+ if(!id.startsWith('/')) {
46
+ id = '/' + id;
47
+ }
48
+ return id;
49
+ }
41
50
  return {
42
51
  name: "vite:react-server-transform",
43
52
  enforce: "pre", // Run before Vite's transforms
@@ -59,12 +68,12 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
59
68
  if (!ssr) return null;
60
69
  if (!userOptions.autoDiscover.modulePattern(id)) return null;
61
70
  if (!code.match('"use client"')) return null;
62
-
71
+
63
72
  if (isBuild) {
64
73
  const [key, value] = userOptions.normalizer(id);
65
74
  if (staticManifest) {
66
75
  if (value in staticManifest) {
67
- id = '/' + staticManifest[value].file;
76
+ id = staticManifest[value].file
68
77
  } else {
69
78
  const hash = this.emitFile({
70
79
  id,
@@ -75,15 +84,16 @@ export function reactTransformPlugin(options: StreamPluginOptions): Plugin {
75
84
  // get fileName from hash
76
85
 
77
86
  const fileName = this.getFileName(hash);
78
- id = '/' + fileName;
87
+ id = fileName;
79
88
  }
80
89
  } else {
81
90
  throw new Error(`Client manifest not found.`);
82
91
  }
83
92
  }
93
+ const finalID = getID(id);
84
94
  const transformed = await transformModuleIfNeeded(
85
95
  code,
86
- id,
96
+ finalID,
87
97
  // Pass null for nextLoad since we don't need module loading in the plugin
88
98
  null
89
99
  );
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Worker,
3
3
  type ResourceLimits,
4
- type TransferListItem
4
+ type TransferListItem,
5
5
  } from "node:worker_threads";
6
6
  import { getMode, getNodePath } from "../config/getPaths.js";
7
7
  import { getCondition } from "../config/getCondition.js";
@@ -14,6 +14,7 @@ export type CreateWorkerOptions = {
14
14
  currentCondition?: "react-server" | "react-client";
15
15
  nodePath?: string;
16
16
  nodeOptions?: string[];
17
+ envPrefix?: string;
17
18
  mode?: "production" | "development";
18
19
  reverseCondition?: string;
19
20
  maxListeners?: number;
@@ -50,6 +51,7 @@ export async function createWorker(
50
51
  projectRoot = process.cwd(),
51
52
  nodePath = getNodePath(projectRoot),
52
53
  currentCondition = getCondition(),
54
+ envPrefix = "VITE_",
53
55
  reverseCondition = currentCondition === "react-server"
54
56
  ? "react-client"
55
57
  : "react-server",
@@ -61,7 +63,7 @@ export async function createWorker(
61
63
  maxYoungGenerationSizeMb: 64,
62
64
  },
63
65
  htmlChunkSize = 8 * 1024,
64
- transferList = []
66
+ transferList = [],
65
67
  } = options;
66
68
  let workerPathWithDefault =
67
69
  typeof workerPath === "string" ? workerPath : undefined;
@@ -78,20 +80,10 @@ export async function createWorker(
78
80
  // Ensure worker uses the same React version
79
81
  const workerData = {
80
82
  ...options.workerData,
81
- importMeta: {
82
- env: {
83
- DEV: mode === 'development' ? 'true' : 'false',
84
- MODE: mode,
85
- PROD: mode === 'production' ? 'true' : 'false',
86
- SSR: true,
87
- BASE_URL: '/',
88
- },
89
- },
90
83
  reactVersion: React.version,
91
84
  };
92
85
 
93
86
  try {
94
-
95
87
  // Ensure consistent NODE_ENV between main thread and worker
96
88
  const isTestEnv =
97
89
  process.env["VITEST"] || process.env["NODE_ENV"] === "test";
@@ -99,12 +91,17 @@ export async function createWorker(
99
91
 
100
92
  const env = {
101
93
  ...process.env,
102
- BASE_URL: '/',
103
- VITE_DEV: mode === 'development' ? '1' : '0',
104
- VITE_MODE: mode,
105
- VITE_PROD: mode === 'production' ? '1' : '0',
106
- VITE_SSR: 'true',
107
- VITE_BASE_URL: '/',
94
+ [envPrefix + "DEV"]: mode === "development" ? "1" : "0",
95
+ [envPrefix + "MODE"]: mode,
96
+ [envPrefix + "PROD"]: mode === "production" ? "1" : "0",
97
+ [envPrefix + "SSR"]: "true",
98
+ [envPrefix + "BASE"]:
99
+ options.workerData.userOptions.moduleBasePath === "" ||
100
+ options.workerData.userOptions.moduleBasePath === "/"
101
+ ? "/"
102
+ : !options.workerData.userOptions.moduleBasePath.endsWith("/")
103
+ ? options.workerData.userOptions.moduleBasePath + "/"
104
+ : options.workerData.userOptions.moduleBasePath,
108
105
  NODE_ENV: nodeEnv,
109
106
  NODE_PATH: nodePath,
110
107
  NODE_OPTIONS: process.env["NODE_OPTIONS"]?.includes(reverseCondition)
@@ -140,10 +137,12 @@ export async function createWorker(
140
137
  worker.once("message", (msg) => {
141
138
  if (msg.type === "READY") {
142
139
  clearTimeout(timeout);
143
- if(msg.env !== nodeEnv) {
140
+ if (msg.env !== nodeEnv) {
144
141
  reject({
145
142
  type: "error",
146
- error: new Error(`Worker environment mismatch: ${msg.env} !== ${nodeEnv}`),
143
+ error: new Error(
144
+ `Worker environment mismatch: ${msg.env} !== ${nodeEnv}`
145
+ ),
147
146
  workerPath: workerPathWithDefault,
148
147
  } satisfies CreateWorkerError);
149
148
  }
@@ -185,4 +184,3 @@ export async function createWorker(
185
184
  return error as CreateWorkerError;
186
185
  }
187
186
  }
188
-