@react-router/dev 0.0.0-experimental-d07149147 → 0.0.0-experimental-479e73b7b

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