@react-router/dev 0.0.0-experimental-701a32801 → 0.0.0-experimental-b571356c3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # `@react-router/dev`
2
2
 
3
+ ## 7.5.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - `react-router@7.5.3`
9
+ - `@react-router/node@7.5.3`
10
+ - `@react-router/serve@7.5.3`
11
+
3
12
  ## 7.5.2
4
13
 
5
14
  ### Patch Changes
package/dist/cli/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * @react-router/dev v0.0.0-experimental-701a32801
3
+ * @react-router/dev v0.0.0-experimental-b571356c3
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
@@ -143,6 +143,15 @@ async function createContext({
143
143
  optimizeDeps: {
144
144
  noDiscovery: true
145
145
  },
146
+ css: {
147
+ // This empty PostCSS config object prevents the PostCSS config file from
148
+ // being loaded. We don't need it in a React Router config context, and
149
+ // there's also an issue in Vite 5 when using a .ts PostCSS config file in
150
+ // an ESM project: https://github.com/vitejs/vite/issues/15869. Consumers
151
+ // can work around this in their own Vite config file, but they can't
152
+ // configure this internal usage of vite-node.
153
+ postcss: {}
154
+ },
146
155
  configFile: false,
147
156
  envFile: false,
148
157
  plugins: []
@@ -339,12 +348,17 @@ async function resolveConfig({
339
348
  serverModuleFormat: "esm",
340
349
  ssr: true
341
350
  };
351
+ let userAndPresetConfigs = mergeReactRouterConfig(
352
+ ...presets,
353
+ reactRouterUserConfig
354
+ );
342
355
  let {
343
356
  appDirectory: userAppDirectory,
344
357
  basename: basename2,
345
358
  buildDirectory: userBuildDirectory,
346
359
  buildEnd,
347
360
  prerender,
361
+ routeDiscovery: userRouteDiscovery,
348
362
  serverBuildFile,
349
363
  serverBundles,
350
364
  serverModuleFormat,
@@ -352,7 +366,7 @@ async function resolveConfig({
352
366
  } = {
353
367
  ...defaults,
354
368
  // Default values should be completely overridden by user/preset config, not merged
355
- ...mergeReactRouterConfig(...presets, reactRouterUserConfig)
369
+ ...userAndPresetConfigs
356
370
  };
357
371
  if (!ssr && serverBundles) {
358
372
  serverBundles = void 0;
@@ -363,6 +377,32 @@ async function resolveConfig({
363
377
  "The `prerender` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths"
364
378
  );
365
379
  }
380
+ let routeDiscovery;
381
+ if (userRouteDiscovery == null) {
382
+ if (ssr) {
383
+ routeDiscovery = {
384
+ mode: "lazy",
385
+ manifestPath: "/__manifest"
386
+ };
387
+ } else {
388
+ routeDiscovery = { mode: "initial" };
389
+ }
390
+ } else if (userRouteDiscovery.mode === "initial") {
391
+ routeDiscovery = userRouteDiscovery;
392
+ } else if (userRouteDiscovery.mode === "lazy") {
393
+ if (!ssr) {
394
+ return err(
395
+ 'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`'
396
+ );
397
+ }
398
+ let { manifestPath } = userRouteDiscovery;
399
+ if (manifestPath != null && !manifestPath.startsWith("/")) {
400
+ return err(
401
+ 'The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")'
402
+ );
403
+ }
404
+ routeDiscovery = userRouteDiscovery;
405
+ }
366
406
  let appDirectory = import_pathe3.default.resolve(root, userAppDirectory || "app");
367
407
  let buildDirectory = import_pathe3.default.resolve(root, userBuildDirectory);
368
408
  let rootRouteFile = findEntry(appDirectory, "root");
@@ -430,6 +470,7 @@ async function resolveConfig({
430
470
  future,
431
471
  prerender,
432
472
  routes: routes2,
473
+ routeDiscovery,
433
474
  serverBuildFile,
434
475
  serverBundles,
435
476
  serverModuleFormat,
@@ -442,12 +483,13 @@ async function resolveConfig({
442
483
  }
443
484
  async function createConfigLoader({
444
485
  rootDirectory: root,
445
- watch: watch2
486
+ watch: watch2,
487
+ mode
446
488
  }) {
447
489
  root = root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
448
490
  let viteNodeContext = await createContext({
449
491
  root,
450
- mode: watch2 ? "development" : "production"
492
+ mode
451
493
  });
452
494
  let reactRouterConfigFile = findEntry(root, "react-router.config", {
453
495
  absolute: true
@@ -523,9 +565,13 @@ async function createConfigLoader({
523
565
  }
524
566
  };
525
567
  }
526
- async function loadConfig({ rootDirectory }) {
568
+ async function loadConfig({
569
+ rootDirectory,
570
+ mode
571
+ }) {
527
572
  let configLoader = await createConfigLoader({
528
573
  rootDirectory,
574
+ mode,
529
575
  watch: false
530
576
  });
531
577
  let config = await configLoader.getConfig();
@@ -533,13 +579,24 @@ async function loadConfig({ rootDirectory }) {
533
579
  return config;
534
580
  }
535
581
  function findEntry(dir, basename2, options) {
536
- for (let ext of entryExts) {
537
- let file = import_pathe3.default.resolve(dir, basename2 + ext);
538
- if (import_node_fs.default.existsSync(file)) {
539
- return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
582
+ let currentDir = import_pathe3.default.resolve(dir);
583
+ let { root } = import_pathe3.default.parse(currentDir);
584
+ while (true) {
585
+ for (let ext of options?.extensions ?? entryExts) {
586
+ let file = import_pathe3.default.resolve(currentDir, basename2 + ext);
587
+ if (import_node_fs.default.existsSync(file)) {
588
+ return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
589
+ }
590
+ }
591
+ if (!options?.walkParents) {
592
+ return void 0;
540
593
  }
594
+ let parentDir = import_pathe3.default.dirname(currentDir);
595
+ if (currentDir === root || parentDir === currentDir) {
596
+ return void 0;
597
+ }
598
+ currentDir = parentDir;
541
599
  }
542
- return void 0;
543
600
  }
544
601
  var import_node_fs, import_node_child_process, import_package_json, import_pathe3, import_chokidar, import_picocolors, import_pick2, import_omit, import_cloneDeep, import_isEqual, excludedConfigPresetKeys, mergeReactRouterConfig, deepFreeze, entryExts;
545
602
  var init_config = __esm({
@@ -808,12 +865,12 @@ var init_generate = __esm({
808
865
  });
809
866
 
810
867
  // typegen/index.ts
811
- async function run(rootDirectory) {
812
- const ctx = await createContext2({ rootDirectory, watch: false });
868
+ async function run(rootDirectory, { mode }) {
869
+ const ctx = await createContext2({ rootDirectory, mode, watch: false });
813
870
  await writeAll(ctx);
814
871
  }
815
- async function watch(rootDirectory, { logger } = {}) {
816
- const ctx = await createContext2({ rootDirectory, watch: true });
872
+ async function watch(rootDirectory, { mode, logger }) {
873
+ const ctx = await createContext2({ rootDirectory, mode, watch: true });
817
874
  await writeAll(ctx);
818
875
  logger?.info(import_picocolors3.default.green("generated types"), { timestamp: true, clear: true });
819
876
  ctx.configLoader.onChange(async ({ result, routeConfigChanged }) => {
@@ -836,9 +893,10 @@ async function watch(rootDirectory, { logger } = {}) {
836
893
  }
837
894
  async function createContext2({
838
895
  rootDirectory,
839
- watch: watch2
896
+ watch: watch2,
897
+ mode
840
898
  }) {
841
- const configLoader = await createConfigLoader({ rootDirectory, watch: watch2 });
899
+ const configLoader = await createConfigLoader({ rootDirectory, mode, watch: watch2 });
842
900
  const configResult = await configLoader.getConfig();
843
901
  if (!configResult.ok) {
844
902
  throw new Error(configResult.error);
@@ -875,18 +933,21 @@ function register(ctx) {
875
933
  }
876
934
  `;
877
935
  const { t: t2 } = babel_exports;
878
- const indexPaths = new Set(
879
- Object.values(ctx.config.routes).filter((route) => route.index).map((route) => route.path)
880
- );
936
+ const fullpaths = {};
937
+ for (const route of Object.values(ctx.config.routes)) {
938
+ if (route.id !== "root" && !route.path) continue;
939
+ const lineage2 = lineage(ctx.config.routes, route);
940
+ const fullpath2 = fullpath(lineage2);
941
+ const existing = fullpaths[fullpath2];
942
+ if (!existing || existing.length < lineage2.length) {
943
+ fullpaths[fullpath2] = lineage2;
944
+ }
945
+ }
881
946
  const typeParams = t2.tsTypeAliasDeclaration(
882
947
  t2.identifier("Params"),
883
948
  null,
884
949
  t2.tsTypeLiteral(
885
- Object.values(ctx.config.routes).map((route) => {
886
- if (route.id !== "root" && !route.path) return void 0;
887
- if (!route.index && indexPaths.has(route.path)) return void 0;
888
- const lineage2 = lineage(ctx.config.routes, route);
889
- const fullpath2 = fullpath(lineage2);
950
+ Object.keys(fullpaths).map((fullpath2) => {
890
951
  const params = parse2(fullpath2);
891
952
  return t2.tsPropertySignature(
892
953
  t2.stringLiteral(fullpath2),
@@ -903,7 +964,7 @@ function register(ctx) {
903
964
  )
904
965
  )
905
966
  );
906
- }).filter((x) => x !== void 0)
967
+ })
907
968
  )
908
969
  );
909
970
  return [register2, generate(typeParams).code].join("\n\n");
@@ -933,6 +994,7 @@ var init_typegen = __esm({
933
994
  export const isSpaMode: ServerBuild["isSpaMode"];
934
995
  export const prerender: ServerBuild["prerender"];
935
996
  export const publicPath: ServerBuild["publicPath"];
997
+ export const routeDiscovery: ServerBuild["routeDiscovery"];
936
998
  export const routes: ServerBuild["routes"];
937
999
  export const ssr: ServerBuild["ssr"];
938
1000
  export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
@@ -1257,8 +1319,9 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
1257
1319
  ""
1258
1320
  ) : null;
1259
1321
  let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
1322
+ let assetsDir = (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.assetsDir : null) ?? viteUserConfig?.build?.assetsDir ?? "assets";
1260
1323
  return path7.posix.join(
1261
- (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.assetsDir : viteUserConfig?.build?.assetsDir) ?? "assets",
1324
+ assetsDir,
1262
1325
  `[name]${routeChunkSuffix}-[hash].js`
1263
1326
  );
1264
1327
  }
@@ -1412,7 +1475,10 @@ __export(build_exports, {
1412
1475
  async function build(root, viteBuildOptions) {
1413
1476
  await preloadVite();
1414
1477
  let vite2 = getVite();
1415
- let configResult = await loadConfig({ rootDirectory: root });
1478
+ let configResult = await loadConfig({
1479
+ rootDirectory: root,
1480
+ mode: viteBuildOptions.mode ?? "production"
1481
+ });
1416
1482
  if (!configResult.ok) {
1417
1483
  throw new Error(configResult.error);
1418
1484
  }
@@ -1738,9 +1804,12 @@ function transpile(tsx, options = {}) {
1738
1804
  init_profiler();
1739
1805
  init_typegen();
1740
1806
  init_vite();
1741
- async function routes(reactRouterRoot, flags = {}) {
1742
- let rootDirectory = reactRouterRoot ?? process.cwd();
1743
- let configResult = await loadConfig({ rootDirectory });
1807
+ async function routes(rootDirectory, flags = {}) {
1808
+ rootDirectory = resolveRootDirectory(rootDirectory, flags);
1809
+ let configResult = await loadConfig({
1810
+ rootDirectory,
1811
+ mode: flags.mode ?? "production"
1812
+ });
1744
1813
  if (!configResult.ok) {
1745
1814
  console.error(import_picocolors7.default.red(configResult.error));
1746
1815
  process.exit(1);
@@ -1749,9 +1818,7 @@ async function routes(reactRouterRoot, flags = {}) {
1749
1818
  console.log(formatRoutes(configResult.value.routes, format));
1750
1819
  }
1751
1820
  async function build2(root, options = {}) {
1752
- if (!root) {
1753
- root = process.env.REACT_ROUTER_ROOT || process.cwd();
1754
- }
1821
+ root = resolveRootDirectory(root, options);
1755
1822
  let { build: build3 } = await Promise.resolve().then(() => (init_build(), build_exports));
1756
1823
  if (options.profile) {
1757
1824
  await start();
@@ -1768,6 +1835,7 @@ async function dev2(root, options = {}) {
1768
1835
  await start();
1769
1836
  }
1770
1837
  (0, import_exit_hook.default)(() => stop(console.info));
1838
+ root = resolveRootDirectory(root, options);
1771
1839
  await dev3(root, options);
1772
1840
  await new Promise(() => {
1773
1841
  });
@@ -1779,14 +1847,17 @@ var conjunctionListFormat = new Intl.ListFormat("en", {
1779
1847
  style: "long",
1780
1848
  type: "conjunction"
1781
1849
  });
1782
- async function generateEntry(entry, reactRouterRoot, flags = {}) {
1850
+ async function generateEntry(entry, rootDirectory, flags = {}) {
1783
1851
  if (!entry) {
1784
- await generateEntry("entry.client", reactRouterRoot, flags);
1785
- await generateEntry("entry.server", reactRouterRoot, flags);
1852
+ await generateEntry("entry.client", rootDirectory, flags);
1853
+ await generateEntry("entry.server", rootDirectory, flags);
1786
1854
  return;
1787
1855
  }
1788
- let rootDirectory = reactRouterRoot ?? process.cwd();
1789
- let configResult = await loadConfig({ rootDirectory });
1856
+ rootDirectory = resolveRootDirectory(rootDirectory, flags);
1857
+ let configResult = await loadConfig({
1858
+ rootDirectory,
1859
+ mode: flags.mode ?? "production"
1860
+ });
1790
1861
  if (!configResult.ok) {
1791
1862
  console.error(import_picocolors7.default.red(configResult.error));
1792
1863
  return;
@@ -1841,6 +1912,12 @@ async function generateEntry(entry, reactRouterRoot, flags = {}) {
1841
1912
  )
1842
1913
  );
1843
1914
  }
1915
+ function resolveRootDirectory(root, flags) {
1916
+ if (root) {
1917
+ return path8.resolve(root);
1918
+ }
1919
+ return process.env.REACT_ROUTER_ROOT || (flags?.config ? path8.dirname(path8.resolve(flags.config)) : process.cwd());
1920
+ }
1844
1921
  async function checkForEntry(rootDirectory, appDirectory, entries2) {
1845
1922
  for (let entry of entries2) {
1846
1923
  let entryPath = path8.resolve(appDirectory, entry);
@@ -1863,17 +1940,22 @@ async function createClientEntry(rootDirectory, appDirectory, inputFile) {
1863
1940
  return contents;
1864
1941
  }
1865
1942
  async function typegen(root, flags) {
1866
- root ??= process.cwd();
1943
+ root = resolveRootDirectory(root, flags);
1867
1944
  if (flags.watch) {
1868
1945
  await preloadVite();
1869
1946
  const vite2 = getVite();
1870
1947
  const logger = vite2.createLogger("info", { prefix: "[react-router]" });
1871
- await watch(root, { logger });
1948
+ await watch(root, {
1949
+ mode: flags.mode ?? "development",
1950
+ logger
1951
+ });
1872
1952
  await new Promise(() => {
1873
1953
  });
1874
1954
  return;
1875
1955
  }
1876
- await run(root);
1956
+ await run(root, {
1957
+ mode: flags.mode ?? "production"
1958
+ });
1877
1959
  }
1878
1960
 
1879
1961
  // cli/run.ts
package/dist/config.d.ts CHANGED
@@ -102,6 +102,22 @@ type ReactRouterConfig = {
102
102
  * other platforms and tools.
103
103
  */
104
104
  presets?: Array<Preset>;
105
+ /**
106
+ * Control the "Lazy Route Discovery" behavior
107
+ *
108
+ * - `routeDiscovery.mode`: By default, this resolves to `lazy` which will
109
+ * lazily discover routes as the user navigates around your application.
110
+ * You can set this to `initial` to opt-out of this behavior and load all
111
+ * routes with the initial HTML document load.
112
+ * - `routeDiscovery.manifestPath`: The path to serve the manifest file from.
113
+ * Only applies to `mode: "lazy"` and defaults to `/__manifest`.
114
+ */
115
+ routeDiscovery?: {
116
+ mode: "lazy";
117
+ manifestPath?: string;
118
+ } | {
119
+ mode: "initial";
120
+ };
105
121
  /**
106
122
  * The file name of the server build output. This file
107
123
  * should end in a `.js` extension and should be deployed to your server.
@@ -148,6 +164,17 @@ type ResolvedReactRouterConfig = Readonly<{
148
164
  * function returning an array to dynamically generate URLs.
149
165
  */
150
166
  prerender: ReactRouterConfig["prerender"];
167
+ /**
168
+ * Control the "Lazy Route Discovery" behavior
169
+ *
170
+ * - `routeDiscovery.mode`: By default, this resolves to `lazy` which will
171
+ * lazily discover routes as the user navigates around your application.
172
+ * You can set this to `initial` to opt-out of this behavior and load all
173
+ * routes with the initial HTML document load.
174
+ * - `routeDiscovery.manifestPath`: The path to serve the manifest file from.
175
+ * Only applies to `mode: "lazy"` and defaults to `/__manifest`.
176
+ */
177
+ routeDiscovery: ReactRouterConfig["routeDiscovery"];
151
178
  /**
152
179
  * An object of all available routes, keyed by route id.
153
180
  */
package/dist/config.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-701a32801
2
+ * @react-router/dev v0.0.0-experimental-b571356c3
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
package/dist/routes.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-701a32801
2
+ * @react-router/dev v0.0.0-experimental-b571356c3
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-701a32801
2
+ * @react-router/dev v0.0.0-experimental-b571356c3
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -113,7 +113,9 @@ function fromNodeRequest(nodeReq, nodeRes) {
113
113
  }
114
114
  async function toNodeRequest(res, nodeRes) {
115
115
  nodeRes.statusCode = res.status;
116
- nodeRes.statusMessage = res.statusText;
116
+ if (!nodeRes.req || nodeRes.req.httpVersionMajor < 2) {
117
+ nodeRes.statusMessage = res.statusText;
118
+ }
117
119
  let cookiesStrings = [];
118
120
  for (let [name, value] of res.headers) {
119
121
  if (name === "set-cookie") {
@@ -213,6 +215,15 @@ async function createContext({
213
215
  optimizeDeps: {
214
216
  noDiscovery: true
215
217
  },
218
+ css: {
219
+ // This empty PostCSS config object prevents the PostCSS config file from
220
+ // being loaded. We don't need it in a React Router config context, and
221
+ // there's also an issue in Vite 5 when using a .ts PostCSS config file in
222
+ // an ESM project: https://github.com/vitejs/vite/issues/15869. Consumers
223
+ // can work around this in their own Vite config file, but they can't
224
+ // configure this internal usage of vite-node.
225
+ postcss: {}
226
+ },
216
227
  configFile: false,
217
228
  envFile: false,
218
229
  plugins: []
@@ -432,12 +443,17 @@ async function resolveConfig({
432
443
  serverModuleFormat: "esm",
433
444
  ssr: true
434
445
  };
446
+ let userAndPresetConfigs = mergeReactRouterConfig(
447
+ ...presets,
448
+ reactRouterUserConfig
449
+ );
435
450
  let {
436
451
  appDirectory: userAppDirectory,
437
452
  basename,
438
453
  buildDirectory: userBuildDirectory,
439
454
  buildEnd,
440
455
  prerender,
456
+ routeDiscovery: userRouteDiscovery,
441
457
  serverBuildFile,
442
458
  serverBundles,
443
459
  serverModuleFormat,
@@ -445,7 +461,7 @@ async function resolveConfig({
445
461
  } = {
446
462
  ...defaults,
447
463
  // Default values should be completely overridden by user/preset config, not merged
448
- ...mergeReactRouterConfig(...presets, reactRouterUserConfig)
464
+ ...userAndPresetConfigs
449
465
  };
450
466
  if (!ssr && serverBundles) {
451
467
  serverBundles = void 0;
@@ -456,6 +472,32 @@ async function resolveConfig({
456
472
  "The `prerender` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths"
457
473
  );
458
474
  }
475
+ let routeDiscovery;
476
+ if (userRouteDiscovery == null) {
477
+ if (ssr) {
478
+ routeDiscovery = {
479
+ mode: "lazy",
480
+ manifestPath: "/__manifest"
481
+ };
482
+ } else {
483
+ routeDiscovery = { mode: "initial" };
484
+ }
485
+ } else if (userRouteDiscovery.mode === "initial") {
486
+ routeDiscovery = userRouteDiscovery;
487
+ } else if (userRouteDiscovery.mode === "lazy") {
488
+ if (!ssr) {
489
+ return err(
490
+ 'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`'
491
+ );
492
+ }
493
+ let { manifestPath } = userRouteDiscovery;
494
+ if (manifestPath != null && !manifestPath.startsWith("/")) {
495
+ return err(
496
+ 'The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")'
497
+ );
498
+ }
499
+ routeDiscovery = userRouteDiscovery;
500
+ }
459
501
  let appDirectory = import_pathe3.default.resolve(root, userAppDirectory || "app");
460
502
  let buildDirectory = import_pathe3.default.resolve(root, userBuildDirectory);
461
503
  let rootRouteFile = findEntry(appDirectory, "root");
@@ -523,6 +565,7 @@ async function resolveConfig({
523
565
  future,
524
566
  prerender,
525
567
  routes,
568
+ routeDiscovery,
526
569
  serverBuildFile,
527
570
  serverBundles,
528
571
  serverModuleFormat,
@@ -535,12 +578,13 @@ async function resolveConfig({
535
578
  }
536
579
  async function createConfigLoader({
537
580
  rootDirectory: root,
538
- watch
581
+ watch,
582
+ mode
539
583
  }) {
540
584
  root = root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
541
585
  let viteNodeContext = await createContext({
542
586
  root,
543
- mode: watch ? "development" : "production"
587
+ mode
544
588
  });
545
589
  let reactRouterConfigFile = findEntry(root, "react-router.config", {
546
590
  absolute: true
@@ -616,9 +660,13 @@ async function createConfigLoader({
616
660
  }
617
661
  };
618
662
  }
619
- async function loadConfig({ rootDirectory }) {
663
+ async function loadConfig({
664
+ rootDirectory,
665
+ mode
666
+ }) {
620
667
  let configLoader = await createConfigLoader({
621
668
  rootDirectory,
669
+ mode,
622
670
  watch: false
623
671
  });
624
672
  let config = await configLoader.getConfig();
@@ -627,13 +675,24 @@ async function loadConfig({ rootDirectory }) {
627
675
  }
628
676
  var entryExts = [".js", ".jsx", ".ts", ".tsx"];
629
677
  function findEntry(dir, basename, options) {
630
- for (let ext of entryExts) {
631
- let file = import_pathe3.default.resolve(dir, basename + ext);
632
- if (import_node_fs.default.existsSync(file)) {
633
- return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
678
+ let currentDir = import_pathe3.default.resolve(dir);
679
+ let { root } = import_pathe3.default.parse(currentDir);
680
+ while (true) {
681
+ for (let ext of options?.extensions ?? entryExts) {
682
+ let file = import_pathe3.default.resolve(currentDir, basename + ext);
683
+ if (import_node_fs.default.existsSync(file)) {
684
+ return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
685
+ }
686
+ }
687
+ if (!options?.walkParents) {
688
+ return void 0;
689
+ }
690
+ let parentDir = import_pathe3.default.dirname(currentDir);
691
+ if (currentDir === root || parentDir === currentDir) {
692
+ return void 0;
634
693
  }
694
+ currentDir = parentDir;
635
695
  }
636
- return void 0;
637
696
  }
638
697
 
639
698
  // vite/cloudflare-dev-proxy.ts
@@ -652,14 +711,15 @@ var cloudflareDevProxyVitePlugin = (options = {}) => {
652
711
  let future;
653
712
  return {
654
713
  name: PLUGIN_NAME,
655
- config: async (config) => {
714
+ config: async (config, configEnv) => {
656
715
  await preloadVite();
657
716
  const vite2 = getVite();
658
717
  const serverConditions = [
659
718
  ...vite2.defaultServerConditions ?? []
660
719
  ];
661
720
  let configResult = await loadConfig({
662
- rootDirectory: config.root ?? process.cwd()
721
+ rootDirectory: config.root ?? process.cwd(),
722
+ mode: configEnv.mode
663
723
  });
664
724
  if (!configResult.ok) {
665
725
  throw new Error(configResult.error);
package/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v0.0.0-experimental-701a32801
2
+ * @react-router/dev v0.0.0-experimental-b571356c3
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -154,6 +154,15 @@ async function createContext({
154
154
  optimizeDeps: {
155
155
  noDiscovery: true
156
156
  },
157
+ css: {
158
+ // This empty PostCSS config object prevents the PostCSS config file from
159
+ // being loaded. We don't need it in a React Router config context, and
160
+ // there's also an issue in Vite 5 when using a .ts PostCSS config file in
161
+ // an ESM project: https://github.com/vitejs/vite/issues/15869. Consumers
162
+ // can work around this in their own Vite config file, but they can't
163
+ // configure this internal usage of vite-node.
164
+ postcss: {}
165
+ },
157
166
  configFile: false,
158
167
  envFile: false,
159
168
  plugins: []
@@ -396,12 +405,17 @@ async function resolveConfig({
396
405
  serverModuleFormat: "esm",
397
406
  ssr: true
398
407
  };
408
+ let userAndPresetConfigs = mergeReactRouterConfig(
409
+ ...presets,
410
+ reactRouterUserConfig
411
+ );
399
412
  let {
400
413
  appDirectory: userAppDirectory,
401
414
  basename: basename2,
402
415
  buildDirectory: userBuildDirectory,
403
416
  buildEnd,
404
417
  prerender,
418
+ routeDiscovery: userRouteDiscovery,
405
419
  serverBuildFile,
406
420
  serverBundles,
407
421
  serverModuleFormat,
@@ -409,7 +423,7 @@ async function resolveConfig({
409
423
  } = {
410
424
  ...defaults,
411
425
  // Default values should be completely overridden by user/preset config, not merged
412
- ...mergeReactRouterConfig(...presets, reactRouterUserConfig)
426
+ ...userAndPresetConfigs
413
427
  };
414
428
  if (!ssr && serverBundles) {
415
429
  serverBundles = void 0;
@@ -420,6 +434,32 @@ async function resolveConfig({
420
434
  "The `prerender` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths"
421
435
  );
422
436
  }
437
+ let routeDiscovery;
438
+ if (userRouteDiscovery == null) {
439
+ if (ssr) {
440
+ routeDiscovery = {
441
+ mode: "lazy",
442
+ manifestPath: "/__manifest"
443
+ };
444
+ } else {
445
+ routeDiscovery = { mode: "initial" };
446
+ }
447
+ } else if (userRouteDiscovery.mode === "initial") {
448
+ routeDiscovery = userRouteDiscovery;
449
+ } else if (userRouteDiscovery.mode === "lazy") {
450
+ if (!ssr) {
451
+ return err(
452
+ 'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`'
453
+ );
454
+ }
455
+ let { manifestPath } = userRouteDiscovery;
456
+ if (manifestPath != null && !manifestPath.startsWith("/")) {
457
+ return err(
458
+ 'The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")'
459
+ );
460
+ }
461
+ routeDiscovery = userRouteDiscovery;
462
+ }
423
463
  let appDirectory = import_pathe3.default.resolve(root, userAppDirectory || "app");
424
464
  let buildDirectory = import_pathe3.default.resolve(root, userBuildDirectory);
425
465
  let rootRouteFile = findEntry(appDirectory, "root");
@@ -487,6 +527,7 @@ async function resolveConfig({
487
527
  future,
488
528
  prerender,
489
529
  routes,
530
+ routeDiscovery,
490
531
  serverBuildFile,
491
532
  serverBundles,
492
533
  serverModuleFormat,
@@ -499,12 +540,13 @@ async function resolveConfig({
499
540
  }
500
541
  async function createConfigLoader({
501
542
  rootDirectory: root,
502
- watch: watch2
543
+ watch: watch2,
544
+ mode
503
545
  }) {
504
546
  root = root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
505
547
  let viteNodeContext = await createContext({
506
548
  root,
507
- mode: watch2 ? "development" : "production"
549
+ mode
508
550
  });
509
551
  let reactRouterConfigFile = findEntry(root, "react-router.config", {
510
552
  absolute: true
@@ -595,7 +637,18 @@ async function resolveEntryFiles({
595
637
  let userEntryServerFile = findEntry(appDirectory, "entry.server");
596
638
  let entryServerFile;
597
639
  let entryClientFile = userEntryClientFile || "entry.client.tsx";
598
- let pkgJson = await import_package_json.default.load(rootDirectory);
640
+ let packageJsonPath = findEntry(rootDirectory, "package", {
641
+ extensions: [".json"],
642
+ absolute: true,
643
+ walkParents: true
644
+ });
645
+ if (!packageJsonPath) {
646
+ throw new Error(
647
+ `Could not find package.json in ${rootDirectory} or any of its parent directories`
648
+ );
649
+ }
650
+ let packageJsonDirectory = import_pathe3.default.dirname(packageJsonPath);
651
+ let pkgJson = await import_package_json.default.load(packageJsonDirectory);
599
652
  let deps = pkgJson.content.dependencies ?? {};
600
653
  if (userEntryServerFile) {
601
654
  entryServerFile = userEntryServerFile;
@@ -618,7 +671,7 @@ async function resolveEntryFiles({
618
671
  await pkgJson.save();
619
672
  let packageManager = detectPackageManager() ?? "npm";
620
673
  (0, import_node_child_process.execSync)(`${packageManager} install`, {
621
- cwd: rootDirectory,
674
+ cwd: packageJsonDirectory,
622
675
  stdio: "inherit"
623
676
  });
624
677
  }
@@ -630,13 +683,24 @@ async function resolveEntryFiles({
630
683
  }
631
684
  var entryExts = [".js", ".jsx", ".ts", ".tsx"];
632
685
  function findEntry(dir, basename2, options) {
633
- for (let ext of entryExts) {
634
- let file = import_pathe3.default.resolve(dir, basename2 + ext);
635
- if (import_node_fs.default.existsSync(file)) {
636
- return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
686
+ let currentDir = import_pathe3.default.resolve(dir);
687
+ let { root } = import_pathe3.default.parse(currentDir);
688
+ while (true) {
689
+ for (let ext of options?.extensions ?? entryExts) {
690
+ let file = import_pathe3.default.resolve(currentDir, basename2 + ext);
691
+ if (import_node_fs.default.existsSync(file)) {
692
+ return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
693
+ }
694
+ }
695
+ if (!options?.walkParents) {
696
+ return void 0;
697
+ }
698
+ let parentDir = import_pathe3.default.dirname(currentDir);
699
+ if (currentDir === root || parentDir === currentDir) {
700
+ return void 0;
637
701
  }
702
+ currentDir = parentDir;
638
703
  }
639
- return void 0;
640
704
  }
641
705
 
642
706
  // vite/babel.ts
@@ -778,8 +842,8 @@ function formatParamProperties(fullpath2) {
778
842
  }
779
843
 
780
844
  // typegen/index.ts
781
- async function watch(rootDirectory, { logger } = {}) {
782
- const ctx = await createContext2({ rootDirectory, watch: true });
845
+ async function watch(rootDirectory, { mode, logger }) {
846
+ const ctx = await createContext2({ rootDirectory, mode, watch: true });
783
847
  await writeAll(ctx);
784
848
  logger?.info(import_picocolors2.default.green("generated types"), { timestamp: true, clear: true });
785
849
  ctx.configLoader.onChange(async ({ result, routeConfigChanged }) => {
@@ -802,9 +866,10 @@ async function watch(rootDirectory, { logger } = {}) {
802
866
  }
803
867
  async function createContext2({
804
868
  rootDirectory,
805
- watch: watch2
869
+ watch: watch2,
870
+ mode
806
871
  }) {
807
- const configLoader = await createConfigLoader({ rootDirectory, watch: watch2 });
872
+ const configLoader = await createConfigLoader({ rootDirectory, mode, watch: watch2 });
808
873
  const configResult = await configLoader.getConfig();
809
874
  if (!configResult.ok) {
810
875
  throw new Error(configResult.error);
@@ -841,18 +906,21 @@ function register(ctx) {
841
906
  }
842
907
  `;
843
908
  const { t: t2 } = babel_exports;
844
- const indexPaths = new Set(
845
- Object.values(ctx.config.routes).filter((route) => route.index).map((route) => route.path)
846
- );
909
+ const fullpaths = {};
910
+ for (const route of Object.values(ctx.config.routes)) {
911
+ if (route.id !== "root" && !route.path) continue;
912
+ const lineage2 = lineage(ctx.config.routes, route);
913
+ const fullpath2 = fullpath(lineage2);
914
+ const existing = fullpaths[fullpath2];
915
+ if (!existing || existing.length < lineage2.length) {
916
+ fullpaths[fullpath2] = lineage2;
917
+ }
918
+ }
847
919
  const typeParams = t2.tsTypeAliasDeclaration(
848
920
  t2.identifier("Params"),
849
921
  null,
850
922
  t2.tsTypeLiteral(
851
- Object.values(ctx.config.routes).map((route) => {
852
- if (route.id !== "root" && !route.path) return void 0;
853
- if (!route.index && indexPaths.has(route.path)) return void 0;
854
- const lineage2 = lineage(ctx.config.routes, route);
855
- const fullpath2 = fullpath(lineage2);
923
+ Object.keys(fullpaths).map((fullpath2) => {
856
924
  const params = parse2(fullpath2);
857
925
  return t2.tsPropertySignature(
858
926
  t2.stringLiteral(fullpath2),
@@ -869,7 +937,7 @@ function register(ctx) {
869
937
  )
870
938
  )
871
939
  );
872
- }).filter((x) => x !== void 0)
940
+ })
873
941
  )
874
942
  );
875
943
  return [register2, generate(typeParams).code].join("\n\n");
@@ -885,6 +953,7 @@ var virtual = import_dedent2.default`
885
953
  export const isSpaMode: ServerBuild["isSpaMode"];
886
954
  export const prerender: ServerBuild["prerender"];
887
955
  export const publicPath: ServerBuild["publicPath"];
956
+ export const routeDiscovery: ServerBuild["routeDiscovery"];
888
957
  export const routes: ServerBuild["routes"];
889
958
  export const ssr: ServerBuild["ssr"];
890
959
  export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
@@ -945,7 +1014,9 @@ function fromNodeRequest(nodeReq, nodeRes) {
945
1014
  }
946
1015
  async function toNodeRequest(res, nodeRes) {
947
1016
  nodeRes.statusCode = res.status;
948
- nodeRes.statusMessage = res.statusText;
1017
+ if (!nodeRes.req || nodeRes.req.httpVersionMajor < 2) {
1018
+ nodeRes.statusMessage = res.statusText;
1019
+ }
949
1020
  let cookiesStrings = [];
950
1021
  for (let [name, value] of res.headers) {
951
1022
  if (name === "set-cookie") {
@@ -2354,6 +2425,9 @@ var reactRouterVitePlugin = () => {
2354
2425
  export const ssr = ${ctx.reactRouterConfig.ssr};
2355
2426
  export const isSpaMode = ${isSpaMode};
2356
2427
  export const prerender = ${JSON.stringify(prerenderPaths)};
2428
+ export const routeDiscovery = ${JSON.stringify(
2429
+ ctx.reactRouterConfig.routeDiscovery
2430
+ )};
2357
2431
  export const publicPath = ${JSON.stringify(ctx.publicPath)};
2358
2432
  export const entry = { module: entryServer };
2359
2433
  export const routes = {
@@ -2687,14 +2761,17 @@ var reactRouterVitePlugin = () => {
2687
2761
  prefix: "[react-router]"
2688
2762
  });
2689
2763
  rootDirectory = viteUserConfig.root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd();
2764
+ let mode = viteConfigEnv.mode;
2690
2765
  if (viteCommand === "serve") {
2691
2766
  typegenWatcherPromise = watch(rootDirectory, {
2767
+ mode,
2692
2768
  // ignore `info` logs from typegen since they are redundant when Vite plugin logs are active
2693
2769
  logger: vite2.createLogger("warn", { prefix: "[react-router]" })
2694
2770
  });
2695
2771
  }
2696
2772
  reactRouterConfigLoader = await createConfigLoader({
2697
2773
  rootDirectory,
2774
+ mode,
2698
2775
  watch: viteCommand === "serve"
2699
2776
  });
2700
2777
  await updatePluginContext();
@@ -4371,8 +4448,9 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
4371
4448
  ""
4372
4449
  ) : null;
4373
4450
  let routeChunkSuffix = routeChunkName ? `-${(0, import_kebabCase.default)(routeChunkName)}` : "";
4451
+ let assetsDir = (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.assetsDir : null) ?? viteUserConfig?.build?.assetsDir ?? "assets";
4374
4452
  return path6.posix.join(
4375
- (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig?.environments?.client?.build?.assetsDir : viteUserConfig?.build?.assetsDir) ?? "assets",
4453
+ assetsDir,
4376
4454
  `[name]${routeChunkSuffix}-[hash].js`
4377
4455
  );
4378
4456
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-router/dev",
3
- "version": "0.0.0-experimental-701a32801",
3
+ "version": "0.0.0-experimental-b571356c3",
4
4
  "description": "Dev tools and CLI for React Router",
5
5
  "homepage": "https://reactrouter.com",
6
6
  "bugs": {
@@ -86,7 +86,7 @@
86
86
  "set-cookie-parser": "^2.6.0",
87
87
  "valibot": "^0.41.0",
88
88
  "vite-node": "3.0.0-beta.2",
89
- "@react-router/node": "0.0.0-experimental-701a32801"
89
+ "@react-router/node": "0.0.0-experimental-b571356c3"
90
90
  },
91
91
  "devDependencies": {
92
92
  "@types/babel__core": "^7.20.5",
@@ -110,15 +110,15 @@
110
110
  "vite": "^6.1.0",
111
111
  "wireit": "0.14.9",
112
112
  "wrangler": "^4.2.0",
113
- "@react-router/serve": "0.0.0-experimental-701a32801",
114
- "react-router": "^0.0.0-experimental-701a32801"
113
+ "@react-router/serve": "0.0.0-experimental-b571356c3",
114
+ "react-router": "^0.0.0-experimental-b571356c3"
115
115
  },
116
116
  "peerDependencies": {
117
117
  "typescript": "^5.1.0",
118
118
  "vite": "^5.1.0 || ^6.0.0",
119
119
  "wrangler": "^3.28.2 || ^4.0.0",
120
- "@react-router/serve": "^0.0.0-experimental-701a32801",
121
- "react-router": "^0.0.0-experimental-701a32801"
120
+ "@react-router/serve": "^0.0.0-experimental-b571356c3",
121
+ "react-router": "^0.0.0-experimental-b571356c3"
122
122
  },
123
123
  "peerDependenciesMeta": {
124
124
  "@react-router/serve": {