@react-router/dev 0.0.0-experimental-073f56f6c → 0.0.0-experimental-ce4015162

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