vite-plugin-react-server 1.1.8 → 1.1.10

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 (163) hide show
  1. package/dist/index.js.map +1 -1
  2. package/dist/package.json +1 -1
  3. package/dist/plugin/config/defaults.d.ts +2 -1
  4. package/dist/plugin/config/defaults.d.ts.map +1 -1
  5. package/dist/plugin/config/defaults.js +3 -1
  6. package/dist/plugin/config/defaults.js.map +1 -1
  7. package/dist/plugin/config/resolveDevServerConfig.d.ts +2 -0
  8. package/dist/plugin/config/resolveDevServerConfig.d.ts.map +1 -0
  9. package/dist/plugin/config/resolveDevServerConfig.js +1 -0
  10. package/dist/plugin/config/resolveEnv.d.ts +3 -0
  11. package/dist/plugin/config/resolveEnv.d.ts.map +1 -0
  12. package/dist/plugin/config/resolveEnv.js +21 -0
  13. package/dist/plugin/config/resolveEnv.js.map +1 -0
  14. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  15. package/dist/plugin/config/resolveOptions.js +25 -9
  16. package/dist/plugin/config/resolveOptions.js.map +1 -1
  17. package/dist/plugin/config/resolveUrlOption.js.map +1 -1
  18. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  19. package/dist/plugin/config/resolveUserConfig.js +45 -52
  20. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  21. package/dist/plugin/helpers/collectManifestCss.js.map +1 -1
  22. package/dist/plugin/helpers/createCssProps.d.ts.map +1 -1
  23. package/dist/plugin/helpers/createCssProps.js +10 -2
  24. package/dist/plugin/helpers/createCssProps.js.map +1 -1
  25. package/dist/plugin/helpers/getRouteFiles.js +18 -35
  26. package/dist/plugin/helpers/inputNormalizer.d.ts +2 -1
  27. package/dist/plugin/helpers/inputNormalizer.d.ts.map +1 -1
  28. package/dist/plugin/helpers/inputNormalizer.js +34 -9
  29. package/dist/plugin/helpers/inputNormalizer.js.map +1 -1
  30. package/dist/plugin/helpers/requestInfo.d.ts +16 -0
  31. package/dist/plugin/helpers/requestInfo.d.ts.map +1 -0
  32. package/dist/plugin/helpers/requestInfo.js +66 -0
  33. package/dist/plugin/helpers/requestInfo.js.map +1 -0
  34. package/dist/plugin/helpers/requestToRoute.js +14 -22
  35. package/dist/plugin/helpers/serializeUserOptions.js.map +1 -1
  36. package/dist/plugin/loader/css-loader.development.d.ts.map +1 -1
  37. package/dist/plugin/loader/css-loader.development.js +1 -7
  38. package/dist/plugin/loader/css-loader.development.js.map +1 -1
  39. package/dist/plugin/loader/css-loader.production.js.map +1 -1
  40. package/dist/plugin/loader/react-loader.d.ts.map +1 -1
  41. package/dist/plugin/loader/react-loader.js +1 -8
  42. package/dist/plugin/loader/react-loader.js.map +1 -1
  43. package/dist/plugin/metrics/formatMetrics.d.ts +6 -1
  44. package/dist/plugin/metrics/formatMetrics.d.ts.map +1 -1
  45. package/dist/plugin/metrics/formatMetrics.js +21 -3
  46. package/dist/plugin/metrics/formatMetrics.js.map +1 -1
  47. package/dist/plugin/metrics.js +1 -1
  48. package/dist/plugin/plugin.client.js.map +1 -1
  49. package/dist/plugin/plugin.server.js.map +1 -1
  50. package/dist/plugin/preserver/plugin.js.map +1 -1
  51. package/dist/plugin/react-client/createMessageHandlers.d.ts +10 -0
  52. package/dist/plugin/react-client/createMessageHandlers.d.ts.map +1 -0
  53. package/dist/plugin/react-client/createMessageHandlers.js +36 -0
  54. package/dist/plugin/react-client/createMessageHandlers.js.map +1 -0
  55. package/dist/plugin/react-client/createWorkerStream.d.ts +3 -3
  56. package/dist/plugin/react-client/createWorkerStream.d.ts.map +1 -1
  57. package/dist/plugin/react-client/createWorkerStream.js +60 -69
  58. package/dist/plugin/react-client/createWorkerStream.js.map +1 -1
  59. package/dist/plugin/react-client/plugin.d.ts.map +1 -1
  60. package/dist/plugin/react-client/plugin.js +1 -3
  61. package/dist/plugin/react-client/plugin.js.map +1 -1
  62. package/dist/plugin/react-client/restartWorker.js +2 -2
  63. package/dist/plugin/react-client/restartWorker.js.map +1 -1
  64. package/dist/plugin/react-client/server.d.ts.map +1 -1
  65. package/dist/plugin/react-client/server.js +29 -40
  66. package/dist/plugin/react-client/server.js.map +1 -1
  67. package/dist/plugin/react-server/server.d.ts.map +1 -1
  68. package/dist/plugin/react-server/server.js +17 -19
  69. package/dist/plugin/react-server/server.js.map +1 -1
  70. package/dist/plugin/react-static/collectHtmlWorkerContent.js.map +1 -1
  71. package/dist/plugin/react-static/collectRscContent.js.map +1 -1
  72. package/dist/plugin/react-static/configurePreviewServer.d.ts.map +1 -1
  73. package/dist/plugin/react-static/configurePreviewServer.js +58 -54
  74. package/dist/plugin/react-static/configurePreviewServer.js.map +1 -1
  75. package/dist/plugin/react-static/fileWriter.js.map +1 -1
  76. package/dist/plugin/react-static/plugin.d.ts.map +1 -1
  77. package/dist/plugin/react-static/plugin.js +12 -6
  78. package/dist/plugin/react-static/plugin.js.map +1 -1
  79. package/dist/plugin/react-static/renderPages.js.map +1 -1
  80. package/dist/plugin/transformer/plugin.client.d.ts.map +1 -1
  81. package/dist/plugin/transformer/plugin.client.js +3 -12
  82. package/dist/plugin/transformer/plugin.client.js.map +1 -1
  83. package/dist/plugin/transformer/plugin.js.map +1 -1
  84. package/dist/plugin/transformer/plugin.server.d.ts.map +1 -1
  85. package/dist/plugin/transformer/plugin.server.js +17 -24
  86. package/dist/plugin/transformer/plugin.server.js.map +1 -1
  87. package/dist/plugin/types.d.ts +4 -1
  88. package/dist/plugin/types.d.ts.map +1 -1
  89. package/dist/plugin/utils/callServer.d.ts.map +1 -1
  90. package/dist/plugin/utils/callServer.js +2 -2
  91. package/dist/plugin/utils/callServer.js.map +1 -1
  92. package/dist/plugin/utils/createReactFetcher.d.ts +1 -1
  93. package/dist/plugin/utils/createReactFetcher.d.ts.map +1 -1
  94. package/dist/plugin/utils/createReactFetcher.js +6 -8
  95. package/dist/plugin/utils/createReactFetcher.js.map +1 -1
  96. package/dist/plugin/utils/env.d.ts +2 -0
  97. package/dist/plugin/utils/env.d.ts.map +1 -0
  98. package/dist/plugin/utils/env.js +9 -0
  99. package/dist/plugin/utils/env.js.map +1 -0
  100. package/dist/plugin/utils/index.d.ts +1 -0
  101. package/dist/plugin/utils/index.d.ts.map +1 -1
  102. package/dist/plugin/utils/index.js +1 -0
  103. package/dist/plugin/utils/pageURL.d.ts +4 -1
  104. package/dist/plugin/utils/pageURL.d.ts.map +1 -1
  105. package/dist/plugin/utils/pageURL.js +23 -11
  106. package/dist/plugin/utils/pageURL.js.map +1 -1
  107. package/dist/plugin/utils.js +1 -0
  108. package/dist/plugin/utils.js.map +1 -1
  109. package/dist/plugin/worker/createWorker.d.ts.map +1 -1
  110. package/dist/plugin/worker/createWorker.js +4 -3
  111. package/dist/plugin/worker/createWorker.js.map +1 -1
  112. package/dist/plugin/worker/html/createHtmlWorkerRenderState.d.ts.map +1 -1
  113. package/dist/plugin/worker/html/createHtmlWorkerRenderState.js +3 -0
  114. package/dist/plugin/worker/html/createHtmlWorkerRenderState.js.map +1 -1
  115. package/dist/plugin/worker/rsc/handleRender.d.ts +2 -7
  116. package/dist/plugin/worker/rsc/handleRender.d.ts.map +1 -1
  117. package/dist/plugin/worker/rsc/handleRender.js.map +1 -1
  118. package/dist/plugin/worker/rsc/messageHandler.d.ts.map +1 -1
  119. package/dist/plugin/worker/rsc/messageHandler.js +1 -1
  120. package/dist/plugin/worker/rsc/messageHandler.js.map +1 -1
  121. package/dist/plugin/worker/rsc/rsc-worker.development.js.map +1 -1
  122. package/dist/plugin/worker/rsc/state.d.ts.map +1 -1
  123. package/dist/plugin/worker/rsc/state.js.map +1 -1
  124. package/dist/plugin/worker/types.d.ts +6 -0
  125. package/dist/plugin/worker/types.d.ts.map +1 -1
  126. package/dist/tsconfig.tsbuildinfo +1 -1
  127. package/package.json +1 -1
  128. package/plugin/config/defaults.tsx +2 -1
  129. package/plugin/config/resolveDevServerConfig.tsx +0 -0
  130. package/plugin/config/resolveEnv.ts +37 -0
  131. package/plugin/config/resolveOptions.ts +49 -24
  132. package/plugin/config/resolveUserConfig.ts +73 -70
  133. package/plugin/helpers/createCssProps.tsx +14 -6
  134. package/plugin/helpers/inputNormalizer.ts +66 -17
  135. package/plugin/helpers/requestInfo.ts +81 -0
  136. package/plugin/loader/css-loader.development.ts +2 -8
  137. package/plugin/loader/react-loader.ts +1 -10
  138. package/plugin/metrics/formatMetrics.ts +29 -4
  139. package/plugin/preserver/plugin.ts +1 -0
  140. package/plugin/react-client/createMessageHandlers.ts +37 -0
  141. package/plugin/react-client/createWorkerStream.ts +76 -83
  142. package/plugin/react-client/plugin.ts +1 -4
  143. package/plugin/react-client/restartWorker.ts +2 -2
  144. package/plugin/react-client/server.ts +36 -62
  145. package/plugin/react-server/server.ts +17 -30
  146. package/plugin/react-static/configurePreviewServer.ts +75 -62
  147. package/plugin/react-static/plugin.ts +17 -11
  148. package/plugin/transformer/plugin.client.ts +4 -12
  149. package/plugin/transformer/plugin.server.ts +18 -25
  150. package/plugin/types.ts +12 -9
  151. package/plugin/utils/callServer.ts +20 -19
  152. package/plugin/utils/createReactFetcher.ts +6 -8
  153. package/plugin/utils/env.ts +1 -0
  154. package/plugin/utils/index.ts +2 -1
  155. package/plugin/utils/pageURL.ts +29 -24
  156. package/plugin/worker/createWorker.ts +4 -9
  157. package/plugin/worker/html/createHtmlWorkerRenderState.tsx +3 -0
  158. package/plugin/worker/rsc/handleRender.ts +2 -7
  159. package/plugin/worker/rsc/messageHandler.tsx +4 -7
  160. package/plugin/worker/rsc/rsc-worker.development.ts +1 -1
  161. package/plugin/worker/types.ts +7 -0
  162. package/dist/plugin/helpers/getRouteFiles.js.map +0 -1
  163. package/dist/plugin/helpers/requestToRoute.js.map +0 -1
