vite-plugin-react-server 1.1.4 → 1.1.6

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 (64) 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/resolveUrlOption.d.ts +2 -2
  8. package/dist/plugin/config/resolveUrlOption.d.ts.map +1 -1
  9. package/dist/plugin/config/resolveUrlOption.js +4 -1
  10. package/dist/plugin/config/resolveUrlOption.js.map +1 -1
  11. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  12. package/dist/plugin/config/resolveUserConfig.js +10 -0
  13. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  14. package/dist/plugin/helpers/createRscStream.js +2 -1
  15. package/dist/plugin/helpers/createRscStream.js.map +1 -1
  16. package/dist/plugin/helpers/requestToRoute.d.ts +5 -0
  17. package/dist/plugin/helpers/requestToRoute.d.ts.map +1 -0
  18. package/dist/plugin/helpers/requestToRoute.js +24 -0
  19. package/dist/plugin/helpers/requestToRoute.js.map +1 -0
  20. package/dist/plugin/html.d.ts +1 -1
  21. package/dist/plugin/html.d.ts.map +1 -1
  22. package/dist/plugin/html.js +3 -2
  23. package/dist/plugin/html.js.map +1 -1
  24. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  25. package/dist/plugin/react-client/plugin.js.map +1 -1
  26. package/dist/plugin/react-client/server.d.ts +1 -1
  27. package/dist/plugin/react-client/server.d.ts.map +1 -1
  28. package/dist/plugin/react-client/server.js +51 -39
  29. package/dist/plugin/react-client/server.js.map +1 -1
  30. package/dist/plugin/react-server/server.d.ts +1 -1
  31. package/dist/plugin/react-server/server.d.ts.map +1 -1
  32. package/dist/plugin/react-server/server.js +36 -22
  33. package/dist/plugin/react-server/server.js.map +1 -1
  34. package/dist/plugin/react-static/plugin.d.ts.map +1 -1
  35. package/dist/plugin/react-static/plugin.js +24 -10
  36. package/dist/plugin/react-static/plugin.js.map +1 -1
  37. package/dist/plugin/react-static/renderPage.d.ts.map +1 -1
  38. package/dist/plugin/react-static/renderPage.js.map +1 -1
  39. package/dist/plugin/transformer/plugin.client.d.ts.map +1 -1
  40. package/dist/plugin/transformer/plugin.client.js +13 -3
  41. package/dist/plugin/transformer/plugin.client.js.map +1 -1
  42. package/dist/plugin/transformer/plugin.server.d.ts.map +1 -1
  43. package/dist/plugin/transformer/plugin.server.js +13 -3
  44. package/dist/plugin/transformer/plugin.server.js.map +1 -1
  45. package/dist/plugin/worker/createWorker.d.ts +1 -0
  46. package/dist/plugin/worker/createWorker.d.ts.map +1 -1
  47. package/dist/plugin/worker/createWorker.js +9 -16
  48. package/dist/plugin/worker/createWorker.js.map +1 -1
  49. package/dist/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +1 -1
  51. package/plugin/config/autoDiscover/resolveBuildPages.ts +1 -1
  52. package/plugin/config/resolveUrlOption.ts +19 -10
  53. package/plugin/config/resolveUserConfig.ts +18 -0
  54. package/plugin/helpers/createRscStream.tsx +2 -2
  55. package/plugin/helpers/requestToRoute.ts +23 -0
  56. package/plugin/html.tsx +2 -0
  57. package/plugin/react-client/plugin.ts +1 -0
  58. package/plugin/react-client/server.ts +62 -40
  59. package/plugin/react-server/server.ts +50 -25
  60. package/plugin/react-static/plugin.ts +30 -13
  61. package/plugin/react-static/renderPage.ts +0 -1
  62. package/plugin/transformer/plugin.client.ts +13 -3
  63. package/plugin/transformer/plugin.server.ts +14 -4
  64. package/plugin/worker/createWorker.ts +19 -21
@@ -1,29 +1,38 @@
1
- import type { ResolvedUserOptions } from '../types.js';
1
+ import type { ResolvedUserOptions } from "../types.js";
2
2
 
3
3
  type ResolvePageAndPropsOptionsSuccess<T extends "Page" | "props"> = {
4
4
  [optionName in T]: string;
5
- } & {type: "success"; error?:never}
5
+ } & { type: "success"; error?: never };
6
6
 
