@react-router/dev 7.6.0 → 7.6.1-pre.0

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/dist/vite.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/dev v7.6.0
2
+ * @react-router/dev v7.6.1-pre.0
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -59,10 +59,9 @@ var import_picocolors3 = __toESM(require("picocolors"));
59
59
  var import_kebabCase = __toESM(require("lodash/kebabCase"));
60
60
 
61
61
  // typegen/index.ts
62
- var import_node_fs2 = __toESM(require("fs"));
63
- var import_dedent2 = __toESM(require("dedent"));
64
- var Path5 = __toESM(require("pathe"));
65
- var import_picocolors2 = __toESM(require("picocolors"));
62
+ var import_promises = __toESM(require("fs/promises"));
63
+ var Path4 = __toESM(require("pathe"));
64
+ var import_picocolors2 = require("picocolors");
66
65
 
67
66
  // config/config.ts
68
67
  var import_node_fs = __toESM(require("fs"));
@@ -414,7 +413,7 @@ async function resolveConfig({
414
413
  );
415
414
  let {
416
415
  appDirectory: userAppDirectory,
417
- basename: basename2,
416
+ basename: basename3,
418
417
  buildDirectory: userBuildDirectory,
419
418
  buildEnd,
420
419
  prerender,
@@ -529,7 +528,7 @@ async function resolveConfig({
529
528
  };
530
529
  let reactRouterConfig = deepFreeze({
531
530
  appDirectory,
532
- basename: basename2,
531
+ basename: basename3,
533
532
  buildDirectory,
534
533
  buildEnd,
535
534
  future,
@@ -592,11 +591,11 @@ async function createConfigLoader({
592
591
  fsWatcher = import_chokidar.default.watch([root, appDirectory], {
593
592
  ignoreInitial: true,
594
593
  ignored: (path6) => {
595
- let dirname5 = import_pathe3.default.dirname(path6);
596
- return !dirname5.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
594
+ let dirname4 = import_pathe3.default.dirname(path6);
595
+ return !dirname4.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
597
596
  // that are at the root level, not nested in subdirectories
598
597
  path6 !== root && // Watch the root directory itself
599
- dirname5 !== root;
598
+ dirname4 !== root;
600
599
  }
601
600
  });
602
601
  fsWatcher.on("all", async (...args) => {
@@ -736,15 +735,15 @@ function omitRoutes(config) {
736
735
  };
737
736
  }
738
737
  var entryExts = [".js", ".jsx", ".ts", ".tsx"];
739
- function isEntryFile(entryBasename, filename3) {
740
- return entryExts.some((ext) => filename3 === `${entryBasename}${ext}`);
738
+ function isEntryFile(entryBasename, filename2) {
739
+ return entryExts.some((ext) => filename2 === `${entryBasename}${ext}`);
741
740
  }
742
- function findEntry(dir, basename2, options) {
741
+ function findEntry(dir, basename3, options) {
743
742
  let currentDir = import_pathe3.default.resolve(dir);
744
743
  let { root } = import_pathe3.default.parse(currentDir);
745
744
  while (true) {
746
745
  for (let ext of options?.extensions ?? entryExts) {
747
- let file = import_pathe3.default.resolve(currentDir, basename2 + ext);
746
+ let file = import_pathe3.default.resolve(currentDir, basename3 + ext);
748
747
  if (import_node_fs.default.existsSync(file)) {
749
748
  return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file);
750
749
  }
@@ -784,6 +783,30 @@ function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /
784
783
  return false;
785
784
  }
786
785
 
786
+ // typegen/context.ts
787
+ async function createContext2({
788
+ rootDirectory,
789
+ watch: watch2,
790
+ mode
791
+ }) {
792
+ const configLoader = await createConfigLoader({ rootDirectory, mode, watch: watch2 });
793
+ const configResult = await configLoader.getConfig();
794
+ if (!configResult.ok) {
795
+ throw new Error(configResult.error);
796
+ }
797
+ const config = configResult.value;
798
+ return {
799
+ configLoader,
800
+ rootDirectory,
801
+ config
802
+ };
803
+ }
804
+
805
+ // typegen/generate.ts
806
+ var import_dedent = __toESM(require("dedent"));
807
+ var Path3 = __toESM(require("pathe"));
808
+ var Pathe = __toESM(require("pathe/utils"));
809
+
787
810
  // vite/babel.ts
788
811
  var babel_exports = {};
789
812
  __export(babel_exports, {
@@ -797,26 +820,6 @@ var t = __toESM(require("@babel/types"));
797
820
  var traverse = require("@babel/traverse").default;
798
821
  var generate = require("@babel/generator").default;
799
822
 
800
- // typegen/generate.ts
801
- var import_dedent = __toESM(require("dedent"));
802
- var Path4 = __toESM(require("pathe"));
803
- var Pathe2 = __toESM(require("pathe/utils"));
804
-
805
- // typegen/paths.ts
806
- var Path3 = __toESM(require("pathe"));
807
- var Pathe = __toESM(require("pathe/utils"));
808
- function getTypesDir(ctx) {
809
- return Path3.join(ctx.rootDirectory, ".react-router/types");
810
- }
811
- function getTypesPath(ctx, route) {
812
- return Path3.join(
813
- getTypesDir(ctx),
814
- Path3.relative(ctx.rootDirectory, ctx.config.appDirectory),
815
- Path3.dirname(route.file),
816
- "+types/" + Pathe.filename(route.file) + ".ts"
817
- );
818
- }
819
-
820
823
  // typegen/params.ts
821
824
  function parse2(fullpath2) {
822
825
  const result = {};
@@ -846,97 +849,367 @@ function lineage(routes, route) {
846
849
  return result;
847
850
  }
848
851
  function fullpath(lineage2) {
849
- if (lineage2.length === 1 && lineage2[0].id === "root") return "/";
850
- return "/" + lineage2.map((route) => route.path?.replace(/^\//, "")?.replace(/\/$/, "")).filter((path6) => path6 !== void 0 && path6 !== "").join("/");
852
+ const route = lineage2.at(-1);
853
+ if (lineage2.length === 1 && route?.id === "root") return "/";
854
+ const isLayout = route && route.index !== true && route.path === void 0;
855
+ if (isLayout) return void 0;
856
+ return "/" + lineage2.map((route2) => route2.path?.replace(/^\//, "")?.replace(/\/$/, "")).filter((path6) => path6 !== void 0 && path6 !== "").join("/");
851
857
  }
852
858
 
853
859
  // typegen/generate.ts
854
- function generate2(ctx, route) {
855
- const lineage2 = lineage(ctx.config.routes, route);
856
- const fullpath2 = fullpath(lineage2);
857
- const typesPath = getTypesPath(ctx, route);
858
- const parents = lineage2.slice(0, -1);
859
- const parentTypeImports = parents.map((parent, i) => {
860
- const rel = Path4.relative(
861
- Path4.dirname(typesPath),
862
- getTypesPath(ctx, parent)
863
- );
864
- const indent = i === 0 ? "" : " ".repeat(2);
865
- let source = noExtension(rel);
866
- if (!source.startsWith("../")) source = "./" + source;
867
- return `${indent}import type { Info as Parent${i} } from "${source}.js"`;
868
- }).join("\n");
869
- return import_dedent.default`
870
- // React Router generated types for route:
871
- // ${route.file}
872
-
873
- import type * as T from "react-router/route-module"
860
+ function typesDirectory(ctx) {
861
+ return Path3.join(ctx.rootDirectory, ".react-router/types");
862
+ }
863
+ function generateFuture(ctx) {
864
+ const filename2 = Path3.join(typesDirectory(ctx), "+future.ts");
865
+ const content = import_dedent.default`
866
+ // Generated by React Router
874
867
 
875
- ${parentTypeImports}
868
+ import "react-router";
876
869
 
877
- type Module = typeof import("../${Pathe2.filename(route.file)}.js")
870
+ declare module "react-router" {
871
+ interface Future {
872
+ unstable_middleware: ${ctx.config.future.unstable_middleware}
873
+ }
874
+ }
875
+ `;
876
+ return { filename: filename2, content };
877
+ }
878
+ function generateServerBuild(ctx) {
879
+ const filename2 = Path3.join(typesDirectory(ctx), "+server-build.d.ts");
880
+ const content = import_dedent.default`
881
+ // Generated by React Router
878
882
 
879
- export type Info = {
880
- parents: [${parents.map((_, i) => `Parent${i}`).join(", ")}],
881
- id: "${route.id}"
882
- file: "${route.file}"
883
- path: "${route.path}"
884
- params: {${formatParamProperties(
885
- fullpath2
886
- )}} & { [key: string]: string | undefined }
887
- module: Module
888
- loaderData: T.CreateLoaderData<Module>
889
- actionData: T.CreateActionData<Module>
883
+ declare module "virtual:react-router/server-build" {
884
+ import { ServerBuild } from "react-router";
885
+ export const assets: ServerBuild["assets"];
886
+ export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"];
887
+ export const basename: ServerBuild["basename"];
888
+ export const entry: ServerBuild["entry"];
889
+ export const future: ServerBuild["future"];
890
+ export const isSpaMode: ServerBuild["isSpaMode"];
891
+ export const prerender: ServerBuild["prerender"];
892
+ export const publicPath: ServerBuild["publicPath"];
893
+ export const routeDiscovery: ServerBuild["routeDiscovery"];
894
+ export const routes: ServerBuild["routes"];
895
+ export const ssr: ServerBuild["ssr"];
896
+ export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
897
+ }
898
+ `;
899
+ return { filename: filename2, content };
900
+ }
901
+ var { t: t2 } = babel_exports;
902
+ function generateRoutes(ctx) {
903
+ const fileToRoutes = /* @__PURE__ */ new Map();
904
+ const lineages = /* @__PURE__ */ new Map();
905
+ const allPages = /* @__PURE__ */ new Set();
906
+ const routeToPages = /* @__PURE__ */ new Map();
907
+ for (const route of Object.values(ctx.config.routes)) {
908
+ let routeIds = fileToRoutes.get(route.file);
909
+ if (!routeIds) {
910
+ routeIds = /* @__PURE__ */ new Set();
911
+ fileToRoutes.set(route.file, routeIds);
890
912
  }
913
+ routeIds.add(route.id);
914
+ const lineage2 = lineage(ctx.config.routes, route);
915
+ lineages.set(route.id, lineage2);
916
+ const fullpath2 = fullpath(lineage2);
917
+ if (!fullpath2) continue;
918
+ const pages = explodeOptionalSegments(fullpath2);
919
+ pages.forEach((page) => allPages.add(page));
920
+ lineage2.forEach(({ id }) => {
921
+ let routePages = routeToPages.get(id);
922
+ if (!routePages) {
923
+ routePages = /* @__PURE__ */ new Set();
924
+ routeToPages.set(id, routePages);
925
+ }
926
+ pages.forEach((page) => routePages.add(page));
927
+ });
928
+ }
929
+ const routesTs = {
930
+ filename: Path3.join(typesDirectory(ctx), "+routes.ts"),
931
+ content: import_dedent.default`
932
+ // Generated by React Router
891
933
 
892
- export namespace Route {
893
- export type LinkDescriptors = T.LinkDescriptors
894
- export type LinksFunction = () => LinkDescriptors
934
+ import "react-router"
895
935
 
896
- export type MetaArgs = T.CreateMetaArgs<Info>
897
- export type MetaDescriptors = T.MetaDescriptors
898
- export type MetaFunction = (args: MetaArgs) => MetaDescriptors
936
+ declare module "react-router" {
937
+ interface Register {
938
+ pages: Pages
939
+ routeFiles: RouteFiles
940
+ }
941
+ }
942
+ ` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({ fileToRoutes, routeToPages })).code
943
+ };
944
+ const allAnnotations = Array.from(fileToRoutes.entries()).filter(([file]) => isInAppDirectory(ctx, file)).map(
945
+ ([file, routeIds]) => getRouteAnnotations({ ctx, file, routeIds, lineages })
946
+ );
947
+ return [routesTs, ...allAnnotations];
948
+ }
949
+ function pagesType(pages) {
950
+ return t2.tsTypeAliasDeclaration(
951
+ t2.identifier("Pages"),
952
+ null,
953
+ t2.tsTypeLiteral(
954
+ Array.from(pages).map((page) => {
955
+ return t2.tsPropertySignature(
956
+ t2.stringLiteral(page),
957
+ t2.tsTypeAnnotation(
958
+ t2.tsTypeLiteral([
959
+ t2.tsPropertySignature(
960
+ t2.identifier("params"),
961
+ t2.tsTypeAnnotation(paramsType(page))
962
+ )
963
+ ])
964
+ )
965
+ );
966
+ })
967
+ )
968
+ );
969
+ }
970
+ function routeFilesType({
971
+ fileToRoutes,
972
+ routeToPages
973
+ }) {
974
+ return t2.tsTypeAliasDeclaration(
975
+ t2.identifier("RouteFiles"),
976
+ null,
977
+ t2.tsTypeLiteral(
978
+ Array.from(fileToRoutes).map(
979
+ ([file, routeIds]) => t2.tsPropertySignature(
980
+ t2.stringLiteral(file),
981
+ t2.tsTypeAnnotation(
982
+ t2.tsUnionType(
983
+ Array.from(routeIds).map((routeId) => {
984
+ const pages = routeToPages.get(routeId) ?? /* @__PURE__ */ new Set();
985
+ return t2.tsTypeLiteral([
986
+ t2.tsPropertySignature(
987
+ t2.identifier("id"),
988
+ t2.tsTypeAnnotation(
989
+ t2.tsLiteralType(t2.stringLiteral(routeId))
990
+ )
991
+ ),
992
+ t2.tsPropertySignature(
993
+ t2.identifier("page"),
994
+ t2.tsTypeAnnotation(
995
+ pages ? t2.tsUnionType(
996
+ Array.from(pages).map(
997
+ (page) => t2.tsLiteralType(t2.stringLiteral(page))
998
+ )
999
+ ) : t2.tsNeverKeyword()
1000
+ )
1001
+ )
1002
+ ]);
1003
+ })
1004
+ )
1005
+ )
1006
+ )
1007
+ )
1008
+ )
1009
+ );
1010
+ }
1011
+ function isInAppDirectory(ctx, routeFile) {
1012
+ const path6 = Path3.resolve(ctx.config.appDirectory, routeFile);
1013
+ return path6.startsWith(ctx.config.appDirectory);
1014
+ }
1015
+ function getRouteAnnotations({
1016
+ ctx,
1017
+ file,
1018
+ routeIds,
1019
+ lineages
1020
+ }) {
1021
+ const filename2 = Path3.join(
1022
+ typesDirectory(ctx),
1023
+ Path3.relative(ctx.rootDirectory, ctx.config.appDirectory),
1024
+ Path3.dirname(file),
1025
+ "+types",
1026
+ Pathe.filename(file) + ".ts"
1027
+ );
1028
+ const matchesType = t2.tsTypeAliasDeclaration(
1029
+ t2.identifier("Matches"),
1030
+ null,
1031
+ t2.tsUnionType(
1032
+ Array.from(routeIds).map((routeId) => {
1033
+ const lineage2 = lineages.get(routeId);
1034
+ return t2.tsTupleType(
1035
+ lineage2.map(
1036
+ (route) => t2.tsTypeLiteral([
1037
+ t2.tsPropertySignature(
1038
+ t2.identifier("id"),
1039
+ t2.tsTypeAnnotation(t2.tsLiteralType(t2.stringLiteral(route.id)))
1040
+ ),
1041
+ t2.tsPropertySignature(
1042
+ t2.identifier("module"),
1043
+ t2.tsTypeAnnotation(
1044
+ t2.tsTypeQuery(
1045
+ t2.tsImportType(
1046
+ t2.stringLiteral(
1047
+ relativeImportSource(
1048
+ rootDirsPath(ctx, filename2),
1049
+ Path3.resolve(ctx.config.appDirectory, route.file)
1050
+ )
1051
+ )
1052
+ )
1053
+ )
1054
+ )
1055
+ )
1056
+ ])
1057
+ )
1058
+ );
1059
+ })
1060
+ )
1061
+ );
1062
+ const routeImportSource = relativeImportSource(
1063
+ rootDirsPath(ctx, filename2),
1064
+ Path3.resolve(ctx.config.appDirectory, file)
1065
+ );
1066
+ const content = import_dedent.default`
1067
+ // Generated by React Router
899
1068
 
900
- export type HeadersArgs = T.HeadersArgs
901
- export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
1069
+ import type { GetInfo, GetAnnotations } from "react-router/internal";
902
1070
 
903
- export type unstable_MiddlewareFunction = T.CreateServerMiddlewareFunction<Info>
904
- export type unstable_ClientMiddlewareFunction = T.CreateClientMiddlewareFunction<Info>
905
- export type LoaderArgs = T.CreateServerLoaderArgs<Info>
906
- export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
907
- export type ActionArgs = T.CreateServerActionArgs<Info>
908
- export type ClientActionArgs = T.CreateClientActionArgs<Info>
1071
+ type Module = typeof import("${routeImportSource}")
909
1072
 
910
- export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Info>
911
- export type ComponentProps = T.CreateComponentProps<Info>
912
- export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Info>
913
- }
914
- `;
1073
+ type Info = GetInfo<{
1074
+ file: "${file}",
1075
+ module: Module
1076
+ }>
1077
+ ` + "\n\n" + generate(matchesType).code + "\n\n" + import_dedent.default`
1078
+ type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }>;
1079
+
1080
+ export namespace Route {
1081
+ // links
1082
+ export type LinkDescriptors = Annotations["LinkDescriptors"];
1083
+ export type LinksFunction = Annotations["LinksFunction"];
1084
+
1085
+ // meta
1086
+ export type MetaArgs = Annotations["MetaArgs"];
1087
+ export type MetaDescriptors = Annotations["MetaDescriptors"];
1088
+ export type MetaFunction = Annotations["MetaFunction"];
1089
+
1090
+ // headers
1091
+ export type HeadersArgs = Annotations["HeadersArgs"];
1092
+ export type HeadersFunction = Annotations["HeadersFunction"];
1093
+
1094
+ // unstable_middleware
1095
+ export type unstable_MiddlewareFunction = Annotations["unstable_MiddlewareFunction"];
1096
+
1097
+ // unstable_clientMiddleware
1098
+ export type unstable_ClientMiddlewareFunction = Annotations["unstable_ClientMiddlewareFunction"];
1099
+
1100
+ // loader
1101
+ export type LoaderArgs = Annotations["LoaderArgs"];
1102
+
1103
+ // clientLoader
1104
+ export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
1105
+
1106
+ // action
1107
+ export type ActionArgs = Annotations["ActionArgs"];
1108
+
1109
+ // clientAction
1110
+ export type ClientActionArgs = Annotations["ClientActionArgs"];
1111
+
1112
+ // HydrateFallback
1113
+ export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
1114
+
1115
+ // Component
1116
+ export type ComponentProps = Annotations["ComponentProps"];
1117
+
1118
+ // ErrorBoundary
1119
+ export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
1120
+ }
1121
+ `;
1122
+ return { filename: filename2, content };
915
1123
  }
916
- var noExtension = (path6) => Path4.join(Path4.dirname(path6), Pathe2.filename(path6));
917
- function formatParamProperties(fullpath2) {
918
- const params = parse2(fullpath2);
919
- const properties = Object.entries(params).map(
920
- ([name, isRequired]) => isRequired ? `"${name}": string` : `"${name}"?: string`
1124
+ function relativeImportSource(from, to) {
1125
+ let path6 = Path3.relative(Path3.dirname(from), to);
1126
+ path6 = Path3.join(Path3.dirname(path6), Pathe.filename(path6));
1127
+ if (!path6.startsWith("../")) path6 = "./" + path6;
1128
+ return path6 + ".js";
1129
+ }
1130
+ function rootDirsPath(ctx, typesPath) {
1131
+ const rel = Path3.relative(typesDirectory(ctx), typesPath);
1132
+ return Path3.join(ctx.rootDirectory, rel);
1133
+ }
1134
+ function paramsType(path6) {
1135
+ const params = parse2(path6);
1136
+ return t2.tsTypeLiteral(
1137
+ Object.entries(params).map(([param, isRequired]) => {
1138
+ const property = t2.tsPropertySignature(
1139
+ t2.stringLiteral(param),
1140
+ t2.tsTypeAnnotation(t2.tsStringKeyword())
1141
+ );
1142
+ property.optional = !isRequired;
1143
+ return property;
1144
+ })
1145
+ );
1146
+ }
1147
+ function explodeOptionalSegments(path6) {
1148
+ let segments = path6.split("/");
1149
+ if (segments.length === 0) return [];
1150
+ let [first, ...rest] = segments;
1151
+ let isOptional = first.endsWith("?");
1152
+ let required = first.replace(/\?$/, "");
1153
+ if (rest.length === 0) {
1154
+ return isOptional ? [required, ""] : [required];
1155
+ }
1156
+ let restExploded = explodeOptionalSegments(rest.join("/"));
1157
+ let result = [];
1158
+ result.push(
1159
+ ...restExploded.map(
1160
+ (subpath) => subpath === "" ? required : [required, subpath].join("/")
1161
+ )
1162
+ );
1163
+ if (isOptional) {
1164
+ result.push(...restExploded);
1165
+ }
1166
+ return result.map(
1167
+ (exploded) => path6.startsWith("/") && exploded === "" ? "/" : exploded
921
1168
  );
922
- return properties.join("; ");
923
1169
  }
924
1170
 
925
1171
  // typegen/index.ts
1172
+ async function clearRouteModuleAnnotations(ctx) {
1173
+ await import_promises.default.rm(
1174
+ Path4.join(typesDirectory(ctx), Path4.basename(ctx.config.appDirectory)),
1175
+ { recursive: true, force: true }
1176
+ );
1177
+ }
1178
+ async function write(...files) {
1179
+ return Promise.all(
1180
+ files.map(async ({ filename: filename2, content }) => {
1181
+ await import_promises.default.mkdir(Path4.dirname(filename2), { recursive: true });
1182
+ await import_promises.default.writeFile(filename2, content);
1183
+ })
1184
+ );
1185
+ }
926
1186
  async function watch(rootDirectory, { mode, logger }) {
927
1187
  const ctx = await createContext2({ rootDirectory, mode, watch: true });
928
- await writeAll(ctx);
929
- logger?.info(import_picocolors2.default.green("generated types"), { timestamp: true, clear: true });
1188
+ await import_promises.default.rm(typesDirectory(ctx), { recursive: true, force: true });
1189
+ await write(
1190
+ generateFuture(ctx),
1191
+ generateServerBuild(ctx),
1192
+ ...generateRoutes(ctx)
1193
+ );
1194
+ logger?.info((0, import_picocolors2.green)("generated types"), { timestamp: true, clear: true });
930
1195
  ctx.configLoader.onChange(
931
1196
  async ({ result, configChanged, routeConfigChanged }) => {
932
1197
  if (!result.ok) {
933
- logger?.error(import_picocolors2.default.red(result.error), { timestamp: true, clear: true });
1198
+ logger?.error((0, import_picocolors2.red)(result.error), { timestamp: true, clear: true });
934
1199
  return;
935
1200
  }
936
1201
  ctx.config = result.value;
937
- if (configChanged || routeConfigChanged) {
938
- await writeAll(ctx);
939
- logger?.info(import_picocolors2.default.green("regenerated types"), {
1202
+ if (configChanged) {
1203
+ await write(generateFuture(ctx));
1204
+ logger?.info((0, import_picocolors2.green)("regenerated types"), {
1205
+ timestamp: true,
1206
+ clear: true
1207
+ });
1208
+ }
1209
+ if (routeConfigChanged) {
1210
+ await clearRouteModuleAnnotations(ctx);
1211
+ await write(...generateRoutes(ctx));
1212
+ logger?.info((0, import_picocolors2.green)("regenerated types"), {
940
1213
  timestamp: true,
941
1214
  clear: true
942
1215
  });
@@ -947,102 +1220,6 @@ async function watch(rootDirectory, { mode, logger }) {
947
1220
  close: async () => await ctx.configLoader.close()
948
1221
  };
949
1222
  }
950
- async function createContext2({
951
- rootDirectory,
952
- watch: watch2,
953
- mode
954
- }) {
955
- const configLoader = await createConfigLoader({ rootDirectory, mode, watch: watch2 });
956
- const configResult = await configLoader.getConfig();
957
- if (!configResult.ok) {
958
- throw new Error(configResult.error);
959
- }
960
- const config = configResult.value;
961
- return {
962
- configLoader,
963
- rootDirectory,
964
- config
965
- };
966
- }
967
- async function writeAll(ctx) {
968
- const typegenDir = getTypesDir(ctx);
969
- import_node_fs2.default.rmSync(typegenDir, { recursive: true, force: true });
970
- Object.values(ctx.config.routes).forEach((route) => {
971
- const typesPath = getTypesPath(ctx, route);
972
- const content = generate2(ctx, route);
973
- import_node_fs2.default.mkdirSync(Path5.dirname(typesPath), { recursive: true });
974
- import_node_fs2.default.writeFileSync(typesPath, content);
975
- });
976
- const registerPath = Path5.join(typegenDir, "+register.ts");
977
- import_node_fs2.default.writeFileSync(registerPath, register(ctx));
978
- const virtualPath = Path5.join(typegenDir, "+virtual.d.ts");
979
- import_node_fs2.default.writeFileSync(virtualPath, virtual);
980
- }
981
- function register(ctx) {
982
- const register2 = import_dedent2.default`
983
- import "react-router";
984
-
985
- declare module "react-router" {
986
- interface Register {
987
- params: Params;
988
- }
989
-
990
- interface Future {
991
- unstable_middleware: ${ctx.config.future.unstable_middleware}
992
- }
993
- }
994
- `;
995
- const { t: t2 } = babel_exports;
996
- const fullpaths = /* @__PURE__ */ new Set();
997
- Object.values(ctx.config.routes).forEach((route) => {
998
- if (route.id !== "root" && !route.path) return;
999
- const lineage2 = lineage(ctx.config.routes, route);
1000
- const fullpath2 = fullpath(lineage2);
1001
- fullpaths.add(fullpath2);
1002
- });
1003
- const typeParams = t2.tsTypeAliasDeclaration(
1004
- t2.identifier("Params"),
1005
- null,
1006
- t2.tsTypeLiteral(
1007
- Array.from(fullpaths).map((fullpath2) => {
1008
- const params = parse2(fullpath2);
1009
- return t2.tsPropertySignature(
1010
- t2.stringLiteral(fullpath2),
1011
- t2.tsTypeAnnotation(
1012
- t2.tsTypeLiteral(
1013
- Object.entries(params).map(([param, isRequired]) => {
1014
- const property = t2.tsPropertySignature(
1015
- t2.stringLiteral(param),
1016
- t2.tsTypeAnnotation(t2.tsStringKeyword())
1017
- );
1018
- property.optional = !isRequired;
1019
- return property;
1020
- })
1021
- )
1022
- )
1023
- );
1024
- })
1025
- )
1026
- );
1027
- return [register2, generate(typeParams).code].join("\n\n");
1028
- }
1029
- var virtual = import_dedent2.default`
1030
- declare module "virtual:react-router/server-build" {
1031
- import { ServerBuild } from "react-router";
1032
- export const assets: ServerBuild["assets"];
1033
- export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"];
1034
- export const basename: ServerBuild["basename"];
1035
- export const entry: ServerBuild["entry"];
1036
- export const future: ServerBuild["future"];
1037
- export const isSpaMode: ServerBuild["isSpaMode"];
1038
- export const prerender: ServerBuild["prerender"];
1039
- export const publicPath: ServerBuild["publicPath"];
1040
- export const routeDiscovery: ServerBuild["routeDiscovery"];
1041
- export const routes: ServerBuild["routes"];
1042
- export const ssr: ServerBuild["ssr"];
1043
- export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
1044
- }
1045
- `;
1046
1223
 
1047
1224
  // vite/node-adapter.ts
1048
1225
  var import_node_events = require("events");
@@ -2030,7 +2207,7 @@ function getRouteChunkNameFromModuleId(id) {
2030
2207
  }
2031
2208
 
2032
2209
  // vite/with-props.ts
2033
- var import_dedent3 = __toESM(require("dedent"));
2210
+ var import_dedent2 = __toESM(require("dedent"));
2034
2211
  var vmod = create("with-props");
2035
2212
  var NAMED_COMPONENT_EXPORTS = ["HydrateFallback", "ErrorBoundary"];
2036
2213
  var plugin = {
@@ -2041,7 +2218,7 @@ var plugin = {
2041
2218
  },
2042
2219
  async load(id) {
2043
2220
  if (id !== vmod.resolvedId) return;
2044
- return import_dedent3.default`
2221
+ return import_dedent2.default`
2045
2222
  import { createElement as h } from "react";
2046
2223
  import { useActionData, useLoaderData, useMatches, useParams, useRouteError } from "react-router";
2047
2224
 
@@ -2201,7 +2378,7 @@ var isRouteVirtualModule = (id) => {
2201
2378
  return isRouteEntryModuleId(id) || isRouteChunkModuleId(id);
2202
2379
  };
2203
2380
  var isServerBuildVirtualModuleId = (id) => {
2204
- return id.split("?")[0] === virtual2.serverBuild.id;
2381
+ return id.split("?")[0] === virtual.serverBuild.id;
2205
2382
  };
2206
2383
  var getServerBuildFile = (viteManifest) => {
2207
2384
  let serverBuildIds = Object.keys(viteManifest).filter(
@@ -2231,13 +2408,13 @@ var resolveRelativeRouteFilePath = (route, reactRouterConfig) => {
2231
2408
  let fullPath = path5.resolve(reactRouterConfig.appDirectory, file);
2232
2409
  return vite2.normalizePath(fullPath);
2233
2410
  };
2234
- var virtual2 = {
2411
+ var virtual = {
2235
2412
  serverBuild: create("server-build"),
2236
2413
  serverManifest: create("server-manifest"),
2237
2414
  browserManifest: create("browser-manifest")
2238
2415
  };
2239
2416
  var invalidateVirtualModules = (viteDevServer) => {
2240
- Object.values(virtual2).forEach((vmod2) => {
2417
+ Object.values(virtual).forEach((vmod2) => {
2241
2418
  let mod = viteDevServer.moduleGraph.getModuleById(vmod2.resolvedId);
2242
2419
  if (mod) {
2243
2420
  viteDevServer.moduleGraph.invalidateModule(mod);
@@ -2412,7 +2589,7 @@ var defaultEntriesDir = path5.resolve(
2412
2589
  "config",
2413
2590
  "defaults"
2414
2591
  );
2415
- var defaultEntries = fse.readdirSync(defaultEntriesDir).map((filename3) => path5.join(defaultEntriesDir, filename3));
2592
+ var defaultEntries = fse.readdirSync(defaultEntriesDir).map((filename2) => path5.join(defaultEntriesDir, filename2));
2416
2593
  invariant(defaultEntries.length > 0, "No default entries found");
2417
2594
  var reactRouterDevLoadContext = () => void 0;
2418
2595
  var reactRouterVitePlugin = () => {
@@ -2508,7 +2685,7 @@ var reactRouterVitePlugin = () => {
2508
2685
  }
2509
2686
  }).join("\n")}
2510
2687
  export { default as assets } from ${JSON.stringify(
2511
- virtual2.serverManifest.id
2688
+ virtual.serverManifest.id
2512
2689
  )};
2513
2690
  export const assetsBuildDirectory = ${JSON.stringify(
2514
2691
  path5.relative(
@@ -2578,10 +2755,11 @@ var reactRouterVitePlugin = () => {
2578
2755
  let sriManifest = {};
2579
2756
  for (const entry of entries) {
2580
2757
  if (entry.isFile() && entry.name.endsWith(".js")) {
2758
+ const entryNormalizedPath = "parentPath" in entry && typeof entry.parentPath === "string" ? entry.parentPath : entry.path;
2581
2759
  let contents;
2582
2760
  try {
2583
2761
  contents = await fse.readFile(
2584
- path5.join(entry.path, entry.name),
2762
+ path5.join(entryNormalizedPath, entry.name),
2585
2763
  "utf-8"
2586
2764
  );
2587
2765
  } catch (e) {
@@ -2590,7 +2768,10 @@ var reactRouterVitePlugin = () => {
2590
2768
  }
2591
2769
  let hash = (0, import_node_crypto.createHash)("sha384").update(contents).digest().toString("base64");
2592
2770
  let filepath = getVite().normalizePath(
2593
- path5.relative(clientBuildDirectory, path5.join(entry.path, entry.name))
2771
+ path5.relative(
2772
+ clientBuildDirectory,
2773
+ path5.join(entryNormalizedPath, entry.name)
2774
+ )
2594
2775
  );
2595
2776
  sriManifest[`${ctx2.publicPath}${filepath}`] = `sha384-${hash}`;
2596
2777
  }
@@ -2790,7 +2971,7 @@ var reactRouterVitePlugin = () => {
2790
2971
  let sri = void 0;
2791
2972
  let reactRouterManifestForDev = {
2792
2973
  version: String(Math.random()),
2793
- url: combineURLs(ctx.publicPath, virtual2.browserManifest.url),
2974
+ url: combineURLs(ctx.publicPath, virtual.browserManifest.url),
2794
2975
  hmr: {
2795
2976
  runtime: combineURLs(ctx.publicPath, virtualInjectHmrRuntime.url)
2796
2977
  },
@@ -3171,11 +3352,11 @@ var reactRouterVitePlugin = () => {
3171
3352
  return;
3172
3353
  }
3173
3354
  build = await ssrEnvironment.runner.import(
3174
- virtual2.serverBuild.id
3355
+ virtual.serverBuild.id
3175
3356
  );
3176
3357
  } else {
3177
3358
  build = await viteDevServer.ssrLoadModule(
3178
- virtual2.serverBuild.id
3359
+ virtual.serverBuild.id
3179
3360
  );
3180
3361
  }
3181
3362
  let handler = (0, import_react_router2.createRequestHandler)(build, "development");
@@ -3210,36 +3391,82 @@ var reactRouterVitePlugin = () => {
3210
3391
  let serverBuildDirectory = future.unstable_viteEnvironmentApi ? this.environment.config?.build?.outDir : ctx.environmentBuildContext?.options.build?.outDir ?? getServerBuildDirectory(ctx.reactRouterConfig);
3211
3392
  let ssrViteManifest = await loadViteManifest(serverBuildDirectory);
3212
3393
  let ssrAssetPaths = getViteManifestAssetPaths(ssrViteManifest);
3394
+ let userSsrEmitAssets = (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.ssrEmitAssets ?? viteUserConfig.environments?.ssr?.build?.emitAssets : null) ?? viteUserConfig.build?.ssrEmitAssets ?? false;
3213
3395
  let movedAssetPaths = [];
3396
+ let removedAssetPaths = [];
3397
+ let copiedAssetPaths = [];
3214
3398
  for (let ssrAssetPath of ssrAssetPaths) {
3215
3399
  let src = path5.join(serverBuildDirectory, ssrAssetPath);
3216
3400
  let dest = path5.join(clientBuildDirectory, ssrAssetPath);
3217
- if (!fse.existsSync(dest)) {
3218
- await fse.move(src, dest);
3219
- movedAssetPaths.push(dest);
3220
- } else {
3221
- await fse.remove(src);
3401
+ if (!userSsrEmitAssets) {
3402
+ if (!fse.existsSync(dest)) {
3403
+ await fse.move(src, dest);
3404
+ movedAssetPaths.push(dest);
3405
+ } else {
3406
+ await fse.remove(src);
3407
+ removedAssetPaths.push(dest);
3408
+ }
3409
+ } else if (!fse.existsSync(dest)) {
3410
+ await fse.copy(src, dest);
3411
+ copiedAssetPaths.push(dest);
3222
3412
  }
3223
3413
  }
3224
- let ssrCssPaths = Object.values(ssrViteManifest).flatMap(
3225
- (chunk) => chunk.css ?? []
3226
- );
3414
+ if (!userSsrEmitAssets) {
3415
+ let ssrCssPaths = Object.values(ssrViteManifest).flatMap(
3416
+ (chunk) => chunk.css ?? []
3417
+ );
3418
+ await Promise.all(
3419
+ ssrCssPaths.map(async (cssPath) => {
3420
+ let src = path5.join(serverBuildDirectory, cssPath);
3421
+ await fse.remove(src);
3422
+ removedAssetPaths.push(src);
3423
+ })
3424
+ );
3425
+ }
3426
+ let cleanedAssetPaths = [...removedAssetPaths, ...movedAssetPaths];
3427
+ let handledAssetPaths = [...cleanedAssetPaths, ...copiedAssetPaths];
3428
+ let cleanedAssetDirs = new Set(cleanedAssetPaths.map(path5.dirname));
3227
3429
  await Promise.all(
3228
- ssrCssPaths.map(
3229
- (cssPath) => fse.remove(path5.join(serverBuildDirectory, cssPath))
3230
- )
3430
+ Array.from(cleanedAssetDirs).map(async (dir) => {
3431
+ try {
3432
+ const files = await fse.readdir(dir);
3433
+ if (files.length === 0) {
3434
+ await fse.remove(dir);
3435
+ }
3436
+ } catch {
3437
+ }
3438
+ })
3231
3439
  );
3232
- if (movedAssetPaths.length) {
3233
- viteConfig.logger.info(
3234
- [
3235
- "",
3236
- `${import_picocolors3.default.green("\u2713")} ${movedAssetPaths.length} asset${movedAssetPaths.length > 1 ? "s" : ""} moved from React Router server build to client assets.`,
3237
- ...movedAssetPaths.map(
3238
- (movedAssetPath) => import_picocolors3.default.dim(path5.relative(ctx.rootDirectory, movedAssetPath))
3239
- ),
3240
- ""
3241
- ].join("\n")
3242
- );
3440
+ if (handledAssetPaths.length) {
3441
+ viteConfig.logger.info("");
3442
+ }
3443
+ function logHandledAssets(paths, message) {
3444
+ invariant(viteConfig);
3445
+ if (paths.length) {
3446
+ viteConfig.logger.info(
3447
+ [
3448
+ `${import_picocolors3.default.green("\u2713")} ${message}`,
3449
+ ...paths.map(
3450
+ (assetPath) => import_picocolors3.default.dim(path5.relative(ctx.rootDirectory, assetPath))
3451
+ )
3452
+ ].join("\n")
3453
+ );
3454
+ }
3455
+ }
3456
+ logHandledAssets(
3457
+ removedAssetPaths,
3458
+ `${removedAssetPaths.length} asset${removedAssetPaths.length > 1 ? "s" : ""} cleaned from React Router server build.`
3459
+ );
3460
+ logHandledAssets(
3461
+ movedAssetPaths,
3462
+ `${movedAssetPaths.length} asset${movedAssetPaths.length > 1 ? "s" : ""} moved from React Router server build to client assets.`
3463
+ );
3464
+ logHandledAssets(
3465
+ copiedAssetPaths,
3466
+ `${copiedAssetPaths.length} asset${copiedAssetPaths.length > 1 ? "s" : ""} copied from React Router server build to client assets.`
3467
+ );
3468
+ if (handledAssetPaths.length) {
3469
+ viteConfig.logger.info("");
3243
3470
  }
3244
3471
  process.env.IS_RR_BUILD_REQUEST = "yes";
3245
3472
  if (isPrerenderingEnabled(ctx.reactRouterConfig)) {
@@ -3400,16 +3627,16 @@ var reactRouterVitePlugin = () => {
3400
3627
  name: "react-router:virtual-modules",
3401
3628
  enforce: "pre",
3402
3629
  resolveId(id) {
3403
- const vmod2 = Object.values(virtual2).find((vmod3) => vmod3.id === id);
3630
+ const vmod2 = Object.values(virtual).find((vmod3) => vmod3.id === id);
3404
3631
  if (vmod2) return vmod2.resolvedId;
3405
3632
  },
3406
3633
  async load(id) {
3407
3634
  switch (id) {
3408
- case virtual2.serverBuild.resolvedId: {
3635
+ case virtual.serverBuild.resolvedId: {
3409
3636
  let routeIds = getServerBundleRouteIds(this, ctx);
3410
3637
  return await getServerEntry({ routeIds });
3411
3638
  }
3412
- case virtual2.serverManifest.resolvedId: {
3639
+ case virtual.serverManifest.resolvedId: {
3413
3640
  let routeIds = getServerBundleRouteIds(this, ctx);
3414
3641
  let reactRouterManifest = viteCommand === "build" ? (await generateReactRouterManifestsForBuild({
3415
3642
  routeIds
@@ -3427,7 +3654,7 @@ var reactRouterVitePlugin = () => {
3427
3654
  es6: true
3428
3655
  })};`;
3429
3656
  }
3430
- case virtual2.browserManifest.resolvedId: {
3657
+ case virtual.browserManifest.resolvedId: {
3431
3658
  if (viteCommand === "build") {
3432
3659
  throw new Error("This module only exists in development");
3433
3660
  }
@@ -3858,16 +4085,16 @@ async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory
3858
4085
  let response = await handler(request);
3859
4086
  let html = await response.text();
3860
4087
  let isPrerenderSpaFallback = build.prerender.includes("/");
3861
- let filename3 = isPrerenderSpaFallback ? "__spa-fallback.html" : "index.html";
4088
+ let filename2 = isPrerenderSpaFallback ? "__spa-fallback.html" : "index.html";
3862
4089
  if (response.status !== 200) {
3863
4090
  if (isPrerenderSpaFallback) {
3864
4091
  throw new Error(
3865
- `Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
4092
+ `Prerender: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename2}\` file.
3866
4093
  ` + html
3867
4094
  );
3868
4095
  } else {
3869
4096
  throw new Error(
3870
- `SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename3}\` file.
4097
+ `SPA Mode: Received a ${response.status} status code from \`entry.server.tsx\` while prerendering your \`${filename2}\` file.
3871
4098
  ` + html
3872
4099
  );
3873
4100
  }
@@ -3877,9 +4104,9 @@ async function handleSpaMode(viteConfig, reactRouterConfig, serverBuildDirectory
3877
4104
  "SPA Mode: Did you forget to include `<Scripts/>` in your root route? Your pre-rendered HTML cannot hydrate without `<Scripts />`."
3878
4105
  );
3879
4106
  }
3880
- await fse.writeFile(path5.join(clientBuildDirectory, filename3), html);
4107
+ await fse.writeFile(path5.join(clientBuildDirectory, filename2), html);
3881
4108
  let prettyDir = path5.relative(process.cwd(), clientBuildDirectory);
3882
- let prettyPath = path5.join(prettyDir, filename3);
4109
+ let prettyPath = path5.join(prettyDir, filename2);
3883
4110
  if (build.prerender.length > 0) {
3884
4111
  viteConfig.logger.info(
3885
4112
  `Prerender (html): SPA Fallback -> ${import_picocolors3.default.bold(prettyPath)}`
@@ -4485,7 +4712,7 @@ async function getEnvironmentOptionsResolvers(ctx, viteCommand) {
4485
4712
  copyPublicDir: false,
4486
4713
  // Assets in the public directory are only used by the client
4487
4714
  rollupOptions: {
4488
- input: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.rollupOptions?.input : viteUserConfig.build?.rollupOptions?.input) ?? virtual2.serverBuild.id,
4715
+ input: (ctx.reactRouterConfig.future.unstable_viteEnvironmentApi ? viteUserConfig.environments?.ssr?.build?.rollupOptions?.input : viteUserConfig.build?.rollupOptions?.input) ?? virtual.serverBuild.id,
4489
4716
  output: {
4490
4717
  entryFileNames: serverBuildFile,
4491
4718
  format: serverModuleFormat