vite-plugin-react-server 1.1.15 → 1.1.17

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 (57) hide show
  1. package/dist/package.json +2 -1
  2. package/dist/plugin/config/createModuleID.d.ts +8 -0
  3. package/dist/plugin/config/createModuleID.d.ts.map +1 -0
  4. package/dist/plugin/config/createModuleID.js +33 -0
  5. package/dist/plugin/config/defaults.d.ts +5 -0
  6. package/dist/plugin/config/defaults.d.ts.map +1 -1
  7. package/dist/plugin/config/defaults.js +8 -3
  8. package/dist/plugin/config/defaults.js.map +1 -1
  9. package/dist/plugin/config/extMap.d.ts +3 -0
  10. package/dist/plugin/config/extMap.d.ts.map +1 -0
  11. package/dist/plugin/config/extMap.js +57 -0
  12. package/dist/plugin/config/extMap.js.map +1 -0
  13. package/dist/plugin/config/resolveOptions.d.ts.map +1 -1
  14. package/dist/plugin/config/resolveOptions.js +29 -26
  15. package/dist/plugin/config/resolveOptions.js.map +1 -1
  16. package/dist/plugin/config/resolveUserConfig.d.ts.map +1 -1
  17. package/dist/plugin/config/resolveUserConfig.js +23 -13
  18. package/dist/plugin/config/resolveUserConfig.js.map +1 -1
  19. package/dist/plugin/helpers/inputNormalizer.d.ts.map +1 -1
  20. package/dist/plugin/helpers/inputNormalizer.js +8 -1
  21. package/dist/plugin/helpers/inputNormalizer.js.map +1 -1
  22. package/dist/plugin/helpers/requestInfo.d.ts +2 -2
  23. package/dist/plugin/helpers/requestInfo.d.ts.map +1 -1
  24. package/dist/plugin/helpers/requestInfo.js +9 -8
  25. package/dist/plugin/helpers/requestInfo.js.map +1 -1
  26. package/dist/plugin/loader/transformModuleWithPreservedFunctions.js +0 -19
  27. package/dist/plugin/loader/transformModuleWithPreservedFunctions.js.map +1 -1
  28. package/dist/plugin/react-server/configureReactServer.js.map +1 -1
  29. package/dist/plugin/source-map/createMappingsSerializer.d.ts.map +1 -1
  30. package/dist/plugin/source-map/createMappingsSerializer.js +0 -1
  31. package/dist/plugin/source-map/readMappings.d.ts.map +1 -1
  32. package/dist/plugin/source-map/readMappings.js +0 -1
  33. package/dist/plugin/transformer/plugin.server.d.ts.map +1 -1
  34. package/dist/plugin/transformer/plugin.server.js +1 -10
  35. package/dist/plugin/transformer/plugin.server.js.map +1 -1
  36. package/dist/plugin/utils/createCallServer.d.ts.map +1 -1
  37. package/dist/plugin/utils/createCallServer.js +1 -2
  38. package/dist/plugin/utils/createCallServer.js.map +1 -1
  39. package/dist/plugin/worker/rsc/state.d.ts +0 -9
  40. package/dist/plugin/worker/rsc/state.d.ts.map +1 -1
  41. package/dist/plugin/worker/rsc/state.js.map +1 -1
  42. package/dist/tsconfig.tsbuildinfo +1 -1
  43. package/package.json +2 -1
  44. package/plugin/config/createModuleID.ts +51 -0
  45. package/plugin/config/defaults.tsx +7 -2
  46. package/plugin/config/extMap.ts +60 -0
  47. package/plugin/config/resolveOptions.ts +66 -54
  48. package/plugin/config/resolveUserConfig.ts +31 -15
  49. package/plugin/helpers/inputNormalizer.ts +19 -3
  50. package/plugin/helpers/requestInfo.ts +29 -21
  51. package/plugin/loader/transformModuleWithPreservedFunctions.ts +1 -1
  52. package/plugin/react-server/configureReactServer.ts +1 -1
  53. package/plugin/source-map/createMappingsSerializer.ts +0 -1
  54. package/plugin/source-map/readMappings.ts +0 -1
  55. package/plugin/transformer/plugin.server.ts +1 -10
  56. package/plugin/utils/createCallServer.ts +1 -2
  57. package/plugin/worker/rsc/state.ts +0 -35