7
7
  type ResolvePageAndPropsOptionsError<T extends "Page" | "props"> = {
8
8
  [optionName in T]?: never;
9
- } & { type: "error"; error: Error }
9
+ } & { type: "error"; error: Error };
10
10
 
11
11
  export async function resolveUrlOption<T extends "Page" | "props">(
12
- options: Pick<ResolvedUserOptions, T>,
12
+ options: Pick<ResolvedUserOptions, T | "moduleBasePath">,
13
13
  optionName: T,
14
14
  url: string
15
- ): Promise<ResolvePageAndPropsOptionsSuccess<T> | ResolvePageAndPropsOptionsError<T>> {
15
+ ): Promise<
16
+ ResolvePageAndPropsOptionsSuccess<T> | ResolvePageAndPropsOptionsError<T>
17
+ > {
16
18
  try {
17
19
  switch (typeof options[optionName]) {
18
20
  case "function":
19
- const result = options[optionName](url);
20
- if(typeof result === "string") {
21
+ const result = options[optionName](
22
+ // quick normalization to make it easier to work with dynamic moduleBasePaths (so that you don't have to change the Page/props function)
23
+ options.moduleBasePath !== "" &&
24
+ options.moduleBasePath !== "/" &&
25
+ url.startsWith(options.moduleBasePath)
26
+ ? url.slice(options.moduleBasePath.length)
27
+ : url
28
+ );
29
+ if (typeof result === "string") {
21
30
  return { type: "success", [optionName]: result };
22
31
  }
23
- if(result instanceof Promise) {
32
+ if (result instanceof Promise) {
24
33
  try {
25
34
  const promiseResult = await result;
26
- if(typeof promiseResult === "string") {
35
+ if (typeof promiseResult === "string") {
27
36
  return { type: "success", [optionName]: promiseResult };
28
37
  }
29
38
  } catch (error) {
@@ -40,4 +49,4 @@ export async function resolveUrlOption<T extends "Page" | "props">(
40
49
  } catch (error) {
41
50
  return { type: "error", error: error as Error };
42
51
  }
43
- }
52
+ }
@@ -101,6 +101,7 @@ export function resolveUserConfig({
101
101
  ...config,
102
102
  root: root,
103
103
  mode: mode,
104
+ base: userOptions.moduleBasePath,
104
105
  resolve: {
105
106
  ...config.resolve,
106
107
  external: config.resolve?.external ?? [
@@ -160,15 +161,32 @@ export function resolveUserConfig({
160
161
  ...config,
161
162
  root: root,
162
163
  mode: mode,
164
+ base: userOptions.moduleBasePath,
163
165
  resolve: {
164
166
  ...config.resolve,
165
167
  externalConditions: config.resolve?.externalConditions ?? [
166
168
  "react-server",
167
169
  ],
168
170
  },
171
+ define: {
172
+ ...config.define,
173
+ "process.env.VITE_SSR": `"1"`,
174
+ "process.env.VITE_DEV": `"${mode === "development" ? "1" : "0"}"`,
175
+ "process.env.VITE_PROD": `"${mode === "production" ? "1" : "0"}"`,
176
+ "process.env.VITE_MODE": `"${mode}"`,
177
+ "process.env.VITE_BASE": `"${
178
+ userOptions.moduleBasePath === "" ||
179
+ userOptions.moduleBasePath === "/"
180
+ ? "/"
181
+ : !userOptions.moduleBasePath.endsWith("/")
182
+ ? userOptions.moduleBasePath + "/"
183
+ : userOptions.moduleBasePath
184
+ }"`,
185
+ },
169
186
  ssr: {
170
187
  ...config.ssr,
171
188
  target: config.ssr?.target ?? "node",
189
+
172
190
  resolve: {
173
191
  ...config.ssr?.resolve,
174
192
  externalConditions: config.ssr?.resolve?.externalConditions ?? [
@@ -1,6 +1,6 @@
1
1
  import { React, ReactDOMServer } from "../vendor.server.js";
2
2
  import type { CreateHandlerOptions, StreamMetrics } from "../types.js";
3
-
3
+ import { join } from "node:path";
4
4
  export function createRscStream<
5
5
  T,
6
6
  C extends React.ComponentType<T>,
@@ -45,7 +45,7 @@ export function createRscStream<
45
45
  const startTime = performance.now()
46
46
  const htmlIsFragment = Html == React.Fragment;
47
47
  const url =
48
- moduleBaseURL !== "" ? new URL(route, moduleBaseURL).toString() : route;
48
+ moduleBaseURL !== "" ? new URL(join(route, moduleBasePath), moduleBaseURL).toString() : route;
49
49
  let errorCount = 0;
50
50
  let streamError: Error | null = null;
51
51
 
@@ -0,0 +1,23 @@
1
+ import type { CreateHandlerOptions } from "../types.js";
2
+
3
+ export function requestToRoute(
4
+ req: {url?: string},
5
+ handlerOptions: Pick<CreateHandlerOptions, "moduleBasePath" | "build">
6
+ ) {
7
+ let route = req.url?.replace("/" + handlerOptions.build.rscOutputPath, "");
8
+ if (typeof route !== "string") {
9
+ return route;
10
+ }
11
+ if (
12
+ route.startsWith(handlerOptions.moduleBasePath)
13
+ ) {
14
+ route = route.slice(handlerOptions.moduleBasePath.length);
15
+ }
16
+ if (!route || route === "") {
17
+ route = "/";
18
+ }
19
+ if (!route.startsWith("/")) {
20
+ route = "/" + route;
21
+ }
22
+ return route;
23
+ }
package/plugin/html.tsx CHANGED
@@ -6,9 +6,11 @@ export const Html = ({
6
6
  CssCollector,
7
7
  cssFiles,
8
8
  globalCss,
9
+ moduleBasePath,
9
10
  }: React.PropsWithChildren<HtmlProps>) => (
10
11
  <html>
11
12
  <head>
13
+ {moduleBasePath !== "" && <base href={moduleBasePath} />}
12
14
  <CssCollectorElements cssFiles={globalCss} />
13
15
  </head>
14
16
  <body>
@@ -76,6 +76,7 @@ export function reactClientPlugin(options: StreamPluginOptions): Plugin {
76
76
  async configureServer(server) {
77
77
  // Create HMR message channel
78
78
  hmrChannel = new MessageChannel();
79
+
79
80
  await configureWorkerRequestHandler({
80
81
  server,
81
82
  autoDiscoveredFiles,
@@ -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,27 +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
- const moduleBasePathForDevServer = "/" + userOptions.moduleBase;
66
94
  const cssFilesResult = await collectViteModuleGraphCss({
67
95
  moduleGraph: server.moduleGraph,
68
96
  pagePath,
69
- loader: (i)=>server.ssrLoadModule(i, {fixStacktrace: true}),
70
- // explicitly set to empty string, because we let vite handle the resolving during development
71
- moduleBaseURL: "",
72
- moduleBasePath: moduleBasePathForDevServer,
73
- moduleRootPath: userOptions.moduleRootPath,
74
- projectRoot: userOptions.projectRoot,
75
- 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,
76
104
  parentUrl: pagePath,
77
105
  });
78
106
  if (cssFilesResult.type === "skip") {
@@ -86,8 +114,8 @@ export async function configureReactServer({
86
114
  propsPath,
87
115
  route,
88
116
  loader: server.ssrLoadModule,
89
- pageExportName: userOptions.pageExportName ?? "default",
90
- propsExportName: userOptions.propsExportName ?? "default",
117
+ pageExportName: handlerOptions.pageExportName ?? "default",
118
+ propsExportName: handlerOptions.propsExportName ?? "default",
91
119
  });
92
120
  if (pageAndPropsResult.type === "error") {
93
121
  throw pageAndPropsResult.error;
@@ -96,9 +124,9 @@ export async function configureReactServer({
96
124
  return next();
97
125
  }
98
126
  const { PageComponent, pageProps } = pageAndPropsResult;
99
- // Create the headless RSC stream directly
127
+ // Create the headless RSC stream directly;
100
128
  const rscResult = await createHandler({
101
- ...handlerUserOptions,
129
+ ...handlerOptions,
102
130
  PageComponent: PageComponent,
103
131
  pageProps: pageProps,
104
132
  logger: server.config.logger,
@@ -111,9 +139,6 @@ export async function configureReactServer({
111
139
  pagePath,
112
140
  propsPath,
113
141
  cssFiles: cssFilesResult.cssFiles ?? new Map(),
114
- // explicitly set to empty string, because we let vite handle the resolving during development
115
- moduleBaseURL: "",
116
- moduleBasePath: "",
117
142
  globalCss: new Map(),
118
143
  });
119
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,10 @@ 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
+ ),
162
166
  ssrManifest: false,
163
167
  });
164
168
  if (clientManifestResult.type === "error") {
@@ -268,7 +272,16 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
268
272
  const pipeableStreamOptions = {
269
273
  ...userOptions.pipeableStreamOptions,
270
274
  bootstrapModules: [
271
- ...(indexHtml ? [new URL(indexHtml, userOptions.moduleBaseURL).href] : []),
275
+ ...(indexHtml
276
+ ? [
277
+ userOptions.moduleBaseURL !== ""
278
+ ? new URL(
279
+ join(userOptions.moduleBasePath, indexHtml),
280
+ userOptions.moduleBaseURL
281
+ ).href
282
+ : join(userOptions.moduleBasePath, indexHtml),
283
+ ]
284
+ : []),
272
285
  ...(userOptions.pipeableStreamOptions?.bootstrapModules ?? []),
273
286
  ],
274
287
  };
@@ -279,34 +292,37 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
279
292
  );
280
293
  // Create worker
281
294
  if (!worker) {
295
+ const viteEnvPrefix = typeof resolvedConfig.envPrefix === 'string' ? resolvedConfig.envPrefix : Array.isArray(resolvedConfig.envPrefix) ? resolvedConfig.envPrefix[0] : 'VITE_'
282
296
  const workerResult = await createWorker({
283
297
  projectRoot: userOptions.projectRoot,
284
298
  workerPath: userOptions.htmlWorkerPath,
285
299
  currentCondition: "react-server",
286
300
  reverseCondition: "react-client",
301
+ envPrefix: viteEnvPrefix,
287
302
  workerData: {
288
303
  resolvedConfig: serializeResolvedConfig(resolvedConfig),
289
304
  userOptions: {
290
305
  ...serializedUserOptions,
291
- moduleBasePath: '',
292
306
  },
293
307
  },
294
308
  });
295
309
  if (workerResult.type === "error") {
296
310
  throw workerResult.error;
297
311
  } else if (workerResult.type === "skip") {
298
- this.environment.logger.info("Worker not created, skipping static build");
312
+ this.environment.logger.info(
313
+ "Worker not created, skipping static build"
314
+ );
299
315
  return;
300
316
  } else {
301
317
  worker = workerResult.worker;
302
318
  }
303
319
  }
304
320
  // Render pages
305
- const { onEvent, ...rest } = userOptions;
321
+ const { onEvent, ...handlerOptions } = userOptions;
306
322
  const renderPagesGenerator = renderPages(
307
323
  autoDiscoveredFiles!,
308
324
  {
309
- ...rest,
325
+ ...handlerOptions,
310
326
  loader: buildLoader,
311
327
  worker: worker,
312
328
  logger: createLogger(),
@@ -321,7 +337,6 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
321
337
  },
322
338
  pipeableStreamOptions: pipeableStreamOptions,
323
339
  manifest: serverManifest ?? {},
324
- moduleBasePath: '',
325
340
  build: {
326
341
  htmlOutputPath: userOptions.build.htmlOutputPath,
327
342
  rscOutputPath: userOptions.build.rscOutputPath,
@@ -333,7 +348,7 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
333
348
  },
334
349
  globalCss: globalCss,
335
350
  },
336
- cssFilesByPage,
351
+ cssFilesByPage
337
352
  );
338
353
 
339
354
  // Process render results
@@ -348,11 +363,13 @@ export function reactStaticPlugin(options: StreamPluginOptions): VitePlugin<{
348
363
  if (!finalResult) {
349
364
  throw new Error("No render result produced");
350
365
  }
351
- finalResult.streamMetrics.duration = Math.round(performance.now() - finalResult.streamMetrics.startTime);
352
-
353
- this.environment.logger.info(`Rendered ${finalResult.completedRoutes.size} unique routes in ${
354
- finalResult.streamMetrics.duration
355
- }ms`);
366
+ finalResult.streamMetrics.duration = Math.round(
367
+ performance.now() - finalResult.streamMetrics.startTime
368
+ );
369
+
370
+ this.environment.logger.info(
371
+ `Rendered ${finalResult.completedRoutes.size} unique routes in ${finalResult.streamMetrics.duration}ms`
372
+ );
356
373
 
357
374
  // Update timing
358
375
  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
  );