UNPKG

@react-router/dev

Version:

Dev tools and CLI for React Router

1,599 lines (1,547 loc) • 83 kB
#!/usr/bin/env node /** * @react-router/dev v7.10.0 * * Copyright (c) Remix Software Inc. * * This source code is licensed under the MIT license found in the * LICENSE.md file in the root directory of this source tree. * * @license MIT */ "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); // invariant.ts function invariant(value, message) { if (value === false || value === null || typeof value === "undefined") { console.error( "The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose" ); throw new Error(message); } } var init_invariant = __esm({ "invariant.ts"() { "use strict"; } }); // config/is-react-router-repo.ts function isReactRouterRepo() { let serverRuntimePath = import_pathe.default.dirname( require.resolve("@react-router/node/package.json") ); let serverRuntimeParentDir = import_pathe.default.basename( import_pathe.default.resolve(serverRuntimePath, "..") ); return serverRuntimeParentDir === "packages"; } var import_pathe; var init_is_react_router_repo = __esm({ "config/is-react-router-repo.ts"() { "use strict"; import_pathe = __toESM(require("pathe")); } }); // vite/vite.ts async function preloadVite() { vite = await import(viteImportSpecifier); } function getVite() { invariant(vite, "getVite() called before preloadVite()"); return vite; } var import_pathe2, vite, viteImportSpecifier; var init_vite = __esm({ "vite/vite.ts"() { "use strict"; import_pathe2 = __toESM(require("pathe")); init_invariant(); init_is_react_router_repo(); viteImportSpecifier = isReactRouterRepo() ? ( // Support testing against different versions of Vite by ensuring that Vite // is resolved from the current working directory when running within this // repo. If we don't do this, Vite will always be imported relative to this // file, which means that it will always resolve to Vite 6. `file:///${import_pathe2.default.normalize( require.resolve("vite/package.json", { paths: [process.cwd()] }) ).replace("package.json", "dist/node/index.js")}` ) : "vite"; } }); // vite/ssr-externals.ts var ssrExternals; var init_ssr_externals = __esm({ "vite/ssr-externals.ts"() { "use strict"; init_is_react_router_repo(); ssrExternals = isReactRouterRepo() ? [ // This is only needed within this repo because these packages // are linked to a directory outside of node_modules so Vite // treats them as internal code by default. "react-router", "react-router-dom", "@react-router/architect", "@react-router/cloudflare", "@react-router/dev", "@react-router/express", "@react-router/node", "@react-router/serve" ] : void 0; } }); // vite/vite-node.ts async function createContext({ root, mode, customLogger }) { await preloadVite(); const vite2 = getVite(); const [{ ViteNodeServer }, { ViteNodeRunner }, { installSourcemapsSupport }] = await Promise.all([ import("vite-node/server"), import("vite-node/client"), import("vite-node/source-map") ]); const devServer = await vite2.createServer({ root, mode, customLogger, server: { preTransformRequests: false, hmr: false, watch: null }, ssr: { external: ssrExternals }, optimizeDeps: { noDiscovery: true }, css: { // This empty PostCSS config object prevents the PostCSS config file from // being loaded. We don't need it in a React Router config context, and // there's also an issue in Vite 5 when using a .ts PostCSS config file in // an ESM project: https://github.com/vitejs/vite/issues/15869. Consumers // can work around this in their own Vite config file, but they can't // configure this internal usage of vite-node. postcss: {} }, configFile: false, envFile: false, plugins: [] }); await devServer.pluginContainer.buildStart({}); const server = new ViteNodeServer(devServer); installSourcemapsSupport({ getSourceMap: (source) => server.getSourceMap(source) }); const runner = new ViteNodeRunner({ root: devServer.config.root, base: devServer.config.base, fetchModule(id) { return server.fetchModule(id); }, resolveId(id, importer) { return server.resolveId(id, importer); } }); return { devServer, server, runner }; } var init_vite_node = __esm({ "vite/vite-node.ts"() { "use strict"; init_vite(); init_ssr_externals(); } }); // config/routes.ts function setAppDirectory(directory) { globalThis.__reactRouterAppDirectory = directory; } function validateRouteConfig({ routeConfigFile, routeConfig }) { if (!routeConfig) { return { valid: false, message: `Route config must be the default export in "${routeConfigFile}".` }; } if (!Array.isArray(routeConfig)) { return { valid: false, message: `Route config in "${routeConfigFile}" must be an array.` }; } let { issues } = v.safeParse(resolvedRouteConfigSchema, routeConfig); if (issues?.length) { let { root, nested } = v.flatten(issues); return { valid: false, message: [ `Route config in "${routeConfigFile}" is invalid.`, root ? `${root}` : [], nested ? Object.entries(nested).map( ([path9, message]) => `Path: routes.${path9} ${message}` ) : [] ].flat().join("\n\n") }; } return { valid: true, routeConfig }; } function configRoutesToRouteManifest(appDirectory, routes2) { let routeManifest = {}; function walk(route, parentId) { let id = route.id || createRouteId(route.file); let manifestItem = { id, parentId, file: Path.isAbsolute(route.file) ? Path.relative(appDirectory, route.file) : route.file, path: route.path, index: route.index, caseSensitive: route.caseSensitive }; if (routeManifest.hasOwnProperty(id)) { throw new Error( `Unable to define routes with duplicate route id: "${id}"` ); } routeManifest[id] = manifestItem; if (route.children) { for (let child of route.children) { walk(child, id); } } } for (let route of routes2) { walk(route); } return routeManifest; } function createRouteId(file) { return Path.normalize(stripFileExtension(file)); } function stripFileExtension(file) { return file.replace(/\.[a-z0-9]+$/i, ""); } var Path, v, import_pick, routeConfigEntrySchema, resolvedRouteConfigSchema; var init_routes = __esm({ "config/routes.ts"() { "use strict"; Path = __toESM(require("pathe")); v = __toESM(require("valibot")); import_pick = __toESM(require("lodash/pick")); init_invariant(); routeConfigEntrySchema = v.pipe( v.custom((value) => { return !(typeof value === "object" && value !== null && "then" in value && "catch" in value); }, "Invalid type: Expected object but received a promise. Did you forget to await?"), v.object({ id: v.optional( v.pipe( v.string(), v.notValue("root", "A route cannot use the reserved id 'root'.") ) ), path: v.optional(v.string()), index: v.optional(v.boolean()), caseSensitive: v.optional(v.boolean()), file: v.string(), children: v.optional(v.array(v.lazy(() => routeConfigEntrySchema))) }) ); resolvedRouteConfigSchema = v.array(routeConfigEntrySchema); } }); // cli/detectPackageManager.ts var init_detectPackageManager = __esm({ "cli/detectPackageManager.ts"() { "use strict"; } }); // config/config.ts function ok(value) { return { ok: true, value }; } function err(error) { return { ok: false, error }; } async function resolveConfig({ root, viteNodeContext, reactRouterConfigFile, skipRoutes, validateConfig }) { let reactRouterUserConfig = {}; if (reactRouterConfigFile) { try { if (!import_node_fs.default.existsSync(reactRouterConfigFile)) { return err(`${reactRouterConfigFile} no longer exists`); } let configModule = await viteNodeContext.runner.executeFile( reactRouterConfigFile ); if (configModule.default === void 0) { return err(`${reactRouterConfigFile} must provide a default export`); } if (typeof configModule.default !== "object") { return err(`${reactRouterConfigFile} must export a config`); } reactRouterUserConfig = configModule.default; if (validateConfig) { const error = validateConfig(reactRouterUserConfig); if (error) { return err(error); } } } catch (error) { return err(`Error loading ${reactRouterConfigFile}: ${error}`); } } reactRouterUserConfig = deepFreeze((0, import_cloneDeep.default)(reactRouterUserConfig)); let presets = (await Promise.all( (reactRouterUserConfig.presets ?? []).map(async (preset) => { if (!preset.name) { throw new Error( "React Router presets must have a `name` property defined." ); } if (!preset.reactRouterConfig) { return null; } let configPreset = (0, import_omit.default)( await preset.reactRouterConfig({ reactRouterUserConfig }), excludedConfigPresetKeys ); return configPreset; }) )).filter(function isNotNull(value) { return value !== null; }); let defaults = { basename: "/", buildDirectory: "build", serverBuildFile: "index.js", serverModuleFormat: "esm", ssr: true }; let userAndPresetConfigs = mergeReactRouterConfig( ...presets, reactRouterUserConfig ); let { appDirectory: userAppDirectory, basename: basename3, buildDirectory: userBuildDirectory, buildEnd, prerender, routeDiscovery: userRouteDiscovery, serverBuildFile, serverBundles, serverModuleFormat, ssr } = { ...defaults, // Default values should be completely overridden by user/preset config, not merged ...userAndPresetConfigs }; if (!ssr && serverBundles) { serverBundles = void 0; } if (prerender) { let isValidPrerenderPathsConfig = (p) => typeof p === "boolean" || typeof p === "function" || Array.isArray(p); let isValidPrerenderConfig = isValidPrerenderPathsConfig(prerender) || typeof prerender === "object" && "paths" in prerender && isValidPrerenderPathsConfig(prerender.paths); if (!isValidPrerenderConfig) { 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." ); } let isValidConcurrencyConfig = typeof prerender != "object" || !("unstable_concurrency" in prerender) || typeof prerender.unstable_concurrency === "number" && Number.isInteger(prerender.unstable_concurrency) && prerender.unstable_concurrency > 0; if (!isValidConcurrencyConfig) { return err( "The `prerender.unstable_concurrency` config must be a positive integer if specified." ); } } let routeDiscovery; if (userRouteDiscovery == null) { if (ssr) { routeDiscovery = { mode: "lazy", manifestPath: "/__manifest" }; } else { routeDiscovery = { mode: "initial" }; } } else if (userRouteDiscovery.mode === "initial") { routeDiscovery = userRouteDiscovery; } else if (userRouteDiscovery.mode === "lazy") { if (!ssr) { return err( 'The `routeDiscovery.mode` config cannot be set to "lazy" when setting `ssr:false`' ); } let { manifestPath } = userRouteDiscovery; if (manifestPath != null && !manifestPath.startsWith("/")) { return err( 'The `routeDiscovery.manifestPath` config must be a root-relative pathname beginning with a slash (i.e., "/__manifest")' ); } routeDiscovery = userRouteDiscovery; } let appDirectory = import_pathe3.default.resolve(root, userAppDirectory || "app"); let buildDirectory = import_pathe3.default.resolve(root, userBuildDirectory); let rootRouteFile = findEntry(appDirectory, "root", { absolute: true }); if (!rootRouteFile) { let rootRouteDisplayPath = import_pathe3.default.relative( root, import_pathe3.default.join(appDirectory, "root.tsx") ); return err( `Could not find a root route module in the app directory as "${rootRouteDisplayPath}"` ); } let routes2; let routeConfig = []; if (skipRoutes) { routes2 = {}; } else { let routeConfigFile = findEntry(appDirectory, "routes"); try { if (!routeConfigFile) { let routeConfigDisplayPath = import_pathe3.default.relative( root, import_pathe3.default.join(appDirectory, "routes.ts") ); return err( `Route config file not found at "${routeConfigDisplayPath}".` ); } setAppDirectory(appDirectory); let routeConfigExport = (await viteNodeContext.runner.executeFile( import_pathe3.default.join(appDirectory, routeConfigFile) )).default; let result = validateRouteConfig({ routeConfigFile, routeConfig: await routeConfigExport }); if (!result.valid) { return err(result.message); } routeConfig = [ { id: "root", path: "", file: import_pathe3.default.relative(appDirectory, rootRouteFile), children: result.routeConfig } ]; routes2 = configRoutesToRouteManifest(appDirectory, routeConfig); } catch (error) { return err( [ import_picocolors.default.red(`Route config in "${routeConfigFile}" is invalid.`), "", error.loc?.file && error.loc?.column && error.frame ? [ import_pathe3.default.relative(appDirectory, error.loc.file) + ":" + error.loc.line + ":" + error.loc.column, error.frame.trim?.() ] : error.stack ].flat().join("\n") ); } } let futureConfig = userAndPresetConfigs.future; if (futureConfig?.unstable_splitRouteModules !== void 0) { return err( 'The "future.unstable_splitRouteModules" flag has been stabilized as "future.v8_splitRouteModules"' ); } if (futureConfig?.unstable_viteEnvironmentApi !== void 0) { return err( 'The "future.unstable_viteEnvironmentApi" flag has been stabilized as "future.v8_viteEnvironmentApi"' ); } let future = { unstable_optimizeDeps: userAndPresetConfigs.future?.unstable_optimizeDeps ?? false, unstable_subResourceIntegrity: userAndPresetConfigs.future?.unstable_subResourceIntegrity ?? false, v8_middleware: userAndPresetConfigs.future?.v8_middleware ?? false, v8_splitRouteModules: userAndPresetConfigs.future?.v8_splitRouteModules ?? false, v8_viteEnvironmentApi: userAndPresetConfigs.future?.v8_viteEnvironmentApi ?? false }; let reactRouterConfig = deepFreeze({ appDirectory, basename: basename3, buildDirectory, buildEnd, future, prerender, routes: routes2, routeDiscovery, serverBuildFile, serverBundles, serverModuleFormat, ssr, unstable_routeConfig: routeConfig }); for (let preset of reactRouterUserConfig.presets ?? []) { await preset.reactRouterConfigResolved?.({ reactRouterConfig }); } return ok(reactRouterConfig); } async function createConfigLoader({ rootDirectory: root, watch: watch2, mode, skipRoutes, validateConfig }) { root = import_pathe3.default.normalize(root ?? process.env.REACT_ROUTER_ROOT ?? process.cwd()); let vite2 = await import("vite"); let viteNodeContext = await createContext({ root, mode, // Filter out any info level logs from vite-node customLogger: vite2.createLogger("warn", { prefix: "[react-router]" }) }); let reactRouterConfigFile; let updateReactRouterConfigFile = () => { reactRouterConfigFile = findEntry(root, "react-router.config", { absolute: true }); }; updateReactRouterConfigFile(); let getConfig = () => resolveConfig({ root, viteNodeContext, reactRouterConfigFile, skipRoutes, validateConfig }); let appDirectory; let initialConfigResult = await getConfig(); if (!initialConfigResult.ok) { throw new Error(initialConfigResult.error); } appDirectory = import_pathe3.default.normalize(initialConfigResult.value.appDirectory); let currentConfig = initialConfigResult.value; let fsWatcher; let changeHandlers = []; return { getConfig, onChange: (handler) => { if (!watch2) { throw new Error( "onChange is not supported when watch mode is disabled" ); } changeHandlers.push(handler); if (!fsWatcher) { fsWatcher = import_chokidar.default.watch([root, appDirectory], { ignoreInitial: true, ignored: (path9) => { let dirname5 = import_pathe3.default.dirname(path9); return !dirname5.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory // that are at the root level, not nested in subdirectories path9 !== root && // Watch the root directory itself dirname5 !== root; } }); fsWatcher.on("all", async (...args) => { let [event, rawFilepath] = args; let filepath = import_pathe3.default.normalize(rawFilepath); let fileAddedOrRemoved = event === "add" || event === "unlink"; let appFileAddedOrRemoved = fileAddedOrRemoved && filepath.startsWith(import_pathe3.default.normalize(appDirectory)); let rootRelativeFilepath = import_pathe3.default.relative(root, filepath); let configFileAddedOrRemoved = fileAddedOrRemoved && isEntryFile("react-router.config", rootRelativeFilepath); if (configFileAddedOrRemoved) { updateReactRouterConfigFile(); } let moduleGraphChanged = configFileAddedOrRemoved || Boolean( viteNodeContext.devServer?.moduleGraph.getModuleById(filepath) ); if (!moduleGraphChanged && !appFileAddedOrRemoved) { return; } viteNodeContext.devServer?.moduleGraph.invalidateAll(); viteNodeContext.runner?.moduleCache.clear(); let result = await getConfig(); let prevAppDirectory = appDirectory; appDirectory = import_pathe3.default.normalize( (result.value ?? currentConfig).appDirectory ); if (appDirectory !== prevAppDirectory) { fsWatcher.unwatch(prevAppDirectory); fsWatcher.add(appDirectory); } let configCodeChanged = configFileAddedOrRemoved || reactRouterConfigFile !== void 0 && isEntryFileDependency( viteNodeContext.devServer.moduleGraph, reactRouterConfigFile, filepath ); let routeConfigFile = !skipRoutes ? findEntry(appDirectory, "routes", { absolute: true }) : void 0; let routeConfigCodeChanged = routeConfigFile !== void 0 && isEntryFileDependency( viteNodeContext.devServer.moduleGraph, routeConfigFile, filepath ); let configChanged = result.ok && !(0, import_isEqual.default)(omitRoutes(currentConfig), omitRoutes(result.value)); let routeConfigChanged = result.ok && !(0, import_isEqual.default)(currentConfig?.routes, result.value.routes); for (let handler2 of changeHandlers) { handler2({ result, configCodeChanged, routeConfigCodeChanged, configChanged, routeConfigChanged, path: filepath, event }); } if (result.ok) { currentConfig = result.value; } }); } return () => { changeHandlers = changeHandlers.filter( (changeHandler) => changeHandler !== handler ); }; }, close: async () => { changeHandlers = []; await viteNodeContext.devServer.close(); await fsWatcher?.close(); } }; } async function loadConfig({ rootDirectory, mode, skipRoutes }) { let configLoader = await createConfigLoader({ rootDirectory, mode, skipRoutes, watch: false }); let config = await configLoader.getConfig(); await configLoader.close(); return config; } function omitRoutes(config) { return { ...config, routes: {} }; } function isEntryFile(entryBasename, filename2) { return entryExts.some((ext) => filename2 === `${entryBasename}${ext}`); } function findEntry(dir, basename3, options) { let currentDir = import_pathe3.default.resolve(dir); let { root } = import_pathe3.default.parse(currentDir); while (true) { for (let ext of options?.extensions ?? entryExts) { let file = import_pathe3.default.resolve(currentDir, basename3 + ext); if (import_node_fs.default.existsSync(file)) { return options?.absolute ?? false ? file : import_pathe3.default.relative(dir, file); } } if (!options?.walkParents) { return void 0; } let parentDir = import_pathe3.default.dirname(currentDir); if (currentDir === root || parentDir === currentDir) { return void 0; } currentDir = parentDir; } } function isEntryFileDependency(moduleGraph, entryFilepath, filepath, visited = /* @__PURE__ */ new Set()) { entryFilepath = import_pathe3.default.normalize(entryFilepath); filepath = import_pathe3.default.normalize(filepath); if (visited.has(filepath)) { return false; } visited.add(filepath); if (filepath === entryFilepath) { return true; } let mod = moduleGraph.getModuleById(filepath); if (!mod) { return false; } for (let importer of mod.importers) { if (!importer.id) { continue; } if (importer.id === entryFilepath || isEntryFileDependency(moduleGraph, entryFilepath, importer.id, visited)) { return true; } } return false; } var import_node_fs, import_node_child_process, import_pathe3, import_chokidar, import_picocolors, import_pkg_types, import_pick2, import_omit, import_cloneDeep, import_isEqual, excludedConfigPresetKeys, mergeReactRouterConfig, deepFreeze, entryExts; var init_config = __esm({ "config/config.ts"() { "use strict"; import_node_fs = __toESM(require("fs")); import_node_child_process = require("child_process"); init_vite_node(); import_pathe3 = __toESM(require("pathe")); import_chokidar = __toESM(require("chokidar")); import_picocolors = __toESM(require("picocolors")); import_pkg_types = require("pkg-types"); import_pick2 = __toESM(require("lodash/pick")); import_omit = __toESM(require("lodash/omit")); import_cloneDeep = __toESM(require("lodash/cloneDeep")); import_isEqual = __toESM(require("lodash/isEqual")); init_routes(); init_detectPackageManager(); excludedConfigPresetKeys = ["presets"]; mergeReactRouterConfig = (...configs) => { let reducer = (configA, configB) => { let mergeRequired = (key) => configA[key] !== void 0 && configB[key] !== void 0; return { ...configA, ...configB, ...mergeRequired("buildEnd") ? { buildEnd: async (...args) => { await Promise.all([ configA.buildEnd?.(...args), configB.buildEnd?.(...args) ]); } } : {}, ...mergeRequired("future") ? { future: { ...configA.future, ...configB.future } } : {}, ...mergeRequired("presets") ? { presets: [...configA.presets ?? [], ...configB.presets ?? []] } : {} }; }; return configs.reduce(reducer, {}); }; deepFreeze = (o) => { Object.freeze(o); let oIsFunction = typeof o === "function"; let hasOwnProp = Object.prototype.hasOwnProperty; Object.getOwnPropertyNames(o).forEach(function(prop) { 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]); } }); return o; }; entryExts = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".mts"]; } }); // vite/profiler.ts var import_node_fs2, import_node_path, import_picocolors2, getSession, start, profileCount, stop; var init_profiler = __esm({ "vite/profiler.ts"() { "use strict"; import_node_fs2 = __toESM(require("fs")); import_node_path = __toESM(require("path")); import_picocolors2 = __toESM(require("picocolors")); getSession = () => global.__reactRouter_profile_session; start = async (callback) => { let inspector = await import("inspector").then((r) => r.default); let session = global.__reactRouter_profile_session = new inspector.Session(); session.connect(); session.post("Profiler.enable", () => { session.post("Profiler.start", callback); }); }; profileCount = 0; stop = (log) => { let session = getSession(); if (!session) return; return new Promise((res, rej) => { session.post("Profiler.stop", (err2, { profile }) => { if (err2) return rej(err2); let outPath = import_node_path.default.resolve(`./react-router-${profileCount++}.cpuprofile`); import_node_fs2.default.writeFileSync(outPath, JSON.stringify(profile)); log( import_picocolors2.default.yellow( `CPU profile written to ${import_picocolors2.default.white(import_picocolors2.default.dim(outPath))}` ) ); global.__reactRouter_profile_session = void 0; res(); }); }); }; } }); // typegen/context.ts async function createContext2({ rootDirectory, watch: watch2, mode, rsc }) { const configLoader = await createConfigLoader({ rootDirectory, mode, watch: watch2 }); const configResult = await configLoader.getConfig(); if (!configResult.ok) { throw new Error(configResult.error); } const config = configResult.value; return { configLoader, rootDirectory, config, rsc }; } var init_context = __esm({ "typegen/context.ts"() { "use strict"; init_config(); } }); // vite/babel.ts var babel_exports = {}; __export(babel_exports, { generate: () => generate, parse: () => import_parser.parse, t: () => t, traverse: () => traverse }); var import_parser, t, traverse, generate; var init_babel = __esm({ "vite/babel.ts"() { "use strict"; import_parser = require("@babel/parser"); t = __toESM(require("@babel/types")); traverse = require("@babel/traverse").default; generate = require("@babel/generator").default; } }); // typegen/params.ts function parse2(fullpath2) { const result = {}; let segments = fullpath2.split("/"); segments.forEach((segment) => { const match = segment.match(/^:([\w-]+)(\?)?/); if (!match) return; const param = match[1]; const isRequired = match[2] === void 0; result[param] ||= isRequired; return; }); const hasSplat = segments.at(-1) === "*"; if (hasSplat) result["*"] = true; return result; } var init_params = __esm({ "typegen/params.ts"() { "use strict"; } }); // typegen/route.ts function lineage(routes2, route) { const result = []; while (route) { result.push(route); if (!route.parentId) break; route = routes2[route.parentId]; } result.reverse(); return result; } function fullpath(lineage2) { const route = lineage2.at(-1); if (lineage2.length === 1 && route?.id === "root") return "/"; const isLayout = route && route.index !== true && route.path === void 0; if (isLayout) return void 0; return "/" + lineage2.map((route2) => route2.path?.replace(/^\//, "")?.replace(/\/$/, "")).filter((path9) => path9 !== void 0 && path9 !== "").join("/"); } var init_route = __esm({ "typegen/route.ts"() { "use strict"; } }); // typegen/generate.ts function typesDirectory(ctx) { return Path3.join(ctx.rootDirectory, ".react-router/types"); } function generateFuture(ctx) { const filename2 = Path3.join(typesDirectory(ctx), "+future.ts"); const content = import_dedent.default` // Generated by React Router import "react-router"; declare module "react-router" { interface Future { v8_middleware: ${ctx.config.future.v8_middleware} } } `; return { filename: filename2, content }; } function generateServerBuild(ctx) { const filename2 = Path3.join(typesDirectory(ctx), "+server-build.d.ts"); const content = import_dedent.default` // Generated by React Router declare module "virtual:react-router/server-build" { import { ServerBuild } from "react-router"; export const assets: ServerBuild["assets"]; export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"]; export const basename: ServerBuild["basename"]; export const entry: ServerBuild["entry"]; export const future: ServerBuild["future"]; export const isSpaMode: ServerBuild["isSpaMode"]; export const prerender: ServerBuild["prerender"]; export const publicPath: ServerBuild["publicPath"]; export const routeDiscovery: ServerBuild["routeDiscovery"]; export const routes: ServerBuild["routes"]; export const ssr: ServerBuild["ssr"]; export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"]; } `; return { filename: filename2, content }; } function generateRoutes(ctx) { const fileToRoutes = /* @__PURE__ */ new Map(); const lineages = /* @__PURE__ */ new Map(); const allPages = /* @__PURE__ */ new Set(); const routeToPages = /* @__PURE__ */ new Map(); for (const route of Object.values(ctx.config.routes)) { let routeIds = fileToRoutes.get(route.file); if (!routeIds) { routeIds = /* @__PURE__ */ new Set(); fileToRoutes.set(route.file, routeIds); } routeIds.add(route.id); const lineage2 = lineage(ctx.config.routes, route); lineages.set(route.id, lineage2); const fullpath2 = fullpath(lineage2); if (!fullpath2) continue; const pages = expand(fullpath2); pages.forEach((page) => allPages.add(page)); lineage2.forEach(({ id }) => { let routePages = routeToPages.get(id); if (!routePages) { routePages = /* @__PURE__ */ new Set(); routeToPages.set(id, routePages); } pages.forEach((page) => routePages.add(page)); }); } const routesTs = { filename: Path3.join(typesDirectory(ctx), "+routes.ts"), content: import_dedent.default` // Generated by React Router import "react-router" declare module "react-router" { interface Register { pages: Pages routeFiles: RouteFiles routeModules: RouteModules } } ` + "\n\n" + generate(pagesType(allPages)).code + "\n\n" + generate(routeFilesType({ fileToRoutes, routeToPages })).code + "\n\n" + generate(routeModulesType(ctx)).code }; const allAnnotations = Array.from(fileToRoutes.entries()).filter(([file]) => isInAppDirectory(ctx, file)).map( ([file, routeIds]) => getRouteAnnotations({ ctx, file, routeIds, lineages }) ); return [routesTs, ...allAnnotations]; } function pagesType(pages) { return t2.tsTypeAliasDeclaration( t2.identifier("Pages"), null, t2.tsTypeLiteral( Array.from(pages).map((page) => { return t2.tsPropertySignature( t2.stringLiteral(page), t2.tsTypeAnnotation( t2.tsTypeLiteral([ t2.tsPropertySignature( t2.identifier("params"), t2.tsTypeAnnotation(paramsType(page)) ) ]) ) ); }) ) ); } function routeFilesType({ fileToRoutes, routeToPages }) { return t2.tsTypeAliasDeclaration( t2.identifier("RouteFiles"), null, t2.tsTypeLiteral( Array.from(fileToRoutes).map( ([file, routeIds]) => t2.tsPropertySignature( t2.stringLiteral(file), t2.tsTypeAnnotation( t2.tsUnionType( Array.from(routeIds).map((routeId) => { const pages = routeToPages.get(routeId) ?? /* @__PURE__ */ new Set(); return t2.tsTypeLiteral([ t2.tsPropertySignature( t2.identifier("id"), t2.tsTypeAnnotation( t2.tsLiteralType(t2.stringLiteral(routeId)) ) ), t2.tsPropertySignature( t2.identifier("page"), t2.tsTypeAnnotation( pages ? t2.tsUnionType( Array.from(pages).map( (page) => t2.tsLiteralType(t2.stringLiteral(page)) ) ) : t2.tsNeverKeyword() ) ) ]); }) ) ) ) ) ) ); } function routeModulesType(ctx) { return t2.tsTypeAliasDeclaration( t2.identifier("RouteModules"), null, t2.tsTypeLiteral( Object.values(ctx.config.routes).map( (route) => t2.tsPropertySignature( t2.stringLiteral(route.id), t2.tsTypeAnnotation( isInAppDirectory(ctx, route.file) ? t2.tsTypeQuery( t2.tsImportType( t2.stringLiteral( `./${Path3.relative(ctx.rootDirectory, ctx.config.appDirectory)}/${route.file}` ) ) ) : t2.tsUnknownKeyword() ) ) ) ) ); } function isInAppDirectory(ctx, routeFile) { const path9 = Path3.resolve(ctx.config.appDirectory, routeFile); return path9.startsWith(ctx.config.appDirectory); } function getRouteAnnotations({ ctx, file, routeIds, lineages }) { const filename2 = Path3.join( typesDirectory(ctx), Path3.relative(ctx.rootDirectory, ctx.config.appDirectory), Path3.dirname(file), "+types", Pathe.filename(file) + ".ts" ); const matchesType = t2.tsTypeAliasDeclaration( t2.identifier("Matches"), null, t2.tsUnionType( Array.from(routeIds).map((routeId) => { const lineage2 = lineages.get(routeId); return t2.tsTupleType( lineage2.map( (route) => t2.tsTypeLiteral([ t2.tsPropertySignature( t2.identifier("id"), t2.tsTypeAnnotation(t2.tsLiteralType(t2.stringLiteral(route.id))) ), t2.tsPropertySignature( t2.identifier("module"), t2.tsTypeAnnotation( t2.tsTypeQuery( t2.tsImportType( t2.stringLiteral( relativeImportSource( rootDirsPath(ctx, filename2), Path3.resolve(ctx.config.appDirectory, route.file) ) ) ) ) ) ) ]) ) ); }) ) ); const routeImportSource = relativeImportSource( rootDirsPath(ctx, filename2), Path3.resolve(ctx.config.appDirectory, file) ); const content = import_dedent.default` // Generated by React Router import type { GetInfo, GetAnnotations } from "react-router/internal"; type Module = typeof import("${routeImportSource}") type Info = GetInfo<{ file: "${file}", module: Module }> ` + "\n\n" + generate(matchesType).code + "\n\n" + import_dedent.default` type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }, ${ctx.rsc}>; export namespace Route { // links export type LinkDescriptors = Annotations["LinkDescriptors"]; export type LinksFunction = Annotations["LinksFunction"]; // meta export type MetaArgs = Annotations["MetaArgs"]; export type MetaDescriptors = Annotations["MetaDescriptors"]; export type MetaFunction = Annotations["MetaFunction"]; // headers export type HeadersArgs = Annotations["HeadersArgs"]; export type HeadersFunction = Annotations["HeadersFunction"]; // middleware export type MiddlewareFunction = Annotations["MiddlewareFunction"]; // clientMiddleware export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"]; // loader export type LoaderArgs = Annotations["LoaderArgs"]; // clientLoader export type ClientLoaderArgs = Annotations["ClientLoaderArgs"]; // action export type ActionArgs = Annotations["ActionArgs"]; // clientAction export type ClientActionArgs = Annotations["ClientActionArgs"]; // HydrateFallback export type HydrateFallbackProps = Annotations["HydrateFallbackProps"]; // Component export type ComponentProps = Annotations["ComponentProps"]; // ErrorBoundary export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"]; } `; return { filename: filename2, content }; } function relativeImportSource(from, to) { let path9 = Path3.relative(Path3.dirname(from), to); let extension = Path3.extname(path9); path9 = Path3.join(Path3.dirname(path9), Pathe.filename(path9)); if (!path9.startsWith("../")) path9 = "./" + path9; if (!extension || /\.(js|ts)x?$/.test(extension)) { extension = ".js"; } return path9 + extension; } function rootDirsPath(ctx, typesPath) { const rel = Path3.relative(typesDirectory(ctx), typesPath); return Path3.join(ctx.rootDirectory, rel); } function paramsType(path9) { const params = parse2(path9); return t2.tsTypeLiteral( Object.entries(params).map(([param, isRequired]) => { const property = t2.tsPropertySignature( t2.stringLiteral(param), t2.tsTypeAnnotation(t2.tsStringKeyword()) ); property.optional = !isRequired; return property; }) ); } function expand(fullpath2) { function recurse(segments2, index) { if (index === segments2.length) return [""]; const segment = segments2[index]; const isOptional = segment.endsWith("?"); const isDynamic = segment.startsWith(":"); const required = segment.replace(/\?$/, ""); const keep = !isOptional || isDynamic; const kept = isDynamic ? segment : required; const withoutSegment = recurse(segments2, index + 1); const withSegment = withoutSegment.map((rest) => [kept, rest].join("/")); if (keep) return withSegment; return [...withoutSegment, ...withSegment]; } const segments = fullpath2.split("/"); const expanded = /* @__PURE__ */ new Set(); for (let result of recurse(segments, 0)) { if (result !== "/") result = result.replace(/\/$/, ""); expanded.add(result); } return expanded; } var import_dedent, Path3, Pathe, t2; var init_generate = __esm({ "typegen/generate.ts"() { "use strict"; import_dedent = __toESM(require("dedent")); Path3 = __toESM(require("pathe")); Pathe = __toESM(require("pathe/utils")); init_babel(); init_params(); init_route(); ({ t: t2 } = babel_exports); } }); // typegen/index.ts async function clearRouteModuleAnnotations(ctx) { await import_promises.default.rm( Path4.join(typesDirectory(ctx), Path4.basename(ctx.config.appDirectory)), { recursive: true, force: true } ); } async function write(...files) { return Promise.all( files.map(async ({ filename: filename2, content }) => { await import_promises.default.mkdir(Path4.dirname(filename2), { recursive: true }); await import_promises.default.writeFile(filename2, content); }) ); } async function run(rootDirectory, { mode, rsc }) { const ctx = await createContext2({ rootDirectory, mode, rsc, watch: false }); await import_promises.default.rm(typesDirectory(ctx), { recursive: true, force: true }); await write( generateFuture(ctx), generateServerBuild(ctx), ...generateRoutes(ctx) ); } async function watch(rootDirectory, { mode, logger, rsc }) { const ctx = await createContext2({ rootDirectory, mode, rsc, watch: true }); await import_promises.default.rm(typesDirectory(ctx), { recursive: true, force: true }); await write( generateFuture(ctx), generateServerBuild(ctx), ...generateRoutes(ctx) ); logger?.info((0, import_picocolors3.green)("generated types"), { timestamp: true, clear: true }); ctx.configLoader.onChange( async ({ result, configChanged, routeConfigChanged }) => { if (!result.ok) { logger?.error((0, import_picocolors3.red)(result.error), { timestamp: true, clear: true }); return; } ctx.config = result.value; if (configChanged) { await write(generateFuture(ctx)); logger?.info((0, import_picocolors3.green)("regenerated types"), { timestamp: true, clear: true }); } if (routeConfigChanged) { await clearRouteModuleAnnotations(ctx); await write(...generateRoutes(ctx)); logger?.info((0, import_picocolors3.green)("regenerated types"), { timestamp: true, clear: true }); } } ); return { close: async () => await ctx.configLoader.close() }; } var import_promises, Path4, import_picocolors3; var init_typegen = __esm({ "typegen/index.ts"() { "use strict"; import_promises = __toESM(require("fs/promises")); Path4 = __toESM(require("pathe")); import_picocolors3 = require("picocolors"); init_context(); init_generate(); } }); // vite/has-rsc-plugin.ts async function hasReactRouterRscPlugin({ root, viteBuildOptions: { config, logLevel, mode } }) { const vite2 = await import("vite"); const viteConfig = await vite2.resolveConfig( { configFile: config, logLevel, mode: mode ?? "production", root }, "build", // command "production", // default mode "production" // default NODE_ENV ); return viteConfig.plugins.some( (plugin) => plugin?.name === "react-router/rsc" ); } var init_has_rsc_plugin = __esm({ "vite/has-rsc-plugin.ts"() { "use strict"; } }); // vite/node-adapter.ts var import_node_fetch_server; var init_node_adapter = __esm({ "vite/node-adapter.ts"() { "use strict"; import_node_fetch_server = require("@remix-run/node-fetch-server"); init_invariant(); } }); // vite/resolve-file-url.ts var path4; var init_resolve_file_url = __esm({ "vite/resolve-file-url.ts"() { "use strict"; path4 = __toESM(require("path")); init_vite(); } }); // vite/styles.ts var path5, import_react_router, cssFileRegExp, cssModulesRegExp; var init_styles = __esm({ "vite/styles.ts"() { "use strict"; path5 = __toESM(require("path")); import_react_router = require("react-router"); init_resolve_file_url(); init_babel(); cssFileRegExp = /\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/; cssModulesRegExp = new RegExp(`\\.module${cssFileRegExp.source}`); } }); // vite/virtual-module.ts function create(name) { let id = `virtual:react-router/${name}`; return { id, resolvedId: `\0${id}`, url: `/@id/__x00__${id}` }; } var init_virtual_module = __esm({ "vite/virtual-module.ts"() { "use strict"; } }); // vite/resolve-relative-route-file-path.ts var import_pathe4; var init_resolve_relative_route_file_path = __esm({ "vite/resolve-relative-route-file-path.ts"() { "use strict"; import_pathe4 = __toESM(require("pathe")); init_vite(); } }); // vite/combine-urls.ts var init_combine_urls = __esm({ "vite/combine-urls.ts"() { "use strict"; } }); // vite/remove-exports.ts var import_babel_dead_code_elimination; var init_remove_exports = __esm({ "vite/remove-exports.ts"() { "use strict"; import_babel_dead_code_elimination = require("babel-dead-code-elimination"); init_babel(); } }); // vite/has-dependency.ts var init_has_dependency = __esm({ "vite/has-dependency.ts"() { "use strict"; } }); // vite/cache.ts var init_cache = __esm({ "vite/cache.ts"() { "use strict"; } }); // vite/route-chunks.ts function getRouteChunkModuleId(filePath, chunkName) { return `${filePath}${routeChunkQueryStrings[chunkName]}`; } function isRouteChunkModuleId(id) { return Object.values(routeChunkQueryStrings).some( (queryString) => id.endsWith(queryString) ); } function isRouteChunkName(name) { return name === mainChunkName || routeChunkExportNames.includes(name); } function getRouteChunkNameFromModuleId(id) { if (!isRouteChunkModuleId(id)) { return null; } let chunkName = id.split(routeChunkQueryStringPrefix)[1].split("&")[0]; if (!isRouteChunkName(chunkName)) { return null; } return chunkName; } var routeChunkExportNames, mainChunkName, routeChunkNames, routeChunkQueryStringPrefix, routeChunkQueryStrings; var init_route_chunks = __esm({ "vite/route-chunks.ts"() { "use strict"; init_invariant(); init_cache(); init_babel(); routeChunkExportNames = [ "clientAction", "clientLoader", "clientMiddleware", "HydrateFallback" ]; mainChunkName = "main"; routeChunkNames = ["main", ...routeChunkExportNames]; routeChunkQueryStringPrefix = "?route-chunk="; routeChunkQueryStrings = { main: `${routeChunkQueryStringPrefix}main`, clientAction: `${routeChunkQueryStringPrefix}clientAction`, clientLoader: `${routeChunkQueryStringPrefix}clientLoader`, clientMiddleware: `${routeChunkQueryStringPrefix}clientMiddleware`, HydrateFallback: `${routeChunkQueryStringPrefix}HydrateFallback` }; } }); // vite/optimize-deps-entries.ts var import_tinyglobby; var init_optimize_deps_entries = __esm({ "vite/optimize-deps-entries.ts"() { "use strict"; import_tinyglobby = require("tinyglobby"); init_resolve_relative_route_file_path(); init_vite(); } }); // vite/with-props.ts var init_with_props = __esm({ "vite/with-props.ts"() { "use strict"; init_babel(); } }); // vite/load-dotenv.ts var init_load_dotenv = __esm({ "vite/load-dotenv.ts"() { "use strict"; } }); // vite/plugins/validate-plugin-order.ts var init_validate_plugin_order = __esm({ "vite/plugins/validate-plugin-order.ts"() { "use strict"; } }); // vite/plugins/warn-on-client-source-maps.ts var import_picocolors4; var init_warn_on_client_source_maps = __esm({ "vite/plugins/warn-on-client-source-maps.ts"() { "use strict"; import_picocolors4 = __toESM(require("picocolors")); init_invariant(); } }); // vite/plugin.ts async function resolveViteConfig({ configFile, mode, root, plugins }) { let vite2 = getVite(); let viteConfig = await vite2.resolveConfig( { mode, configFile, root, plugins }, "build", // command "production", // default mode "production" // default NODE_ENV ); if (typeof viteConfig.build.manifest === "string") { throw new Error("Custom Vite manifest paths are not supported"); } return viteConfig; } function extractPluginContext(viteConfig) { return viteConfig["__reactRouterPluginContext"]; } function isSsrBundleEnvironmentName(name) { return name.startsWith(SSR_BUNDLE_PREFIX); } function getServerEnvironmentEntries(ctx, record) { return Object.entries(record).filter( ([name]) => ctx.buildManifest?.serverBundles ? isSsrBundleEnvironmentName(name) : name === "ssr" ); } function getServerEnvironmentKeys(ctx, record) { return getServerEnvironmentEntries(ctx, record).map(([key]) => key); } function getServerBundleIds(ctx) { return ctx.buildManifest?.serverBundles ? Object.keys(ctx.buildManifest.serverBundles) : void 0; } async function cleanBuildDirectory(viteConfig, ctx) { let buildDirectory = ctx.reactRouterConfig.buildDirectory; let isWithinRoot = () => { let relativePath = path7.relative(ctx.root