@react-router/dev 7.15.1 → 8.0.0-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.
@@ -0,0 +1,859 @@
1
+ /**
2
+ * @react-router/dev v8.0.0-pre.0
3
+ *
4
+ * Copyright (c) Remix Software Inc.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE.md file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ import { c as setAppDirectory, l as validateRouteConfig, t as configRoutesToRouteManifest, u as invariant } from "./routes-DXogguGb.js";
12
+ import { createRequire } from "node:module";
13
+ import fs from "node:fs";
14
+ import colors from "picocolors";
15
+ import fs$1 from "node:fs/promises";
16
+ import { readPackageJSON, sortPackage, updatePackage } from "pkg-types";
17
+ import { execSync } from "node:child_process";
18
+ import * as Path from "pathe";
19
+ import path from "pathe";
20
+ import chokidar from "chokidar";
21
+ import pick from "lodash/pick.js";
22
+ import omit from "lodash/omit.js";
23
+ import cloneDeep from "lodash/cloneDeep.js";
24
+ import isEqual from "lodash/isEqual.js";
25
+ import ts from "dedent";
26
+ import * as Pathe from "pathe/utils";
27
+ import { parse as parse$1 } from "@babel/parser";
28
+ import * as t$1 from "@babel/types";
29
+ import _traverse from "@babel/traverse";
30
+ import _generate from "@babel/generator";
31
+ //#region \0rolldown/runtime.js
32
+ var __defProp = Object.defineProperty;
33
+ var __exportAll = (all, no_symbols) => {
34
+ let target = {};
35
+ for (var name in all) __defProp(target, name, {
36
+ get: all[name],
37
+ enumerable: true
38
+ });
39
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
40
+ return target;
41
+ };
42
+ //#endregion
43
+ //#region config/is-react-router-repo.ts
44
+ const nodeRequire$2 = createRequire(import.meta.url);
45
+ function isReactRouterRepo() {
46
+ let serverRuntimePath = path.dirname(nodeRequire$2.resolve("@react-router/node/package.json"));
47
+ return path.basename(path.resolve(serverRuntimePath, "..")) === "packages";
48
+ }
49
+ //#endregion
50
+ //#region vite/vite.ts
51
+ const nodeRequire$1 = createRequire(import.meta.url);
52
+ let vite;
53
+ const viteImportSpecifier = isReactRouterRepo() ? `file:///${path.normalize(nodeRequire$1.resolve("vite/package.json", { paths: [process.cwd()] })).replace("package.json", "dist/node/index.js")}` : "vite";
54
+ async function preloadVite() {
55
+ vite = await import(viteImportSpecifier);
56
+ }
57
+ function getVite() {
58
+ invariant(vite, "getVite() called before preloadVite()");
59
+ return vite;
60
+ }
61
+ function defineCompilerOptions(options) {
62
+ let vite = getVite();
63
+ return parseInt(vite.version.split(".")[0], 10) >= 8 ? { oxc: options.oxc } : { esbuild: options.esbuild };
64
+ }
65
+ function defineOptimizeDepsCompilerOptions(options) {
66
+ let vite = getVite();
67
+ return parseInt(vite.version.split(".")[0], 10) >= 8 ? { rolldownOptions: options.rolldown } : { esbuildOptions: options.esbuild };
68
+ }
69
+ //#endregion
70
+ //#region vite/ssr-externals.ts
71
+ const ssrExternals = isReactRouterRepo() ? [
72
+ "react-router",
73
+ "@react-router/architect",
74
+ "@react-router/cloudflare",
75
+ "@react-router/dev",
76
+ "@react-router/express",
77
+ "@react-router/node",
78
+ "@react-router/serve"
79
+ ] : void 0;
80
+ //#endregion
81
+ //#region vite/vite-runner.ts
82
+ async function createContext$1({ root, mode, customLogger }) {
83
+ await preloadVite();
84
+ const vite = getVite();
85
+ const devServer = await vite.createServer({
86
+ root,
87
+ mode,
88
+ customLogger,
89
+ server: {
90
+ preTransformRequests: false,
91
+ hmr: false,
92
+ watch: null
93
+ },
94
+ ssr: { external: ssrExternals },
95
+ optimizeDeps: { noDiscovery: true },
96
+ css: { postcss: {} },
97
+ configFile: false,
98
+ envFile: false,
99
+ plugins: [],
100
+ environments: { __config_loader: {
101
+ consumer: "server",
102
+ dev: { createEnvironment: (name, config, context) => vite.createRunnableDevEnvironment(name, config) }
103
+ } }
104
+ });
105
+ const environment = devServer.environments.__config_loader;
106
+ if (!vite.isRunnableDevEnvironment(environment)) {
107
+ await devServer.close();
108
+ throw new Error("React Router config loading requires Vite's __config_loader environment to be runnable.");
109
+ }
110
+ return {
111
+ devServer,
112
+ environment,
113
+ runner: environment.runner
114
+ };
115
+ }
116
+ //#endregion
117
+ //#region cli/detectPackageManager.ts
118
+ /**
119
+ * Determine which package manager the user prefers.
120
+ *
121
+ * npm, pnpm and Yarn set the user agent environment variable
122
+ * that can be used to determine which package manager ran
123
+ * the command.
124
+ */
125
+ const detectPackageManager = () => {
126
+ let { npm_config_user_agent } = process.env;
127
+ if (!npm_config_user_agent) return void 0;
128
+ try {
129
+ let pkgManager = npm_config_user_agent.split("/")[0];
130
+ if (pkgManager === "npm") return "npm";
131
+ if (pkgManager === "pnpm") return "pnpm";
132
+ if (pkgManager === "yarn") return "yarn";
133
+ if (pkgManager === "bun") return "bun";
134
+ return;
135
+ } catch {
136
+ return;
137
+ }
138
+ };
139
+ //#endregion
140
+ //#region config/config.ts
141
+ const nodeRequire = createRequire(import.meta.url);
142
+ const excludedConfigPresetKeys = ["presets"];
143
+ const branchRouteProperties = [
144
+ "id",
145
+ "path",
146
+ "file",
147
+ "index"
148
+ ];
149
+ const configRouteToBranchRoute = (configRoute) => pick(configRoute, branchRouteProperties);
150
+ let mergeReactRouterConfig = (...configs) => {
151
+ let reducer = (configA, configB) => {
152
+ let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0;
153
+ return {
154
+ ...configA,
155
+ ...configB,
156
+ ...mergeRequired("buildEnd") ? { buildEnd: async (...args) => {
157
+ await Promise.all([configA.buildEnd?.(...args), configB.buildEnd?.(...args)]);
158
+ } } : {},
159
+ ...mergeRequired("future") ? { future: {
160
+ ...configA.future,
161
+ ...configB.future
162
+ } } : {},
163
+ ...mergeRequired("presets") ? { presets: [...configA.presets ?? [], ...configB.presets ?? []] } : {}
164
+ };
165
+ };
166
+ return configs.reduce(reducer, {});
167
+ };
168
+ let deepFreeze = (o) => {
169
+ Object.freeze(o);
170
+ let oIsFunction = typeof o === "function";
171
+ let hasOwnProp = Object.prototype.hasOwnProperty;
172
+ Object.getOwnPropertyNames(o).forEach(function(prop) {
173
+ if (hasOwnProp.call(o, prop) && (oIsFunction ? prop !== "caller" && prop !== "callee" && prop !== "arguments" : true) && o[prop] !== null && (typeof o[prop] === "object" || typeof o[prop] === "function") && !Object.isFrozen(o[prop])) deepFreeze(o[prop]);
174
+ });
175
+ return o;
176
+ };
177
+ function ok(value) {
178
+ return {
179
+ ok: true,
180
+ value
181
+ };
182
+ }
183
+ function err(error) {
184
+ return {
185
+ ok: false,
186
+ error
187
+ };
188
+ }
189
+ async function resolveConfig({ root, viteRunnerContext, reactRouterConfigFile, skipRoutes, validateConfig }) {
190
+ let reactRouterUserConfig = {};
191
+ if (reactRouterConfigFile) try {
192
+ if (!fs.existsSync(reactRouterConfigFile)) return err(`${reactRouterConfigFile} no longer exists`);
193
+ let configModule = await viteRunnerContext.runner.import(reactRouterConfigFile);
194
+ if (configModule.default === void 0) return err(`${reactRouterConfigFile} must provide a default export`);
195
+ if (typeof configModule.default !== "object") return err(`${reactRouterConfigFile} must export a config`);
196
+ reactRouterUserConfig = configModule.default;
197
+ if (validateConfig) {
198
+ const error = validateConfig(reactRouterUserConfig);
199
+ if (error) return err(error);
200
+ }
201
+ } catch (error) {
202
+ return err(`Error loading ${reactRouterConfigFile}: ${error}`);
203
+ }
204
+ reactRouterUserConfig = deepFreeze(cloneDeep(reactRouterUserConfig));
205
+ let presets = (await Promise.all((reactRouterUserConfig.presets ?? []).map(async (preset) => {
206
+ if (!preset.name) throw new Error("React Router presets must have a `name` property defined.");
207
+ if (!preset.reactRouterConfig) return null;
208
+ return omit(await preset.reactRouterConfig({ reactRouterUserConfig }), excludedConfigPresetKeys);
209
+ }))).filter(function isNotNull(value) {
210
+ return value !== null;
211
+ });
212
+ let defaults = {
213
+ basename: "/",
214
+ buildDirectory: "build",
215
+ serverBuildFile: "index.js",
216
+ serverModuleFormat: "esm",
217
+ ssr: true
218
+ };
219
+ let userAndPresetConfigs = mergeReactRouterConfig(...presets, reactRouterUserConfig);
220
+ let { appDirectory: userAppDirectory, basename, buildDirectory: userBuildDirectory, buildEnd, prerender, routeDiscovery: userRouteDiscovery, serverBuildFile, serverBundles, serverModuleFormat, ssr } = {
221
+ ...defaults,
222
+ ...userAndPresetConfigs
223
+ };
224
+ if (!ssr && serverBundles) serverBundles = void 0;
225
+ if (prerender) {
226
+ let isValidPrerenderPathsConfig = (p) => typeof p === "boolean" || typeof p === "function" || Array.isArray(p);
227
+ if (!(isValidPrerenderPathsConfig(prerender) || typeof prerender === "object" && "paths" in prerender && isValidPrerenderPathsConfig(prerender.paths))) return err("The `prerender`/`prerender.paths` config must be a boolean, an array of string paths, or a function returning a boolean or array of string paths.");
228
+ if (typeof prerender === "object" && "unstable_concurrency" in prerender) return err("The `prerender.unstable_concurrency` config field has been stabilized as `prerender.concurrency`");
229
+ if (!(typeof prerender != "object" || !("concurrency" in prerender) || typeof prerender.concurrency === "number" && Number.isInteger(prerender.concurrency) && prerender.concurrency > 0)) return err("The `prerender.concurrency` config must be a positive integer if specified.");
230
+ }
231
+ let routeDiscovery;
232
+ if (userRouteDiscovery == null) if (ssr) routeDiscovery = {
233
+ mode: "lazy",
234
+ manifestPath: "/__manifest"
235
+ };
236
+ else routeDiscovery = { mode: "initial" };
237
+ else if (userRouteDiscovery.mode === "initial") routeDiscovery = userRouteDiscovery;
238
+ else if (userRouteDiscovery.mode === "lazy") {
239
+ if (!ssr) return err("The `routeDiscovery.mode` config cannot be set to \"lazy\" when setting `ssr:false`");
240
+ let { manifestPath } = userRouteDiscovery;
241
+ if (manifestPath != null && !manifestPath.startsWith("/")) return err("The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., \"/__manifest\")");
242
+ routeDiscovery = userRouteDiscovery;
243
+ }
244
+ let appDirectory = path.resolve(root, userAppDirectory || "app");
245
+ let buildDirectory = path.resolve(root, userBuildDirectory);
246
+ let rootRouteFile = findEntry(appDirectory, "root", { absolute: true });
247
+ if (!rootRouteFile) return err(`Could not find a root route module in the app directory as "${path.relative(root, path.join(appDirectory, "root.tsx"))}"`);
248
+ let routes;
249
+ let routeConfig = [];
250
+ if (skipRoutes) routes = {};
251
+ else {
252
+ let routeConfigFile = findEntry(appDirectory, "routes");
253
+ try {
254
+ if (!routeConfigFile) return err(`Route config file not found at "${path.relative(root, path.join(appDirectory, "routes.ts"))}".`);
255
+ setAppDirectory(appDirectory);
256
+ let routeConfigExport = (await viteRunnerContext.runner.import(path.join(appDirectory, routeConfigFile))).default;
257
+ let result = validateRouteConfig({
258
+ routeConfigFile,
259
+ routeConfig: await routeConfigExport
260
+ });
261
+ if (!result.valid) return err(result.message);
262
+ routeConfig = [{
263
+ id: "root",
264
+ path: "",
265
+ file: path.relative(appDirectory, rootRouteFile),
266
+ children: result.routeConfig
267
+ }];
268
+ routes = configRoutesToRouteManifest(appDirectory, routeConfig);
269
+ } catch (error) {
270
+ return err([
271
+ colors.red(`Route config in "${routeConfigFile}" is invalid.`),
272
+ "",
273
+ error.loc?.file && error.loc?.column && error.frame ? [path.relative(appDirectory, error.loc.file) + ":" + error.loc.line + ":" + error.loc.column, error.frame.trim?.()] : error.stack
274
+ ].flat().join("\n"));
275
+ }
276
+ }
277
+ let futureConfig = userAndPresetConfigs.future;
278
+ if (futureConfig) {
279
+ if ("unstable_splitRouteModules" in futureConfig || "v8_splitRouteModules" in futureConfig) return err("The `future.v8_splitRouteModules` flag has been moved to a top-level `config.splitRouteModules` field (default `true`)");
280
+ if ("unstable_viteEnvironmentApi" in futureConfig || "v8_viteEnvironmentApi" in futureConfig) return err("The `future.v8_viteEnvironmentApi` flag has been removed because Vite Environment API usage is now always enabled");
281
+ if ("unstable_passThroughRequests" in futureConfig || "v8_passThroughRequests" in futureConfig) return err("The `future.v8_passThroughRequests` flag has been removed because pass-through requests are now the default behavior");
282
+ if ("unstable_middleware" in futureConfig || "v8_middleware" in futureConfig) return err("The `future.v8_middleware` flag has been removed because middleware is now always enabled");
283
+ if ("unstable_trailingSlashAwareDataRequests" in futureConfig || "v8_trailingSlashAwareDataRequests" in futureConfig) return err("The `future.v8_trailingSlashAwareDataRequests` flag has been removed because trailing slash-aware data requests are now the default behavior");
284
+ if ("unstable_subResourceIntegrity" in futureConfig) return err("The `future.unstable_subResourceIntegrity` flag has been stabilized and moved to a top-level `config.subResourceIntegrity` field");
285
+ }
286
+ let future = { unstable_optimizeDeps: userAndPresetConfigs.future?.unstable_optimizeDeps ?? false };
287
+ let allowedActionOrigins = userAndPresetConfigs.allowedActionOrigins ?? false;
288
+ let splitRouteModules = userAndPresetConfigs.splitRouteModules ?? true;
289
+ let subResourceIntegrity = userAndPresetConfigs.subResourceIntegrity ?? false;
290
+ let reactRouterConfig = deepFreeze({
291
+ appDirectory,
292
+ basename,
293
+ buildDirectory,
294
+ buildEnd,
295
+ future,
296
+ prerender,
297
+ routes,
298
+ routeDiscovery,
299
+ serverBuildFile,
300
+ serverBundles,
301
+ serverModuleFormat,
302
+ ssr,
303
+ splitRouteModules,
304
+ subResourceIntegrity,
305
+ allowedActionOrigins,
306
+ unstable_routeConfig: routeConfig
307
+ });
308
+ for (let preset of reactRouterUserConfig.presets ?? []) await preset.reactRouterConfigResolved?.({ reactRouterConfig });
309
+ return ok(reactRouterConfig);
310
+ }
311
+ async function createConfigLoader({ rootDirectory: root, watch, mode, skipRoutes, validateConfig }) {
312
+ root = path.normalize(root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd());
313
+ let vite = await import("vite");
314
+ let viteRunnerContext = await createContext$1({
315
+ root,
316
+ mode,
317
+ customLogger: vite.createLogger("warn", { prefix: "[react-router]" })
318
+ });
319
+ let reactRouterConfigFile;
320
+ let updateReactRouterConfigFile = () => {
321
+ reactRouterConfigFile = findEntry(root, "react-router.config", { absolute: true });
322
+ };
323
+ updateReactRouterConfigFile();
324
+ let getConfig = () => resolveConfig({
325
+ root,
326
+ viteRunnerContext,
327
+ reactRouterConfigFile,
328
+ skipRoutes,
329
+ validateConfig
330
+ });
331
+ let appDirectory;
332
+ let initialConfigResult = await getConfig();
333
+ if (!initialConfigResult.ok) throw new Error(initialConfigResult.error);
334
+ appDirectory = path.normalize(initialConfigResult.value.appDirectory);
335
+ let currentConfig = initialConfigResult.value;
336
+ let fsWatcher;
337
+ let changeHandlers = [];
338
+ return {
339
+ getConfig,
340
+ onChange: (handler) => {
341
+ if (!watch) throw new Error("onChange is not supported when watch mode is disabled");
342
+ changeHandlers.push(handler);
343
+ if (!fsWatcher) {
344
+ fsWatcher = chokidar.watch([root, appDirectory], {
345
+ ignoreInitial: true,
346
+ ignored: (path) => isIgnoredByWatcher(path, {
347
+ root,
348
+ appDirectory
349
+ })
350
+ });
351
+ fsWatcher.on("error", (error) => {
352
+ let message = error instanceof Error ? error.message : String(error);
353
+ console.warn(colors.yellow(`File watcher error: ${message}`));
354
+ });
355
+ fsWatcher.on("all", async (...args) => {
356
+ let [event, rawFilepath] = args;
357
+ let filepath = path.normalize(rawFilepath);
358
+ let fileAddedOrRemoved = event === "add" || event === "unlink";
359
+ let appFileAddedOrRemoved = fileAddedOrRemoved && filepath.startsWith(path.normalize(appDirectory));
360
+ let rootRelativeFilepath = path.relative(root, filepath);
361
+ let configFileAddedOrRemoved = fileAddedOrRemoved && isEntryFile("react-router.config", rootRelativeFilepath);
362
+ if (configFileAddedOrRemoved) updateReactRouterConfigFile();
363
+ if (!(configFileAddedOrRemoved || Boolean(viteRunnerContext.environment.moduleGraph.getModuleById(filepath))) && !appFileAddedOrRemoved) return;
364
+ viteRunnerContext.environment.moduleGraph.invalidateAll();
365
+ viteRunnerContext.runner.clearCache();
366
+ let result = await getConfig();
367
+ let prevAppDirectory = appDirectory;
368
+ appDirectory = path.normalize((result.value ?? currentConfig).appDirectory);
369
+ if (appDirectory !== prevAppDirectory) {
370
+ fsWatcher.unwatch(prevAppDirectory);
371
+ fsWatcher.add(appDirectory);
372
+ }
373
+ let configCodeChanged = configFileAddedOrRemoved || reactRouterConfigFile !== void 0 && isEntryFileDependency(viteRunnerContext.environment.moduleGraph, reactRouterConfigFile, filepath);
374
+ let routeConfigFile = !skipRoutes ? findEntry(appDirectory, "routes", { absolute: true }) : void 0;
375
+ let routeConfigCodeChanged = routeConfigFile !== void 0 && isEntryFileDependency(viteRunnerContext.environment.moduleGraph, routeConfigFile, filepath);
376
+ let configChanged = result.ok && !isEqual(omitRoutes(currentConfig), omitRoutes(result.value));
377
+ let routeConfigChanged = result.ok && !isEqual(currentConfig?.routes, result.value.routes);
378
+ for (let handler of changeHandlers) handler({
379
+ result,
380
+ configCodeChanged,
381
+ routeConfigCodeChanged,
382
+ configChanged,
383
+ routeConfigChanged,
384
+ path: filepath,
385
+ event
386
+ });
387
+ if (result.ok) currentConfig = result.value;
388
+ });
389
+ }
390
+ return () => {
391
+ changeHandlers = changeHandlers.filter((changeHandler) => changeHandler !== handler);
392
+ };
393
+ },
394
+ close: async () => {
395
+ changeHandlers = [];
396
+ await viteRunnerContext.devServer.close();
397
+ await fsWatcher?.close();
398
+ }
399
+ };
400
+ }
401
+ async function loadConfig({ rootDirectory, mode, skipRoutes }) {
402
+ let configLoader = await createConfigLoader({
403
+ rootDirectory,
404
+ mode,
405
+ skipRoutes,
406
+ watch: false
407
+ });
408
+ let config = await configLoader.getConfig();
409
+ await configLoader.close();
410
+ return config;
411
+ }
412
+ async function resolveEntryFiles({ rootDirectory, reactRouterConfig }) {
413
+ let { appDirectory } = reactRouterConfig;
414
+ let defaultsDirectory = path.resolve(path.dirname(nodeRequire.resolve("@react-router/dev/package.json")), "dist", "config", "defaults");
415
+ let userEntryClientFile = findEntry(appDirectory, "entry.client");
416
+ let userEntryServerFile = findEntry(appDirectory, "entry.server");
417
+ let entryServerFile;
418
+ let entryClientFile = userEntryClientFile || "entry.client.tsx";
419
+ if (userEntryServerFile) entryServerFile = userEntryServerFile;
420
+ else {
421
+ let packageJsonPath = findEntry(rootDirectory, "package", {
422
+ extensions: [".json"],
423
+ absolute: true,
424
+ walkParents: true
425
+ });
426
+ if (!packageJsonPath) throw new Error(`Could not find package.json in ${rootDirectory} or any of its parent directories. Please add a package.json, or provide a custom entry.server.tsx/jsx file in your app directory.`);
427
+ let packageJsonDirectory = path.dirname(packageJsonPath);
428
+ let deps = (await readPackageJSON(packageJsonDirectory)).dependencies ?? {};
429
+ if (!deps["@react-router/node"]) throw new Error(`Could not determine server runtime. Please install @react-router/node, or provide a custom entry.server.tsx/jsx file in your app directory.`);
430
+ if (!deps["isbot"]) {
431
+ console.log("adding `isbot@5` to your package.json, you should commit this change");
432
+ await updatePackage(packageJsonPath, (pkg) => {
433
+ pkg.dependencies ??= {};
434
+ pkg.dependencies.isbot = "^5";
435
+ sortPackage(pkg);
436
+ });
437
+ execSync(`${detectPackageManager() ?? "npm"} install`, {
438
+ cwd: packageJsonDirectory,
439
+ stdio: "inherit"
440
+ });
441
+ }
442
+ entryServerFile = `entry.server.node.tsx`;
443
+ }
444
+ return {
445
+ entryClientFilePath: userEntryClientFile ? path.resolve(reactRouterConfig.appDirectory, userEntryClientFile) : path.resolve(defaultsDirectory, entryClientFile),
446
+ entryServerFilePath: userEntryServerFile ? path.resolve(reactRouterConfig.appDirectory, userEntryServerFile) : path.resolve(defaultsDirectory, entryServerFile)
447
+ };
448
+ }
449
+ async function resolveRSCEntryFiles({ reactRouterConfig }) {
450
+ let { appDirectory } = reactRouterConfig;
451
+ let defaultsDirectory = path.resolve(path.dirname(nodeRequire.resolve("@react-router/dev/package.json")), "dist", "config", "default-rsc-entries");
452
+ let userEntryClientFile = findEntry(appDirectory, "entry.client", { absolute: true });
453
+ let userEntryRSCFile = findEntry(appDirectory, "entry.rsc", { absolute: true });
454
+ let userEntrySSRFile = findEntry(appDirectory, "entry.ssr", { absolute: true });
455
+ return {
456
+ client: userEntryClientFile ?? path.join(defaultsDirectory, "entry.client.tsx"),
457
+ rsc: userEntryRSCFile ?? path.join(defaultsDirectory, "entry.rsc.tsx"),
458
+ ssr: userEntrySSRFile ?? path.join(defaultsDirectory, "entry.ssr.tsx")
459
+ };
460
+ }
461
+ function omitRoutes(config) {
462
+ return {
463
+ ...config,
464
+ routes: {}
465
+ };
466
+ }
467
+ const entryExts = [
468
+ ".js",
469
+ ".jsx",
470
+ ".ts",
471
+ ".tsx",
472
+ ".mjs",
473
+ ".mts"
474
+ ];
475
+ function isEntryFile(entryBasename, filename) {
476
+ return entryExts.some((ext) => filename === `${entryBasename}${ext}`);
477
+ }
478
+ function findEntry(dir, basename, options) {
479
+ let currentDir = path.resolve(dir);
480
+ let { root } = path.parse(currentDir);
481
+ while (true) {
482
+ for (let ext of options?.extensions ?? entryExts) {
483
+ let file = path.resolve(currentDir, basename + ext);
484
+ if (fs.existsSync(file)) return options?.absolute ?? false ? file : path.relative(dir, file);
485
+ }
486
+ if (!options?.walkParents) return;
487
+ let parentDir = path.dirname(currentDir);
488
+ if (currentDir === root || parentDir === currentDir) return;
489
+ currentDir = parentDir;
490
+ }
491
+ }
492
+ function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /* @__PURE__ */ new Set()) {
493
+ entryFilepath = path.normalize(entryFilepath);
494
+ filepath = path.normalize(filepath);
495
+ if (visited.has(filepath)) return false;
496
+ visited.add(filepath);
497
+ if (filepath === entryFilepath) return true;
498
+ let mod = moduleGraph.getModuleById(filepath);
499
+ if (!mod) return false;
500
+ for (let importer of mod.importers) {
501
+ if (!importer.id) continue;
502
+ if (importer.id === entryFilepath || isEntryFileDependency(moduleGraph, entryFilepath, importer.id, visited)) return true;
503
+ }
504
+ return false;
505
+ }
506
+ function isIgnoredByWatcher(path$1, { root, appDirectory }) {
507
+ let dirname = path.dirname(path$1);
508
+ if (!dirname.startsWith(appDirectory) && path$1 !== root && dirname !== root) return true;
509
+ try {
510
+ let stat = fs.statSync(path$1, { throwIfNoEntry: false });
511
+ if (stat && !stat.isFile() && !stat.isDirectory()) return true;
512
+ } catch {
513
+ return true;
514
+ }
515
+ return false;
516
+ }
517
+ //#endregion
518
+ //#region typegen/context.ts
519
+ async function createContext({ rootDirectory, watch, mode, rsc }) {
520
+ const configLoader = await createConfigLoader({
521
+ rootDirectory,
522
+ mode,
523
+ watch
524
+ });
525
+ const configResult = await configLoader.getConfig();
526
+ if (!configResult.ok) throw new Error(configResult.error);
527
+ return {
528
+ configLoader,
529
+ rootDirectory,
530
+ config: configResult.value,
531
+ rsc
532
+ };
533
+ }
534
+ //#endregion
535
+ //#region vite/babel.ts
536
+ var babel_exports = /* @__PURE__ */ __exportAll({
537
+ generate: () => generate,
538
+ parse: () => parse$1,
539
+ t: () => t$1,
540
+ traverse: () => traverse
541
+ });
542
+ const traverse = _traverse.default;
543
+ const generate = _generate.default;
544
+ //#endregion
545
+ //#region typegen/params.ts
546
+ function parse(fullpath) {
547
+ const result = {};
548
+ let segments = fullpath.split("/");
549
+ segments.forEach((segment) => {
550
+ const match = segment.match(/^:([\w-]+)(\?)?/);
551
+ if (!match) return;
552
+ const param = match[1];
553
+ const isRequired = match[2] === void 0;
554
+ result[param] ||= isRequired;
555
+ });
556
+ if (segments.at(-1) === "*") result["*"] = true;
557
+ return result;
558
+ }
559
+ //#endregion
560
+ //#region typegen/route.ts
561
+ function lineage(routes, route) {
562
+ const result = [];
563
+ while (route) {
564
+ result.push(route);
565
+ if (!route.parentId) break;
566
+ route = routes[route.parentId];
567
+ }
568
+ result.reverse();
569
+ return result;
570
+ }
571
+ function fullpath(lineage) {
572
+ const route = lineage.at(-1);
573
+ if (lineage.length === 1 && route?.id === "root") return "/";
574
+ if (route && route.index !== true && route.path === void 0) return void 0;
575
+ return "/" + lineage.map((route) => route.path?.replace(/^\//, "")?.replace(/\/$/, "")).filter((path) => path !== void 0 && path !== "").join("/");
576
+ }
577
+ //#endregion
578
+ //#region typegen/generate.ts
579
+ function typesDirectory(ctx) {
580
+ return Path.join(ctx.rootDirectory, ".react-router/types");
581
+ }
582
+ function generateServerBuild(ctx) {
583
+ return {
584
+ filename: Path.join(typesDirectory(ctx), "+server-build.d.ts"),
585
+ content: ts`
586
+ // Generated by React Router
587
+
588
+ declare module "virtual:react-router/server-build" {
589
+ import { ServerBuild } from "react-router";
590
+ export const assets: ServerBuild["assets"];
591
+ export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"];
592
+ export const basename: ServerBuild["basename"];
593
+ export const entry: ServerBuild["entry"];
594
+ export const future: ServerBuild["future"];
595
+ export const isSpaMode: ServerBuild["isSpaMode"];
596
+ export const prerender: ServerBuild["prerender"];
597
+ export const publicPath: ServerBuild["publicPath"];
598
+ export const routeDiscovery: ServerBuild["routeDiscovery"];
599
+ export const routes: ServerBuild["routes"];
600
+ export const ssr: ServerBuild["ssr"];
601
+ export const allowedActionOrigins: ServerBuild["allowedActionOrigins"];
602
+ export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
603
+ }
604
+ `
605
+ };
606
+ }
607
+ const { t } = babel_exports;
608
+ function generateRoutes(ctx) {
609
+ const fileToRoutes = /* @__PURE__ */ new Map();
610
+ const lineages = /* @__PURE__ */ new Map();
611
+ const allPages = /* @__PURE__ */ new Set();
612
+ const routeToPages = /* @__PURE__ */ new Map();
613
+ for (const route of Object.values(ctx.config.routes)) {
614
+ let routeIds = fileToRoutes.get(route.file);
615
+ if (!routeIds) {
616
+ routeIds = /* @__PURE__ */ new Set();
617
+ fileToRoutes.set(route.file, routeIds);
618
+ }
619
+ routeIds.add(route.id);
620
+ const lineage$1 = lineage(ctx.config.routes, route);
621
+ lineages.set(route.id, lineage$1);
622
+ const fullpath$1 = fullpath(lineage$1);
623
+ if (!fullpath$1) continue;
624
+ const pages = expand(fullpath$1);
625
+ pages.forEach((page) => allPages.add(page));
626
+ lineage$1.forEach(({ id }) => {
627
+ let routePages = routeToPages.get(id);
628
+ if (!routePages) {
629
+ routePages = /* @__PURE__ */ new Set();
630
+ routeToPages.set(id, routePages);
631
+ }
632
+ pages.forEach((page) => routePages.add(page));
633
+ });
634
+ }
635
+ return [{
636
+ filename: Path.join(typesDirectory(ctx), "+routes.ts"),
637
+ content: ts`
638
+ // Generated by React Router
639
+
640
+ import "react-router"
641
+
642
+ declare module "react-router" {
643
+ interface Register {
644
+ pages: Pages
645
+ routeFiles: RouteFiles
646
+ routeModules: RouteModules
647
+ }
648
+ }
649
+ ` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({
650
+ fileToRoutes,
651
+ routeToPages
652
+ })).code + "\n\n" + generate(routeModulesType(ctx)).code
653
+ }, ...Array.from(fileToRoutes.entries()).filter(([file]) => isInAppDirectory(ctx, file)).map(([file, routeIds]) => getRouteAnnotations({
654
+ ctx,
655
+ file,
656
+ routeIds,
657
+ lineages
658
+ }))];
659
+ }
660
+ function pagesType(pages) {
661
+ return t.tsTypeAliasDeclaration(t.identifier("Pages"), null, t.tsTypeLiteral(Array.from(pages).map((page) => {
662
+ return t.tsPropertySignature(t.stringLiteral(page), t.tsTypeAnnotation(t.tsTypeLiteral([t.tsPropertySignature(t.identifier("params"), t.tsTypeAnnotation(paramsType(page)))])));
663
+ })));
664
+ }
665
+ function routeFilesType({ fileToRoutes, routeToPages }) {
666
+ return t.tsTypeAliasDeclaration(t.identifier("RouteFiles"), null, t.tsTypeLiteral(Array.from(fileToRoutes).map(([file, routeIds]) => t.tsPropertySignature(t.stringLiteral(file), t.tsTypeAnnotation(t.tsUnionType(Array.from(routeIds).map((routeId) => {
667
+ const pages = routeToPages.get(routeId) ?? /* @__PURE__ */ new Set();
668
+ return t.tsTypeLiteral([t.tsPropertySignature(t.identifier("id"), t.tsTypeAnnotation(t.tsLiteralType(t.stringLiteral(routeId)))), t.tsPropertySignature(t.identifier("page"), t.tsTypeAnnotation(pages.size > 0 ? t.tsUnionType(Array.from(pages).map((page) => t.tsLiteralType(t.stringLiteral(page)))) : t.tsNeverKeyword()))]);
669
+ })))))));
670
+ }
671
+ function routeModulesType(ctx) {
672
+ return t.tsTypeAliasDeclaration(t.identifier("RouteModules"), null, t.tsTypeLiteral(Object.values(ctx.config.routes).map((route) => t.tsPropertySignature(t.stringLiteral(route.id), t.tsTypeAnnotation(isInAppDirectory(ctx, route.file) ? t.tsTypeQuery(t.tsImportType(t.stringLiteral(`./${Path.relative(ctx.rootDirectory, ctx.config.appDirectory)}/${route.file}`))) : t.tsUnknownKeyword())))));
673
+ }
674
+ function isInAppDirectory(ctx, routeFile) {
675
+ return Path.resolve(ctx.config.appDirectory, routeFile).startsWith(ctx.config.appDirectory);
676
+ }
677
+ function getRouteAnnotations({ ctx, file, routeIds, lineages }) {
678
+ const filename = Path.join(typesDirectory(ctx), Path.relative(ctx.rootDirectory, ctx.config.appDirectory), Path.dirname(file), "+types", Pathe.filename(file) + ".ts");
679
+ const matchesType = t.tsTypeAliasDeclaration(t.identifier("Matches"), null, t.tsUnionType(Array.from(routeIds).map((routeId) => {
680
+ const lineage = lineages.get(routeId);
681
+ return t.tsTupleType(lineage.map((route) => t.tsTypeLiteral([t.tsPropertySignature(t.identifier("id"), t.tsTypeAnnotation(t.tsLiteralType(t.stringLiteral(route.id)))), t.tsPropertySignature(t.identifier("module"), t.tsTypeAnnotation(t.tsTypeQuery(t.tsImportType(t.stringLiteral(relativeImportSource(rootDirsPath(ctx, filename), Path.resolve(ctx.config.appDirectory, route.file)))))))])));
682
+ })));
683
+ return {
684
+ filename,
685
+ content: ts`
686
+ // Generated by React Router
687
+
688
+ import type { GetInfo, GetAnnotations } from "react-router/internal";
689
+
690
+ type Module = typeof import("${relativeImportSource(rootDirsPath(ctx, filename), Path.resolve(ctx.config.appDirectory, file))}")
691
+
692
+ type Info = GetInfo<{
693
+ file: "${file}",
694
+ module: Module
695
+ }>
696
+ ` + "\n\n" + generate(matchesType).code + "\n\n" + ts`
697
+ type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }>;
698
+
699
+ export namespace Route {
700
+ // links
701
+ export type LinkDescriptors = Annotations["LinkDescriptors"];
702
+ export type LinksFunction = Annotations["LinksFunction"];
703
+
704
+ // meta
705
+ export type MetaArgs = Annotations["MetaArgs"];
706
+ export type MetaDescriptors = Annotations["MetaDescriptors"];
707
+ export type MetaFunction = Annotations["MetaFunction"];
708
+
709
+ // headers
710
+ export type HeadersArgs = Annotations["HeadersArgs"];
711
+ export type HeadersFunction = Annotations["HeadersFunction"];
712
+
713
+ // middleware
714
+ export type MiddlewareFunction = Annotations["MiddlewareFunction"];
715
+
716
+ // clientMiddleware
717
+ export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
718
+
719
+ // loader
720
+ export type LoaderArgs = Annotations["LoaderArgs"];
721
+
722
+ // clientLoader
723
+ export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
724
+
725
+ // action
726
+ export type ActionArgs = Annotations["ActionArgs"];
727
+
728
+ // clientAction
729
+ export type ClientActionArgs = Annotations["ClientActionArgs"];
730
+
731
+ // HydrateFallback
732
+ export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
733
+
734
+ // ServerHydrateFallback
735
+ export type ServerHydrateFallbackProps = Annotations["ServerHydrateFallbackProps"];
736
+
737
+ // Component
738
+ export type ComponentProps = Annotations["ComponentProps"];
739
+
740
+ // ServerComponent
741
+ export type ServerComponentProps = Annotations["ServerComponentProps"];
742
+
743
+ // ErrorBoundary
744
+ export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
745
+
746
+ // ServerErrorBoundary
747
+ export type ServerErrorBoundaryProps = Annotations["ServerErrorBoundaryProps"];
748
+ }
749
+ `
750
+ };
751
+ }
752
+ function relativeImportSource(from, to) {
753
+ let path = Path.relative(Path.dirname(from), to);
754
+ let extension = Path.extname(path);
755
+ path = Path.join(Path.dirname(path), Path.basename(path, extension));
756
+ if (!path.startsWith("../")) path = "./" + path;
757
+ if (!extension || /\.(js|ts)x?$/.test(extension)) extension = ".js";
758
+ return path + extension;
759
+ }
760
+ function rootDirsPath(ctx, typesPath) {
761
+ const rel = Path.relative(typesDirectory(ctx), typesPath);
762
+ return Path.join(ctx.rootDirectory, rel);
763
+ }
764
+ function paramsType(path) {
765
+ const params = parse(path);
766
+ return t.tsTypeLiteral(Object.entries(params).map(([param, isRequired]) => {
767
+ const property = t.tsPropertySignature(t.stringLiteral(param), t.tsTypeAnnotation(t.tsStringKeyword()));
768
+ property.optional = !isRequired;
769
+ return property;
770
+ }));
771
+ }
772
+ function expand(fullpath) {
773
+ function recurse(segments, index) {
774
+ if (index === segments.length) return [""];
775
+ const segment = segments[index];
776
+ const isOptional = segment.endsWith("?");
777
+ const isDynamic = segment.startsWith(":");
778
+ const required = segment.replace(/\?$/, "");
779
+ const keep = !isOptional || isDynamic;
780
+ const kept = isDynamic ? segment : required;
781
+ const withoutSegment = recurse(segments, index + 1);
782
+ const withSegment = withoutSegment.map((rest) => [kept, rest].join("/"));
783
+ if (keep) return withSegment;
784
+ return [...withoutSegment, ...withSegment];
785
+ }
786
+ const segments = fullpath.split("/");
787
+ const expanded = /* @__PURE__ */ new Set();
788
+ for (let result of recurse(segments, 0)) {
789
+ if (result !== "/") result = result.replace(/\/$/, "");
790
+ expanded.add(result);
791
+ }
792
+ return expanded;
793
+ }
794
+ //#endregion
795
+ //#region typegen/index.ts
796
+ const { green, red } = colors;
797
+ async function clearRouteModuleAnnotations(ctx) {
798
+ await fs$1.rm(Path.join(typesDirectory(ctx), Path.basename(ctx.config.appDirectory)), {
799
+ recursive: true,
800
+ force: true
801
+ });
802
+ }
803
+ async function write(...files) {
804
+ return Promise.all(files.map(async ({ filename, content }) => {
805
+ await fs$1.mkdir(Path.dirname(filename), { recursive: true });
806
+ await fs$1.writeFile(filename, content);
807
+ }));
808
+ }
809
+ async function run(rootDirectory, { mode, rsc }) {
810
+ const ctx = await createContext({
811
+ rootDirectory,
812
+ mode,
813
+ rsc,
814
+ watch: false
815
+ });
816
+ await fs$1.rm(typesDirectory(ctx), {
817
+ recursive: true,
818
+ force: true
819
+ });
820
+ await write(generateServerBuild(ctx), ...generateRoutes(ctx));
821
+ }
822
+ async function watch(rootDirectory, { mode, logger, rsc }) {
823
+ const ctx = await createContext({
824
+ rootDirectory,
825
+ mode,
826
+ rsc,
827
+ watch: true
828
+ });
829
+ await fs$1.rm(typesDirectory(ctx), {
830
+ recursive: true,
831
+ force: true
832
+ });
833
+ await write(generateServerBuild(ctx), ...generateRoutes(ctx));
834
+ logger?.info(green("generated types"), {
835
+ timestamp: true,
836
+ clear: true
837
+ });
838
+ ctx.configLoader.onChange(async ({ result, routeConfigChanged }) => {
839
+ if (!result.ok) {
840
+ logger?.error(red(result.error), {
841
+ timestamp: true,
842
+ clear: true
843
+ });
844
+ return;
845
+ }
846
+ ctx.config = result.value;
847
+ if (routeConfigChanged) {
848
+ await clearRouteModuleAnnotations(ctx);
849
+ await write(...generateRoutes(ctx));
850
+ logger?.info(green("regenerated types"), {
851
+ timestamp: true,
852
+ clear: true
853
+ });
854
+ }
855
+ });
856
+ return { close: async () => await ctx.configLoader.close() };
857
+ }
858
+ //#endregion
859
+ export { t$1 as a, createConfigLoader as c, resolveRSCEntryFiles as d, ssrExternals as f, preloadVite as g, getVite as h, parse$1 as i, loadConfig as l, defineOptimizeDepsCompilerOptions as m, watch as n, traverse as o, defineCompilerOptions as p, generate as r, configRouteToBranchRoute as s, run as t, resolveEntryFiles as u };