@@ -0,0 +1,51 @@
1
+ import { join } from "node:path";
2
+ import { extMap } from "./extMap.js";
3
+ import type { ResolvedUserOptions } from "../types.js";
4
+
5
+ export const createDefaultModuleID = (options: {
6
+ moduleBase: ResolvedUserOptions["moduleBase"];
7
+ moduleBasePath: ResolvedUserOptions["moduleBasePath"];
8
+ autoDiscover: Pick<
9
+ ResolvedUserOptions["autoDiscover"],
10
+ | "moduleExtension"
11
+ | "jsExtension"
12
+ | "cssExtension"
13
+ | "jsonExtension"
14
+ | "htmlExtension"
15
+ | "rscExtension"
16
+ >;
17
+ build: Pick<ResolvedUserOptions["build"], "preserveModulesRoot">;
18
+ }) => {
19
+ const { moduleBase, moduleBasePath, autoDiscover } = options;
20
+ const isProd =
21
+ process.env["NODE_ENV"] === "production" ||
22
+ process.env["VITE_PROD"] === "true" ||
23
+ process.env["VITE_PROD"] === "1";
24
+ const prodModuleBase =
25
+ isProd && options.build?.preserveModulesRoot === true
26
+ ? options.moduleBase
27
+ : undefined;
28
+ const mapExtension = extMap(autoDiscover);
29
+
30
+ return (id: string) => {
31
+ if (prodModuleBase && id.startsWith(moduleBase)) {
32
+ id = id.slice(moduleBase.length);
33
+ }
34
+ if (!id.startsWith(moduleBasePath)) {
35
+ id = join(moduleBasePath, id);
36
+ }
37
+ // in the case the moduleBase comes after the base path, remove it
38
+ if (prodModuleBase && id.startsWith("/" + moduleBase)) {
39
+ id = id.slice(moduleBase.length + 1);
40
+ }
41
+ // these paths will generally start with a /, simply ensure they always do
42
+ if (!id.startsWith("/")) {
43
+ id = "/" + id;
44
+ }
45
+ if (isProd) {
46
+ // generally it will work if we just use the .js extension for modules
47
+ return mapExtension(id);
48
+ }
49
+ return id;
50
+ };
51
+ };
@@ -74,11 +74,11 @@ export const DEFAULT_CONFIG = {
74
74
  /**
75
75
  * /(\.|\/)?client(\.(m|c)?(j|t)sx?)$/ and .lowerCase()
76
76
  */
77
- clientComponents: (n: string) => /(\.|\/)?client(\.(m|c)?(j|t)sx?)$/.test(n.toLowerCase()),
77
+ clientComponents: (n: string) => /(\.|\/)?client(\.(m|c)?(j|t)sx?)?$/.test(n.toLowerCase()),
78
78
  /**
79
79
  * /(\.|\/)?server(\.(m|c)?(j|t)sx?)$/ and .lowerCase()
80
80
  */
81
- serverFunctions: (n: string) => /(\.|\/)?server(\.(m|c)?(j|t)sx?)$/.test(n.toLowerCase()),
81
+ serverFunctions: (n: string) => /(\.|\/)?server(\.(m|c)?(j|t)sx?)?$/.test(n.toLowerCase()),
82
82
  /**
83
83
  * /\.css$/
84
84
  */
@@ -133,6 +133,11 @@ export const DEFAULT_CONFIG = {
133
133
  (moduleId && DEFAULT_CONFIG.AUTO_DISCOVER.serverFunctions(moduleId)) ||
134
134
  false,
135
135
  isClientComponentCode: (code: string) => code.match(DEFAULT_CONFIG.AUTO_DISCOVER.clientDirective) !== null,
136
+ jsExtension: ".js",
137
+ cssExtension: ".css",
138
+ jsonExtension: ".json",
139
+ htmlExtension: ".html",
140
+ rscExtension: ".rsc",
136
141
 
137
142
  },
138
143
  MODULE_ID: (id: string) => id,
@@ -0,0 +1,60 @@
1
+ import type { ResolvedUserOptions } from "../types.js";
2
+ import { DEFAULT_CONFIG } from "./defaults.js";
3
+
4
+ export const extMap = (
5
+ {
6
+ moduleExtension,
7
+ jsExtension,
8
+ cssExtension,
9
+ jsonExtension,
10
+ htmlExtension,
11
+ rscExtension,
12
+ }: Pick<
13
+ ResolvedUserOptions["autoDiscover"],
14
+ | "moduleExtension"
15
+ | "jsExtension"
16
+ | "cssExtension"
17
+ | "jsonExtension"
18
+ | "htmlExtension"
19
+ | "rscExtension"
20
+ > = {
21
+ moduleExtension: DEFAULT_CONFIG.AUTO_DISCOVER.moduleExtension,
22
+ jsExtension: DEFAULT_CONFIG.AUTO_DISCOVER.jsExtension,
23
+ cssExtension: DEFAULT_CONFIG.AUTO_DISCOVER.cssExtension,
24
+ jsonExtension: DEFAULT_CONFIG.AUTO_DISCOVER.jsonExtension,
25
+ htmlExtension: DEFAULT_CONFIG.AUTO_DISCOVER.htmlExtension,
26
+ rscExtension: DEFAULT_CONFIG.AUTO_DISCOVER.rscExtension,
27
+ }
28
+ ) => {
29
+ const map = {
30
+ // should not have just .client as extension
31
+ ".client": ".client" + jsExtension,
32
+ // should not have just .server as extension
33
+ ".server": ".server" + jsExtension,
34
+ // these transform to js
35
+ ".jsx": jsExtension,
36
+ ".ts": jsExtension,
37
+ ".tsx": jsExtension,
38
+ ".mjs": jsExtension,
39
+ ".cjs": jsExtension,
40
+ ".mts": jsExtension,
41
+ ".cts": jsExtension,
42
+ ".css": cssExtension,
43
+ ".json": jsonExtension,
44
+ ".html": htmlExtension,
45
+ ".rsc": rscExtension,
46
+ // otherwise do nothing
47
+ };
48
+ return (id: string) => {
49
+ const lastDotIndex = id.lastIndexOf(".");
50
+ if (lastDotIndex === -1) {
51
+ return id + jsExtension;
52
+ }
53
+ let ext = id.slice(lastDotIndex);
54
+ let withoutExt = id.slice(0, lastDotIndex);
55
+ if (ext in map) {
56
+ return withoutExt + map[ext as keyof typeof map];
57
+ }
58
+ return id.replace(moduleExtension, jsExtension);
59
+ };
60
+ };
@@ -12,16 +12,16 @@ import { pluginRoot } from "../root.js";
12
12
  import { CssCollector } from "../components/css-collector.js";
13
13
  import { createInputNormalizer } from "../helpers/inputNormalizer.js";
14
14
  import { resolveAutoDiscoverMatcher } from "./resolveAutoDiscoverMatcher.js";
15
-
16
- /**
17
- * Ensures a path ends with .js extension
18
- */
19
- const addExtension = (path: string, extension: string = "js") => {
20
- if (path.endsWith(`.${extension}`)) return path;
21
- if (path.endsWith("/.")) return path.slice(0, -2) + "." + extension;
22
- if (path.endsWith(".")) return path + "." + extension;
23
- return path + "." + extension;
24
- };
15
+ import { extMap } from "./extMap.js";
16
+ // /**
17
+ // * Ensures a path ends with .js extension
18
+ // */
19
+ // const addExtension = (path: string, extension: string = "js") => {
20
+ // if (path.endsWith(`.${extension}`)) return path;
21
+ // if (path.endsWith("/.")) return path.slice(0, -2) + "." + extension;
22
+ // if (path.endsWith(".")) return path + "." + extension;
23
+ // return path + "." + extension;
24
+ // };
25
25
 
26
26
  /**
27
27
  * Handles search query parameters in file paths
@@ -60,8 +60,25 @@ export const resolveOptions = <
60
60
  ):
61
61
  | { type: "success"; userOptions: ResolvedUserOptions<T, InlineCSS> }
62
62
  | { type: "error"; error: Error } => {
63
+ // Module path configuration
64
+ const moduleBase =
65
+ typeof options.moduleBase === "string"
66
+ ? options.moduleBase
67
+ : DEFAULT_CONFIG.MODULE_BASE;
63
68
  // Basic configuration
64
69
  const projectRoot = options.projectRoot ?? process.cwd();
70
+
71
+ // Build options
72
+ const preserveModulesRoot =
73
+ options.build?.preserveModulesRoot ??
74
+ DEFAULT_CONFIG.BUILD.preserveModulesRoot;
75
+
76
+ const isProd =
77
+ process.env["NODE_ENV"] === "production" ||
78
+ process.env["VITE_PROD"] === "true" ||
79
+ process.env["VITE_PROD"] === "1";
80
+ const prodModuleBase = isProd && preserveModulesRoot ? moduleBase : undefined;
81
+
65
82
  const {
66
83
  pageExportName = DEFAULT_CONFIG.PAGE_EXPORT_NAME,
67
84
  propsExportName = DEFAULT_CONFIG.PROPS_EXPORT_NAME,
@@ -83,17 +100,6 @@ export const resolveOptions = <
83
100
  const assetsDir =
84
101
  options.build?.assetsDir ?? `${DEFAULT_CONFIG.CLIENT_ASSETS_DIR}`;
85
102
 
86
- // Build options
87
- const preserveModulesRoot =
88
- options.build?.preserveModulesRoot ??
89
- DEFAULT_CONFIG.BUILD.preserveModulesRoot;
90
-
91
- // Module path configuration
92
- const moduleBase =
93
- typeof options.moduleBase === "string"
94
- ? options.moduleBase
95
- : DEFAULT_CONFIG.MODULE_BASE;
96
-
97
103
  const moduleBasePath =
98
104
  typeof options.moduleBasePath === "string"
99
105
  ? options.moduleBasePath
@@ -138,16 +144,6 @@ export const resolveOptions = <
138
144
  process.env.VITE_PUBLIC_ORIGIN = publicOrigin;
139
145
  }
140
146
 
141
- const normalizer =
142
- options.normalizer ??
143
- createInputNormalizer({
144
- root: projectRoot,
145
- preserveModulesRoot:
146
- preserveModulesRoot === true ? moduleBase : undefined,
147
- removeExtension: true,
148
- moduleBasePath,
149
- });
150
-
151
147
  const moduleExtension = resolveAutoDiscoverMatcher(
152
148
  options.autoDiscover?.moduleExtension,
153
149
  DEFAULT_CONFIG.AUTO_DISCOVER.moduleExtension
@@ -183,18 +179,14 @@ export const resolveOptions = <
183
179
  const clientComponents = resolveAutoDiscoverMatcher(
184
180
  options.autoDiscover?.clientComponents,
185
181
  options.autoDiscover?.moduleExtension
186
- ? (id: string) =>
187
- moduleExtension(id.toLowerCase()) &&
188
- /(\.|\/)?client(\.|\/)/.test(id.toLowerCase())
182
+ ? (id: string) => /(\.|\/)?client(\.|\/)?/.test(id.toLowerCase())
189
183
  : DEFAULT_CONFIG.AUTO_DISCOVER.clientComponents
190
184
  );
191
185
 
192
186
  const serverFunctions = resolveAutoDiscoverMatcher(
193
187
  options.autoDiscover?.serverFunctions,
194
188
  options.autoDiscover?.moduleExtension
195
- ? (id: string) =>
196
- moduleExtension(id.toLowerCase()) &&
197
- /(\.|\/)?server(\.|\/)/.test(id.toLowerCase())
189
+ ? (id: string) => /(\.|\/)?server(\.|\/)?/.test(id.toLowerCase())
198
190
  : DEFAULT_CONFIG.AUTO_DISCOVER.serverFunctions
199
191
  );
200
192
 
@@ -268,18 +260,16 @@ export const resolveOptions = <
268
260
  : DEFAULT_CONFIG.BUILD.hash;
269
261
 
270
262
  const hashString = hashOption === "" ? "" : `-[${hashOption}]`;
271
-
272
- const addModuleExtension = (path: string) => {
273
- const isAsset =
274
- autoDiscover.cssPattern(path) || autoDiscover.jsonPattern(path);
275
- if (isAsset) {
276
- return path;
277
- }
278
- return addExtension(path);
279
- };
263
+ // const addModuleExtension = (path: string) => {
264
+ // const isAsset =
265
+ // autoDiscover.cssPattern(path) || autoDiscover.jsonPattern(path);
266
+ // if (isAsset) {
267
+ // return path;
268
+ // }
269
+ // return addExtension(path);
270
+ // };
280
271
 
281
272
  // File naming and hashing
282
-
283
273
  const hash = (n: string | null, ssr: boolean) => {
284
274
  if (!n) return "";
285
275
  if (ssr) return n;
@@ -361,9 +351,17 @@ export const resolveOptions = <
361
351
  options.autoDiscover?.modulePattern,
362
352
  jsExtension
363
353
  );
364
- return path;
354
+ return registerPath(path, options.autoDiscover?.modulePattern, jsExtension);
365
355
  };
366
356
 
357
+ const normalizer =
358
+ options.normalizer ??
359
+ createInputNormalizer({
360
+ root: projectRoot,
361
+ preserveModulesRoot: prodModuleBase,
362
+ removeExtension: true,
363
+ moduleBasePath,
364
+ });
367
365
  // File naming functions
368
366
  const entryFile = (n: PreRenderedChunk, ssr: boolean) => {
369
367
  if (vendorPattern(n.name)) {
@@ -374,11 +372,11 @@ export const resolveOptions = <
374
372
  return hash(`${n.name}${jsExtension}`, ssr);
375
373
  }
376
374
  }
377
- return hash(addModuleExtension(getOutputPath(normalizer(n.name)[0])), ssr);
375
+ return hash(getOutputPath(normalizer(n.name)[0]), ssr);
378
376
  };
379
377
 
380
378
  const chunkFile = (n: PreRenderedChunk, ssr: boolean) => {
381
- return hash(addModuleExtension(getOutputPath(normalizer(n.name)[0])), ssr);
379
+ return hash(getOutputPath(normalizer(n.name)[0]), ssr);
382
380
  };
383
381
 
384
382
  const assetFile = (n: PreRenderedAsset, ssr: boolean) => {
@@ -389,17 +387,30 @@ export const resolveOptions = <
389
387
  const assetName = normalizer(nameWithoutExtension)[0] + extension;
390
388
  return hash(getOutputPath(assetName), ssr);
391
389
  };
392
-
393
390
  const moduleID =
394
391
  typeof options.moduleID === "function"
395
392
  ? options.moduleID
396
393
  : (id: string) => {
397
-
398
- // Ensure the path starts with moduleBasePath
394
+ if (prodModuleBase && id.startsWith(prodModuleBase)) {
395
+ id = id.slice(prodModuleBase.length);
396
+ }
399
397
  if (!id.startsWith(moduleBasePath)) {
400
398
  id = join(moduleBasePath, id);
401
399
  }
402
-
400
+ // in the case the moduleBase comes after the base path, remove it
401
+ if (prodModuleBase && id.startsWith("/" + prodModuleBase)) {
402
+ id = id.slice(prodModuleBase.length + 1);
403
+ }
404
+ // these paths will generally start with a /, simply ensure they always do
405
+ if (!id.startsWith("/")) {
406
+ id = "/" + id;
407
+ }
408
+ if (isProd) {
409
+ // generally it will work if we just use the .js extension for modules
410
+ return mapExtension(id);
411
+ }
412
+ // but for extra good development workflow, we keep the path intact
413
+ // not even stripping the moduleBase or ts extensions
403
414
  return id;
404
415
  };
405
416
 
@@ -468,6 +479,7 @@ export const resolveOptions = <
468
479
  isServerFunctionCode: isServerFunctionCode,
469
480
  isClientComponentCode: isClientComponentCode,
470
481
  };
482
+ const mapExtension = extMap(autoDiscover);
471
483
  const pipeableStreamOptions = options.pipeableStreamOptions
472
484
  ? options.pipeableStreamOptions
473
485
  : {};
@@ -76,16 +76,18 @@ export function resolveUserConfig<
76
76
  if (!ssr || !input) {
77
77
  return fallback(info, false);
78
78
  }
79
- const [, value] = userOptions.normalizer(input);
79
+ let [id, value] = userOptions.normalizer(input);
80
+ if (value.startsWith(userOptions.moduleBasePath)) {
81
+ value = value.slice(userOptions.moduleBasePath.length);
82
+ }
80
83
  const entry = autoDiscoveredFiles.staticManifest[value];
81
84
  if (
82
85
  entry?.name &&
83
86
  info.type === "asset" &&
84
87
  userOptions.autoDiscover.cssPattern(value)
85
88
  ) {
86
- const withoutExt = entry.name?.split(".")[0];
87
89
  const found = entry.css?.find((css) =>
88
- css.startsWith(withoutExt as string)
90
+ css.startsWith(id as string)
89
91
  );
90
92
  if (found) {
91
93
  return found;
@@ -136,8 +138,11 @@ export function resolveUserConfig<
136
138
  entryFileNames:
137
139
  userDefinedEntryFileNames ??
138
140
  ((info) => {
139
- const input = info.facadeModuleId ?? (info.name + userOptions.autoDiscover.moduleExtension);
140
- if (!stashedReturns[input]) {
141
+ const input =
142
+ info.facadeModuleId ??
143
+ info.name + userOptions.autoDiscover.moduleExtension;
144
+ const inputId = input + (ssr ? "-ssr" : "");
145
+ if (!stashedReturns[inputId]) {
141
146
  const r = handleSsrName(
142
147
  info,
143
148
  input,
@@ -147,38 +152,49 @@ export function resolveUserConfig<
147
152
  if (userOptions.verbose) {
148
153
  console.log("entryFileNames", input, r);
149
154
  }
150
- stashedReturns[input] = r;
155
+ stashedReturns[inputId] = r;
151
156
  }
152
- return stashedReturns[input];
157
+ return stashedReturns[inputId];
153
158
  }),
154
159
  assetFileNames: process.env["VITEST"]
155
160
  ? undefined
156
161
  : userDefinedAssetFileNames ??
157
162
  ((i) => {
158
163
  const input = i.originalFileNames[0];
159
- if (!stashedReturns[input]) {
164
+ const inputId = input + (ssr ? "-ssr" : "");
165
+
166
+ if (!stashedReturns[inputId]) {
160
167
  const r = handleSsrName(i, input, userOptions.build.assetFile, ssr);
161
168
 
162
169
  if (userOptions.verbose) {
163
170
  console.log("assetFileNames", input, stashedReturns[input]);
164
171
  }
165
- stashedReturns[input] = r;
172
+ stashedReturns[inputId] = r;
166
173
  }
167
- return stashedReturns[input];
174
+ return stashedReturns[inputId];
168
175
  }),
169
176
  chunkFileNames:
170
177
  userDefinedChunkFileNames ??
171
178
  ((info) => {
172
- const input = info.facadeModuleId ?? (info.name + userOptions.autoDiscover.moduleExtension);
173
- if (!stashedReturns[input]) {
174
- const r = handleSsrName(info, input, userOptions.build.chunkFile, ssr);
179
+ const input =
180
+ info.facadeModuleId ??
181
+ info.name + userOptions.autoDiscover.moduleExtension;
182
+ const inputId = input + (ssr ? "-ssr" : "");
183
+
184
+ if (!stashedReturns[inputId]) {
185
+ const r = handleSsrName(
186
+ info,
187
+ input,
188
+ userOptions.build.chunkFile,
189
+ ssr
190
+ );
175
191
 
176
192
  if (userOptions.verbose) {
177
193
  console.log("chunkFileNames", input, stashedReturns[input]);
178
194
  }
179
- stashedReturns[input] = r;
195
+ stashedReturns[inputId] = r;
180
196
  }
181
- return stashedReturns[input];
197
+ return stashedReturns[inputId];
182
198
  }),
183
199
  format: "esm",
184
200
  exports: "named",
@@ -1,18 +1,26 @@
1
1
  import { normalizePath } from "vite";
2
- import type { CreateInputNormalizerProps, InputNormalizer, NormalizerInput } from "../types.js";
2
+ import type {
3
+ CreateInputNormalizerProps,
4
+ InputNormalizer,
5
+ NormalizerInput,
6
+ } from "../types.js";
3
7
  import path, { join, sep } from "path";
4
8
  import { DEFAULT_CONFIG } from "../config/defaults.js";
5
9
 
6
10
  let stashedNormalizer: InputNormalizer | null = null;
7
11
 
8
-
9
12
  const resolveExtensionOptions = (
10
13
  removeExtension: CreateInputNormalizerProps["removeExtension"]
11
14
  ) => {
12
15
  if (typeof removeExtension === "boolean") {
13
16
  if (removeExtension) {
14
17
  return (path: string) => {
18
+ // if extension is client or server, don't remove it
19
+ if (path.endsWith(".client") || path.endsWith(".server")) {
20
+ return path;
21
+ }
15
22
  const extensionIndex = path.lastIndexOf(".");
23
+
16
24
  return extensionIndex !== -1 ? path.slice(0, extensionIndex) : path;
17
25
  };
18
26
  }
@@ -27,6 +35,9 @@ const resolveExtensionOptions = (
27
35
  }
28
36
  if (typeof removeExtension === "function") {
29
37
  return (path: string) => {
38
+ if (path.endsWith(".client") || path.endsWith(".server")) {
39
+ return path;
40
+ }
30
41
  const extIndex = path.lastIndexOf(".");
31
42
  if (extIndex !== -1) {
32
43
  const extension = path.slice(extIndex);
@@ -230,7 +241,12 @@ export function createInputNormalizer({
230
241
 
231
242
  stashedNormalizer = (input: NormalizerInput): [string, string] => {
232
243
  const [key, path] = normalizeInput(input);
233
- const normalizedPath = path.startsWith(moduleBasePath) ? path.slice(moduleBasePath.length) : path;
244
+ let normalizedPath = path.startsWith(moduleBasePath)
245
+ ? path.slice(moduleBasePath.length)
246
+ : path;
247
+ normalizedPath = normalizedPath.startsWith("/")
248
+ ? normalizedPath.slice(1)
249
+ : normalizedPath;
234
250
  const virtualPrefix = key.match(/^\0+/) ?? "";
235
251
  // If key has virtual prefix, ensure path has it too
236
252
  const finalPath = virtualPrefix
@@ -42,13 +42,39 @@ export function requestInfo(
42
42
  const hasRscHeader = req.headers.accept?.includes("text/x-component");
43
43
  const hasCssHeader = req.headers.accept?.includes("text/css");
44
44
  const isFolder = !ext;
45
+ const isFormContentType =
46
+ req.headers["content-type"]?.includes(
47
+ "application/x-www-form-urlencoded"
48
+ ) || !!req.headers["content-type"]?.includes("multipart/form-data");
49
+
50
+ // Server action detection
51
+ const hasServerActionHeaders =
52
+ req.method === "POST" &&
53
+ (req.headers["sec-fetch-dest"] === "empty" ||
54
+ req.headers["sec-fetch-dest"] === "") &&
55
+ req.headers["sec-fetch-mode"] === "cors";
56
+ const isServerActionRequest = hasServerActionHeaders;
57
+
58
+ const isFormActionRequest = !isServerActionRequest && (
59
+ req.method === "POST" ||
60
+ (isFormContentType &&
61
+ req.headers["sec-fetch-dest"] === "document" &&
62
+ req.headers["sec-fetch-mode"] === "navigate")
63
+ );
64
+
45
65
  const isJsRequest =
46
- !isJson && !isHtml && !isCss && !isRsc && (isJS || hasJsHeader);
66
+ !isFormActionRequest && !isJson && !isHtml && !isCss && !isRsc && (isJS || hasJsHeader);
47
67
  const isJsonRequest = isJson || (hasJsonHeader && !isJsRequest);
68
+ // Form action detection
69
+
48
70
  const isHtmlRequest =
49
71
  isHtml ||
50
72
  hasHtmlHeader ||
51
- (isFolder && !hasRscHeader && !isRsc && !isJsRequest);
73
+ (isFolder &&
74
+ !hasRscHeader &&
75
+ !isRsc &&
76
+ !isJsRequest &&
77
+ !isFormActionRequest);
52
78
  const isRscRequest =
53
79
  !isJsRequest && !isHtmlRequest && (isRsc || hasRscHeader);
54
80
  const isCssRequest =
@@ -58,24 +84,6 @@ export function requestInfo(
58
84
  !isJsonRequest &&
59
85
  (isCss || hasCssHeader);
60
86
 
61
- // Form action detection
62
- const formContentType = req.headers["content-type"] ?? "";
63
- const isFormContentType =
64
- formContentType.includes("application/x-www-form-urlencoded") ||
65
- formContentType.includes("multipart/form-data");
66
- const isFormActionRequest =
67
- isFormContentType &&
68
- req.headers["sec-fetch-dest"] === "document" &&
69
- req.headers["sec-fetch-mode"] === "navigate";
70
-
71
- // Server action detection
72
- const hasServerActionHeaders =
73
- isJsonRequest &&
74
- (req.headers["sec-fetch-dest"] === "empty" ||
75
- req.headers["sec-fetch-dest"] === "") &&
76
- req.headers["sec-fetch-mode"] === "cors";
77
- const isServerActionRequest = hasServerActionHeaders;
78
-
79
87
  let filePath = join(hostDir, value);
80
88
  let contentType;
81
89
  if (isServerActionRequest) {
@@ -143,7 +151,7 @@ export function requestInfo(
143
151
  } else if (isHtmlRequest) {
144
152
  logger.info(`[react-dev-server] (html) ${routeWithLeadingSlash}`);
145
153
  } else if (isRscRequest) {
146
- logger.info(`[react-dev-server] (rsc.) ${routeWithLeadingSlash}`);
154
+ logger.info(`[react-dev-server] (rsc) ${routeWithLeadingSlash}`);
147
155
  } else if (isCssRequest) {
148
156
  logger.info(`[react-dev-server] (css) ${routeWithLeadingSlash}`);
149
157
  } else if (isJsRequest) {
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { handleExports } from "./handleExports.js";
20
20
  import type { Program } from "./types.js";
21
- import createMappingsSerializer from "webpack-sources/lib/helpers/createMappingsSerializer.js";
21
+ import { createMappingsSerializer } from "../source-map/createMappingsSerializer.js";
22
22
 
23
23
  export interface TransformOptions {
24
24
  id: string;
@@ -85,11 +85,11 @@ export async function configureReactServer<
85
85
  }
86
86
  const info = requestInfo(req, handlerOptions, "", server.config.logger);
87
87
 
88
+
88
89
  // Handle server actions
89
90
  if (info.isServerActionRequest) {
90
91
  return handleServerAction(req, res, server, handlerOptions);
91
92
  }
92
-
93
93
  if (!info.isRscRequest) return next();
94
94
  try {
95
95
  const routeFiles = await getRouteFiles(
@@ -1,5 +1,4 @@
1
1
  // alternative to webpack-sources/lib/helpers/createMappingsSerializer.js
2
- // unused for now, but it's a dependency of react-server-dom-esm and you may or may not want to download webpack-sources
3
2
  export function createMappingsSerializer() {
4
3
  let generatedLine = 1;
5
4
  let generatedColumn = 0;
@@ -1,5 +1,4 @@
1
1
  // alternative to webpack-sources/lib/helpers/readMappings.js
2
- // unused for now, but it's a dependency of react-server-dom-esm and you may or may not want to download webpack-sources
3
2
  export function readMappings(
4
3
  mappings: string,
5
4
  onMapping: (
@@ -100,21 +100,12 @@ export function reactTransformPlugin<
100
100
  if (!options?.ssr || !userOptions.autoDiscover.modulePattern(id)) {
101
101
  return null;
102
102
  }
103
- const [key, value] = userOptions.normalizer(id);
103
+ const [, value] = userOptions.normalizer(id);
104
104
  let moduleID = value;
105
105
  if (isBuild) {
106
106
  if (staticManifest) {
107
107
  if (value in staticManifest) {
108
108
  moduleID = staticManifest[value].file;
109
- } else {
110
- const hash = this.emitFile({
111
- id,
112
- type: "chunk",
113
- fileName: key + ".js",
114
- name: value,
115
- });
116
- const fileName = this.getFileName(hash);
117
- moduleID = fileName;
118
109
  }
119
110
  } else {
120
111
  throw new Error(`Static manifest not found during dev build.`);
@@ -19,8 +19,7 @@ export const createCallServer = (moduleBaseURL: string) => {
19
19
  args
20
20
  }),
21
21
  headers: {
22
- Accept: "application/json",
23
- "Content-Type": "application/json",
22
+ Accept: "text/x-component",
24
23
  },
25
24
  }),
26
25
  { callServer, moduleBaseURL }