@@ -6,6 +6,7 @@ import type {
6
6
  } from "../types.js";
7
7
  import { join } from "node:path";
8
8
  import type { OutputOptions, PreRenderedAsset, PreRenderedChunk } from "rollup";
9
+ import { DEFAULT_CONFIG } from "./defaults.js";
9
10
 
10
11
  let stashedUserConfig: Record<string, ResolvedUserConfig | null> = {};
11
12
 
@@ -59,21 +60,25 @@ export function resolveUserConfig({
59
60
  if (!ssr || !input) {
60
61
  return fallback(info, false);
61
62
  }
62
- const [, value] = userOptions.normalizer(
63
- input
64
- );
63
+ const [, value] = userOptions.normalizer(input);
65
64
  const entry = autoDiscoveredFiles.staticManifest[value];
66
- if(entry?.name && info.type === 'asset' && userOptions.autoDiscover.cssPattern(value)) {
67
- const withoutExt = entry.name?.split('.')[0]
68
- const found = entry.css?.find(css => css.startsWith(withoutExt as string))
69
- if(found) {
70
- return found
65
+ if (
66
+ entry?.name &&
67
+ info.type === "asset" &&
68
+ userOptions.autoDiscover.cssPattern(value)
69
+ ) {
70
+ const withoutExt = entry.name?.split(".")[0];
71
+ const found = entry.css?.find((css) =>
72
+ css.startsWith(withoutExt as string)
73
+ );
74
+ if (found) {
75
+ return found;
71
76
  } else {
72
- return entry.file
77
+ return entry.file;
73
78
  }
74
79
  }
75
80
  if (entry) {
76
- return entry.file
81
+ return entry.file;
77
82
  }
78
83
  return fallback(info, true);
79
84
  };
@@ -82,15 +87,15 @@ export function resolveUserConfig({
82
87
  ? userOptions.moduleBase
83
88
  : undefined,
84
89
  entryFileNames: (info) => {
85
- const input = info.facadeModuleId
86
- return handleSsrName(info, input, userOptions.build.entryFile, ssr);
90
+ const input = info.facadeModuleId;
91
+ return handleSsrName(info, input, userOptions.build.entryFile, ssr);
87
92
  },
88
93
  assetFileNames: (i) => {
89
- const input = i.originalFileNames[0]
94
+ const input = i.originalFileNames[0];
90
95
  return handleSsrName(i, input, userOptions.build.assetFile, ssr);
91
96
  },
92
97
  chunkFileNames: (i) => {
93
- const input = i.facadeModuleId
98
+ const input = i.facadeModuleId;
94
99
  return handleSsrName(i, input, userOptions.build.chunkFile, ssr);
95
100
  },
96
101
  format: "esm",
@@ -103,7 +108,7 @@ export function resolveUserConfig({
103
108
  config.build?.rollupOptions?.output !== null
104
109
  ? [config.build?.rollupOptions?.output, pluginOutput]
105
110
  : pluginOutput;
106
- const vitePrefix = config.envPrefix ?? "VITE_";
111
+ const vitePrefix = config.envPrefix ?? DEFAULT_CONFIG.ENV_PREFIX;
107
112
  const mode =
108
113
  process.env["NODE_ENV"] === "development"
109
114
  ? "development"
@@ -115,13 +120,55 @@ export function resolveUserConfig({
115
120
  ? "production"
116
121
  : "development";
117
122
  const minify = config.build?.minify;
123
+
124
+ const srrConfig = {
125
+ ...config.ssr,
126
+ target: config.ssr?.target ?? "node",
127
+ optimizeDeps: {
128
+ ...config.ssr?.optimizeDeps,
129
+ include: config.ssr?.optimizeDeps?.include ?? [
130
+ "react",
131
+ "react-dom",
132
+ "react-server-dom-esm/client",
133
+ ],
134
+ },
135
+ resolve: {
136
+ ...config.ssr?.resolve,
137
+ externalConditions: config.ssr?.resolve?.externalConditions ?? [
138
+ "react-server",
139
+ ],
140
+ },
141
+ };
142
+ let publicOrigin = userOptions.publicOrigin;
143
+ if (configEnv.command === "serve" && !configEnv.isPreview) {
144
+ publicOrigin = `http${config.server?.https ? "s" : ""}://${
145
+ typeof config.server?.host === "string"
146
+ ? config.server?.host
147
+ : "localhost"
148
+ }:${typeof config.server?.port === "number" ? config.server?.port : 5173}`;
149
+ }
150
+ const define = {
151
+ ...config.define,
152
+ [`import.meta.env.PUBLIC_ORIGIN`]: `"${publicOrigin}"`,
153
+ [`process.env.${vitePrefix}SSR`]: `true`,
154
+ [`process.env.${vitePrefix}DEV`]: `${
155
+ mode === "development" ? "true" : "false"
156
+ }`,
157
+ [`process.env.${vitePrefix}PROD`]: `${
158
+ mode === "production" ? "true" : "false"
159
+ }`,
160
+ [`process.env.${vitePrefix}MODE`]: `"${mode}"`,
161
+ [`process.env.${vitePrefix}BASE_URL`]: `"${userOptions.moduleBaseURL}"`,
162
+ [`process.env.${vitePrefix}PUBLIC_ORIGIN`]: `"${publicOrigin}"`,
163
+ }
164
+
118
165
  if (condition === "react-client") {
119
166
  // client plugin build options (client plugin still outputs server files)
120
167
  const clientConfig = {
121
168
  ...config,
122
169
  root: root,
123
170
  mode: mode,
124
- base: userOptions.moduleBasePath,
171
+ base: userOptions.moduleBaseURL,
125
172
  envPrefix: vitePrefix,
126
173
  resolve: {
127
174
  ...config.resolve,
@@ -131,31 +178,18 @@ export function resolveUserConfig({
131
178
  "react-server-dom-esm/client",
132
179
  ],
133
180
  },
134
- ssr: {
135
- ...config.ssr,
136
- target: config.ssr?.target ?? "node",
137
- optimizeDeps: {
138
- ...config.ssr?.optimizeDeps,
139
- include: config.ssr?.optimizeDeps?.include ?? [
140
- "react",
141
- "react-dom",
142
- "react-server-dom-esm/client",
143
- ],
144
- },
145
- resolve: {
146
- ...config.ssr?.resolve,
147
- externalConditions: config.ssr?.resolve?.externalConditions ?? [
148
- "react-server",
149
- ],
150
- },
151
- },
181
+ define: define,
182
+ ssr: srrConfig,
152
183
  // client build options
153
184
  build: {
154
185
  ...config.build,
155
186
  emptyOutDir: config.build?.emptyOutDir ?? true,
156
187
  outDir: config.build?.outDir ?? join(userOptions.build.outDir, envDir),
157
188
  assetsDir: config.build?.assetsDir ?? userOptions.build.assetsDir,
158
- copyPublicDir: typeof config.build?.copyPublicDir === "boolean" ? config.build?.copyPublicDir : !ssr,
189
+ copyPublicDir:
190
+ typeof config.build?.copyPublicDir === "boolean"
191
+ ? config.build?.copyPublicDir
192
+ : !ssr,
159
193
  // modern browsers
160
194
  target: config.build?.target ?? ["esnext"],
161
195
  minify: minify,
@@ -187,7 +221,7 @@ export function resolveUserConfig({
187
221
  ...config,
188
222
  root: root,
189
223
  mode: mode,
190
- base: userOptions.moduleBasePath,
224
+ base: userOptions.moduleBaseURL,
191
225
  envPrefix: vitePrefix,
192
226
  resolve: {
193
227
  ...config.resolve,
@@ -195,39 +229,8 @@ export function resolveUserConfig({
195
229
  "react-server",
196
230
  ],
197
231
  },
198
- define: {
199
- ...config.define,
200
- [`process.env.${vitePrefix}SSR`]: `"1"`,
201
- [`process.env.${vitePrefix}DEV`]: `"${mode === "development" ? "1" : "0"}"`,
202
- [`process.env.${vitePrefix}PROD`]: `"${mode === "production" ? "1" : "0"}"`,
203
- [`process.env.${vitePrefix}MODE`]: `"${mode}"`,
204
- [`process.env.${vitePrefix}BASE_URL`]: `"${
205
- userOptions.moduleBasePath === "" ||
206
- userOptions.moduleBasePath === "/"
207
- ? "/"
208
- : !userOptions.moduleBasePath.endsWith("/")
209
- ? userOptions.moduleBasePath + "/"
210
- : userOptions.moduleBasePath
211
- }"`,
212
- },
213
- ssr: {
214
- ...config.ssr,
215
- target: config.ssr?.target ?? "node",
216
- optimizeDeps: {
217
- ...config.ssr?.optimizeDeps,
218
- include: config.ssr?.optimizeDeps?.include ?? [
219
- "react",
220
- "react-dom",
221
- "react-server-dom-esm/client",
222
- ],
223
- },
224
- resolve: {
225
- ...config.ssr?.resolve,
226
- externalConditions: config.ssr?.resolve?.externalConditions ?? [
227
- "react-server",
228
- ],
229
- },
230
- },
232
+ define: define,
233
+ ssr: srrConfig,
231
234
  // server build options
232
235
  build: {
233
236
  ...config.build,
@@ -245,7 +248,7 @@ export function resolveUserConfig({
245
248
  copyPublicDir:
246
249
  typeof config.build?.copyPublicDir === "boolean"
247
250
  ? config.build?.copyPublicDir
248
- : false,
251
+ : !ssr,
249
252
  assetsDir: config.build?.assetsDir ?? userOptions.build.assetsDir,
250
253
  // Ensure CSS files are output to static directory
251
254
  cssCodeSplit:
@@ -76,14 +76,22 @@ export const createCssProps = ({
76
76
  : {}),
77
77
  } as CssContent<true>;
78
78
  }
79
+ const joined = normalizedId.startsWith(moduleBasePath) ? normalizedId : join(moduleBasePath, normalizedId);
80
+ const moduleBaseHasTrailingSlash = moduleBaseURL.endsWith("/");
81
+ const joinedHasLeadingSlash = joined.startsWith("/");
79
82
  const safeParseURL = (() => {
80
- try {
81
- return new URL(join(moduleBasePath, normalizedId), moduleBaseURL).href;
82
- } catch (error) {
83
- // if the url is not valid, we return the moduleBaseURL + the normalizedId
84
- // dont make it a argument of join or it will mangle something like http:// into http:/
85
- return moduleBaseURL + join(moduleBasePath, normalizedId);
83
+ if(joined.startsWith(moduleBaseHasTrailingSlash ? moduleBaseURL.slice(0, -1) : moduleBaseURL)) {
84
+ return joined;
86
85
  }
86
+ try {
87
+ if (moduleBaseURL.includes("//")) {
88
+ // relative to moduleBaseURL
89
+ return new URL(joinedHasLeadingSlash ? joined.slice(1) : joined, moduleBaseURL).href;
90
+ }
91
+ } catch (error) {}
92
+ // if the url is not valid, we return the moduleBaseURL + the normalizedId
93
+ // dont make it a argument of join or it will mangle something like http:// into http:/
94
+ return moduleBaseURL + (!moduleBaseHasTrailingSlash && !joinedHasLeadingSlash ? "/" : "") + (moduleBaseHasTrailingSlash ? joined.slice(1) : joined);
87
95
  })();
88
96
  // Default case
89
97
  return {
@@ -1,6 +1,6 @@
1
1
  import { normalizePath } from "vite";
2
2
  import type { InputNormalizer, NormalizerInput } from "../types.js";
3
- import path, { join } from "path";
3
+ import path, { join, sep } from "path";
4
4
  import { DEFAULT_CONFIG } from "../config/defaults.js";
5
5
 
6
6
  let stashedNormalizer: InputNormalizer | null = null;
@@ -9,6 +9,7 @@ type CreateInputNormalizerProps = {
9
9
  root: string;
10
10
  preserveModulesRoot?: string | undefined;
11
11
  removeExtension?: boolean | RegExp | string | ((path: string) => boolean);
12
+ moduleBasePath?: string | undefined;
12
13
  };
13
14
 
14
15
  const resolveExtensionOptions = (
@@ -55,7 +56,10 @@ const resolveRootOption = (
55
56
  return normalizedPreserveModulesRoot.slice(root.length + 1);
56
57
  }
57
58
  return "";
58
- } else if (typeof preserveModulesRoot === "string" && typeof root !== "string") {
59
+ } else if (
60
+ typeof preserveModulesRoot === "string" &&
61
+ typeof root !== "string"
62
+ ) {
59
63
  return normalizePath(preserveModulesRoot);
60
64
  }
61
65
  return "";
@@ -65,23 +69,43 @@ const createKeyNormalizer =
65
69
  root: normalizedRoot,
66
70
  preserveModulesRoot,
67
71
  handleExtension,
72
+ moduleBasePath,
68
73
  }: {
69
74
  root: string;
70
75
  preserveModulesRoot: string | undefined;
71
76
  handleExtension: (path: string) => string;
77
+ moduleBasePath: string | undefined;
72
78
  }) =>
73
79
  (key: string) => {
80
+ if (key.includes("?")) {
81
+ key = key.split("?")[0];
82
+ }
83
+
74
84
  // Handle virtual modules first
75
- const virtualPrefix = key.match(/^\0+/)?.[0] || '';
76
- const actualKey = key.slice(virtualPrefix.length);
77
-
85
+ const virtualPrefix = key.match(/^\0+/) ?? "";
86
+ const actualKey = virtualPrefix ? key.slice(virtualPrefix[0].length) : key;
87
+
78
88
  let moduleId = normalizePath(actualKey);
79
-
89
+
80
90
  // Normalize root path to handle both absolute and relative paths
81
91
  const normalizedRootPath = normalizePath(normalizedRoot);
82
92
  if (moduleId.startsWith(normalizedRootPath)) {
83
93
  moduleId = moduleId.slice(normalizedRootPath.length);
84
94
  }
95
+ if (
96
+ typeof moduleBasePath === "string" &&
97
+ moduleBasePath !== "" &&
98
+ moduleBasePath !== "/"
99
+ ) {
100
+ moduleId = moduleId.startsWith(
101
+ moduleBasePath.endsWith(sep) ? moduleBasePath : moduleBasePath + sep
102
+ )
103
+ ? moduleId.slice(
104
+ moduleBasePath.length +
105
+ (moduleBasePath.endsWith(sep) ? 0 : sep.length)
106
+ )
107
+ : moduleId;
108
+ }
85
109
 
86
110
  moduleId = handleExtension(moduleId);
87
111
  while (moduleId.startsWith("/") || moduleId.startsWith(".")) {
@@ -95,7 +119,7 @@ const createKeyNormalizer =
95
119
  ? moduleId.slice(preserveModulesRoot.length + path.sep.length)
96
120
  : moduleId;
97
121
  }
98
-
122
+
99
123
  // Add virtual prefix back
100
124
  return virtualPrefix + moduleId;
101
125
  };
@@ -104,18 +128,37 @@ const createPathNormalizer =
104
128
  ({
105
129
  root,
106
130
  preserveModulesRoot,
131
+ moduleBasePath,
107
132
  }: {
108
133
  root: string;
109
134
  preserveModulesRoot: string | undefined;
135
+ moduleBasePath: string | undefined;
110
136
  }) =>
111
137
  (path: string) => {
112
138
  if (typeof path !== "string") {
113
139
  throw new Error(`Invalid path: ${JSON.stringify(path)}`);
114
140
  }
141
+ if (path.includes("?")) {
142
+ path = path.split("?")[0];
143
+ }
115
144
  let normalPath = normalizePath(path);
116
- if(normalPath.startsWith(root)) {
145
+ if (normalPath.startsWith(root)) {
117
146
  normalPath = normalPath.slice(root.length);
118
147
  }
148
+ if (
149
+ typeof moduleBasePath === "string" &&
150
+ moduleBasePath !== "" &&
151
+ moduleBasePath !== "/"
152
+ ) {
153
+ normalPath = normalPath.startsWith(
154
+ moduleBasePath.endsWith(sep) ? moduleBasePath : moduleBasePath + sep
155
+ )
156
+ ? normalPath.slice(
157
+ moduleBasePath.length +
158
+ (moduleBasePath.endsWith(sep) ? 0 : sep.length)
159
+ )
160
+ : normalPath;
161
+ }
119
162
  if (typeof preserveModulesRoot === "string" && preserveModulesRoot !== "") {
120
163
  normalPath = normalPath.startsWith(preserveModulesRoot)
121
164
  ? normalPath.slice(preserveModulesRoot.length)
@@ -135,10 +178,11 @@ const createPathNormalizer =
135
178
  */
136
179
  export function createInputNormalizer({
137
180
  root,
181
+ moduleBasePath,
138
182
  preserveModulesRoot = undefined,
139
183
  removeExtension = DEFAULT_CONFIG.MODULE_EXTENSION,
140
184
  }: CreateInputNormalizerProps): InputNormalizer {
141
- if(stashedNormalizer) {
185
+ if (stashedNormalizer) {
142
186
  return stashedNormalizer;
143
187
  }
144
188
  const relativeRoot = resolveRootOption(root, preserveModulesRoot);
@@ -147,10 +191,12 @@ export function createInputNormalizer({
147
191
  root: root,
148
192
  preserveModulesRoot: preserveModulesRoot,
149
193
  handleExtension,
194
+ moduleBasePath,
150
195
  });
151
196
  const normalizeEntryPath = createPathNormalizer({
152
197
  root: root,
153
198
  preserveModulesRoot: relativeRoot,
199
+ moduleBasePath,
154
200
  });
155
201
  function normalizeInput(id: NormalizerInput): [string, string] {
156
202
  // Normalize both paths to use POSIX separators
@@ -185,19 +231,22 @@ export function createInputNormalizer({
185
231
  return normalized;
186
232
  }
187
233
  throw new Error(`Invalid input type: ${typeof id}`);
188
- };
234
+ }
189
235
 
190
236
  stashedNormalizer = (input: NormalizerInput): [string, string] => {
191
237
  const [key, path] = normalizeInput(input);
192
238
  // Apply the same normalization to both key and path
193
- const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
194
- const virtualPrefix = key.match(/^\0+/)?.[0] || '';
195
-
239
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
240
+ const virtualPrefix = key.match(/^\0+/) ?? "";
196
241
  // If key has virtual prefix, ensure path has it too
197
- const finalPath = virtualPrefix ?
198
- (normalizedPath.startsWith(virtualPrefix) ? normalizedPath : virtualPrefix + normalizedPath) :
199
- normalizedPath;
200
-
242
+ const finalPath = virtualPrefix
243
+ ? virtualPrefix.length && normalizedPath.startsWith(virtualPrefix[0])
244
+ ? normalizedPath
245
+ : virtualPrefix.length
246
+ ? virtualPrefix[0] + normalizedPath
247
+ : normalizedPath
248
+ : normalizedPath;
249
+
201
250
  return [key, finalPath];
202
251
  };
203
252
  return stashedNormalizer;
@@ -0,0 +1,81 @@
1
+ import { join } from "node:path";
2
+ import type { ResolvedUserOptions } from "../types.js";
3
+ import type { Connect } from "vite";
4
+ import { MIME_TYPES } from "../config/mimeTypes.js";
5
+
6
+ export function requestInfo(
7
+ req: Connect.IncomingMessage,
8
+ userOptions: Pick<ResolvedUserOptions, "normalizer" | "build" | "autoDiscover">,
9
+ hostDir: string
10
+ ) {
11
+ const [, value] = userOptions.normalizer(req.url);
12
+ const dotIndex = value.lastIndexOf(".");
13
+ const ext = dotIndex === -1 ? "" : value.slice(dotIndex);
14
+ // handle index.html
15
+ const isHtml = userOptions.autoDiscover.htmlPattern(value);
16
+ const hasHtmlHeader = req.headers.accept?.includes("text/html");
17
+ const isRsc = userOptions.autoDiscover.rscPattern(value);
18
+ const hasRscHeader = req.headers.accept?.includes("text/x-component");
19
+ const isFolder = !ext;
20
+ const isHtmlRequest =
21
+ isHtml || hasHtmlHeader || (isFolder && !hasRscHeader && !isRsc);
22
+ const isRscRequest = !isHtmlRequest && (isRsc || hasRscHeader);
23
+ const isCss = userOptions.autoDiscover.cssPattern(value);
24
+ const isCssRequest =
25
+ !isHtmlRequest &&
26
+ !isRscRequest &&
27
+ (isCss || req.headers.accept?.includes("text/css"));
28
+ let filePath = join(hostDir, value);
29
+ let contentType;
30
+ if (isHtmlRequest) {
31
+ if (!isHtml) {
32
+ filePath = join(hostDir, value, userOptions.build.htmlOutputPath);
33
+ }
34
+ contentType = "text/html; charset=utf-8";
35
+ } else if (isRscRequest) {
36
+ if (!isRsc) {
37
+ filePath = join(hostDir, value, userOptions.build.rscOutputPath);
38
+ }
39
+ contentType = "text/x-component; charset=utf-8";
40
+ } else if (isCssRequest) {
41
+ if (!isCss) {
42
+ filePath = join(hostDir, value);
43
+ }
44
+ contentType = "text/css; charset=utf-8";
45
+ } else {
46
+ const mimeType = MIME_TYPES[ext];
47
+ if (mimeType) {
48
+ contentType = mimeType;
49
+ } else {
50
+ contentType = "application/octet-stream";
51
+ }
52
+ }
53
+ const route = value
54
+ .replace(userOptions.build.rscOutputPath, "")
55
+ .replace(userOptions.build.htmlOutputPath, "");
56
+
57
+ const routeWithoutTrailingSlash =
58
+ route === "" || route === "/"
59
+ ? "/"
60
+ : route.endsWith("/")
61
+ ? route.slice(0, -1)
62
+ : route;
63
+ const routeWithLeadingSlash =
64
+ routeWithoutTrailingSlash.startsWith("/")
65
+ ? routeWithoutTrailingSlash
66
+ : `/${routeWithoutTrailingSlash}`;
67
+
68
+ return {
69
+ route: routeWithLeadingSlash,
70
+ ext,
71
+ isHtmlRequest,
72
+ isRscRequest,
73
+ isCssRequest,
74
+ isCss,
75
+ isHtml,
76
+ isRsc,
77
+ isFolder,
78
+ contentType,
79
+ filePath,
80
+ };
81
+ }
@@ -6,6 +6,7 @@ import { preprocessCSS } from "vite";
6
6
  import type { ResolvedConfig } from "vite";
7
7
  import { readFile } from "node:fs/promises";
8
8
  import { join } from "node:path";
9
+ import { env } from "../utils/env.js";
9
10
 
10
11
  /**
11
12
  * Global port for communication between the main thread and the CSS loader.
@@ -21,14 +22,7 @@ const cssFilesByPage = new Map<string, Set<string>>();
21
22
 
22
23
  let currentPage: string | null = null;
23
24
  let resolvedConfig: ResolvedConfig | undefined;
24
- // Get environment variables
25
- const env = import.meta?.env || {
26
- BASE_URL: '/',
27
- DEV: true,
28
- MODE: 'development',
29
- PROD: false,
30
- SSR: true
31
- };
25
+
32
26
 
33
27
  /**
34
28
  * Initializes the CSS loader with the necessary communication channels.
@@ -8,9 +8,9 @@ import {
8
8
  type LoadHookContext,
9
9
  type ResolveHookContext,
10
10
  } from "node:module";
11
- import { workerData } from "node:worker_threads";
12
11
  import type { MessagePort } from "node:worker_threads";
13
12
  import type { LoaderContext } from "../types.js";
13
+ import { env } from '../utils/env.js';
14
14
 
15
15
  let stashedGetSource: any = null;
16
16
  let stashedResolve: any = null;
@@ -21,15 +21,6 @@ setSourceMapsSupport(true, {
21
21
  generatedCode: true, // Enable for generated code
22
22
  });
23
23
 
24
- // Get environment variables from workerData or import.meta
25
- const env = workerData?.importMeta?.env ||
26
- import.meta?.env || {
27
- BASE_URL: "/",
28
- DEV: false,
29
- MODE: "production",
30
- PROD: true,
31
- SSR: true,
32
- };
33
24
 
34
25
  // Store port globally for use in load hook
35
26
  export let loaderPort: MessagePort | undefined;
@@ -12,7 +12,8 @@ export function formatMetrics(metrics: RenderMetrics): string {
12
12
  } = metrics;
13
13
 
14
14
  // Format memory usage in MB
15
- const formatMemory = (bytes: number) => `${(bytes / 1024 / 1024).toFixed(2)}MB`;
15
+ const formatMemory = (bytes: number) =>
16
+ `${(bytes / 1024 / 1024).toFixed(2)}MB`;
16
17
 
17
18
  return `
18
19
  Route: ${route}
@@ -32,6 +33,30 @@ Stream:
32
33
  `.trim();
33
34
  }
34
35
 
35
- export function logMetrics(metrics: RenderMetrics) {
36
- console.log(formatMetrics(metrics));
37
- }
36
+ export function metricWatcher({
37
+ maxTime = 200,
38
+ warnOnly = false,
39
+ warn = console.warn,
40
+ info = console.info,
41
+ }: {
42
+ maxTime?: number;
43
+ warnOnly?: boolean;
44
+ warn?: (...args: any[]) => void;
45
+ info?: (...args: any[]) => void;
46
+ }) {
47
+ return (metrics: RenderMetrics) => {
48
+ if (metrics.processingTime > maxTime) {
49
+ warn(`It took over ${maxTime}ms to render ${metrics.route}`);
50
+ warn(formatMetrics(metrics));
51
+ } else if (!warnOnly) {
52
+ const rounded = Math.round(metrics.processingTime);
53
+ if (rounded === 0) {
54
+ // smaller unit of time
55
+ const rounded = Math.round(metrics.processingTime * 1000);
56
+ info(`${metrics.route} (${rounded}μs)`);
57
+ } else {
58
+ info(`${metrics.route} (${rounded}ms)`);
59
+ }
60
+ }
61
+ };
62
+ }
@@ -155,3 +155,4 @@ export function reactPreservePlugin(_options: StreamPluginOptions): import("vite
155
155
  },
156
156
  };
157
157
  }
158
+
@@ -0,0 +1,37 @@
1
+ import type { RscWorkerOutputMessage } from "../worker/types.js";
2
+ import type { Logger } from "vite";
3
+ import type { StreamHandlers } from "../worker/types.js";
4
+
5
+ type MessageHandlerContext = {
6
+ handlers: StreamHandlers;
7
+ logger: Logger;
8
+ };
9
+
10
+ export function createMessageHandler({
11
+ handlers,
12
+ logger,
13
+ }: MessageHandlerContext) {
14
+ return (message: RscWorkerOutputMessage | undefined) => {
15
+ if (!message) {
16
+ logger.warn("[react-client] Received undefined message from worker");
17
+ return;
18
+ }
19
+ switch (message.type) {
20
+ case "RSC_CHUNK":
21
+ handlers.onData(message.chunk);
22
+ break;
23
+ case "RSC_END":
24
+ handlers.onEnd();
25
+ break;
26
+ case "ERROR":
27
+ handlers.onError(message.error, message.errorInfo);
28
+ break;
29
+ case "RSC_METRICS":
30
+ handlers.onMetrics(message.metrics);
31
+ break;
32
+ default:
33
+ logger.warn(`Unknown message type: ${message.type}`);
34
+ break;
35
+ }
36
+ };
37
+ }