@react-router/dev
Version:
Dev tools and CLI for React Router
855 lines (839 loc) • 28.3 kB
JavaScript
/**
* @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
*/
;
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 __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
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// vite/cloudflare.ts
var cloudflare_exports = {};
__export(cloudflare_exports, {
cloudflareDevProxy: () => cloudflareDevProxyVitePlugin
});
module.exports = __toCommonJS(cloudflare_exports);
// vite/cloudflare-dev-proxy.ts
var import_node_fetch_server2 = require("@remix-run/node-fetch-server");
var import_react_router = require("react-router");
// vite/node-adapter.ts
var import_node_fetch_server = require("@remix-run/node-fetch-server");
// 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);
}
}
// vite/node-adapter.ts
function fromNodeRequest(nodeReq, nodeRes) {
invariant(
nodeReq.originalUrl,
"Expected `nodeReq.originalUrl` to be defined"
);
nodeReq.url = nodeReq.originalUrl;
return (0, import_node_fetch_server.createRequest)(nodeReq, nodeRes);
}
// vite/vite.ts
var import_pathe2 = __toESM(require("pathe"));
// config/is-react-router-repo.ts
var import_pathe = __toESM(require("pathe"));
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";
}
// vite/vite.ts
var vite;
var 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";
async function preloadVite() {
vite = await import(viteImportSpecifier);
}
function getVite() {
invariant(vite, "getVite() called before preloadVite()");
return vite;
}
// config/config.ts
var import_node_fs = __toESM(require("fs"));
var import_node_child_process = require("child_process");
// vite/ssr-externals.ts
var 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 };
}
// config/config.ts
var import_pathe3 = __toESM(require("pathe"));
var import_chokidar = __toESM(require("chokidar"));
var import_picocolors = __toESM(require("picocolors"));
var import_pkg_types = require("pkg-types");
var import_pick2 = __toESM(require("lodash/pick"));
var import_omit = __toESM(require("lodash/omit"));
var import_cloneDeep = __toESM(require("lodash/cloneDeep"));
var import_isEqual = __toESM(require("lodash/isEqual"));
// config/routes.ts
var Path = __toESM(require("pathe"));
var v = __toESM(require("valibot"));
var import_pick = __toESM(require("lodash/pick"));
function setAppDirectory(directory) {
globalThis.__reactRouterAppDirectory = directory;
}
var 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)))
})
);
var resolvedRouteConfigSchema = v.array(routeConfigEntrySchema);
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(
([path3, message]) => `Path: routes.${path3}
${message}`
) : []
].flat().join("\n\n")
};
}
return {
valid: true,
routeConfig
};
}
function configRoutesToRouteManifest(appDirectory, routes) {
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 routes) {
walk(route);
}
return routeManifest;
}
function createRouteId(file) {
return Path.normalize(stripFileExtension(file));
}
function stripFileExtension(file) {
return file.replace(/\.[a-z0-9]+$/i, "");
}
// config/config.ts
var excludedConfigPresetKeys = ["presets"];
var 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, {});
};
var 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;
};
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,
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 routes;
let routeConfig = [];
if (skipRoutes) {
routes = {};
} 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
}
];
routes = 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,
buildDirectory,
buildEnd,
future,
prerender,
routes,
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,
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 (!watch) {
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: (path3) => {
let dirname = import_pathe3.default.dirname(path3);
return !dirname.startsWith(appDirectory) && // Ensure we're only watching files outside of the app directory
// that are at the root level, not nested in subdirectories
path3 !== root && // Watch the root directory itself
dirname !== 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: {}
};
}
var entryExts = [".js", ".jsx", ".ts", ".tsx", ".mjs", ".mts"];
function isEntryFile(entryBasename, filename) {
return entryExts.some((ext) => filename === `${entryBasename}${ext}`);
}
function findEntry(dir, basename, 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, basename + 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;
}
// vite/cloudflare-dev-proxy.ts
var serverBuildId = "virtual:react-router/server-build";
function importWrangler() {
try {
return import("wrangler");
} catch (_) {
throw Error("Could not import `wrangler`. Do you have it installed?");
}
}
var PLUGIN_NAME = "react-router-cloudflare-vite-dev-proxy";
var cloudflareDevProxyVitePlugin = (options = {}) => {
let { getLoadContext, ...restOptions } = options;
const workerdConditions = ["workerd", "worker"];
let future;
return {
name: PLUGIN_NAME,
config: async (config, configEnv) => {
await preloadVite();
const externalConditions = ["node"];
let configResult = await loadConfig({
rootDirectory: config.root ?? process.cwd(),
mode: configEnv.mode
});
if (!configResult.ok) {
throw new Error(configResult.error);
}
future = configResult.value.future;
return {
ssr: {
resolve: {
externalConditions: [...workerdConditions, ...externalConditions]
}
}
};
},
configEnvironment: async (name, options2) => {
if (!future.v8_viteEnvironmentApi) {
return;
}
if (name !== "client") {
options2.resolve = options2.resolve ?? {};
options2.resolve.externalConditions = [
...workerdConditions,
...options2.resolve?.externalConditions ?? []
];
}
},
configResolved: (viteConfig) => {
let pluginIndex = (name) => viteConfig.plugins.findIndex((plugin) => plugin.name === name);
let reactRouterPluginIndex = pluginIndex("react-router");
if (reactRouterPluginIndex >= 0 && reactRouterPluginIndex < pluginIndex(PLUGIN_NAME)) {
throw new Error(
`The "${PLUGIN_NAME}" plugin should be placed before the React Router plugin in your Vite config file`
);
}
},
configureServer: async (viteDevServer) => {
let context;
let getContext = async () => {
let { getPlatformProxy } = await importWrangler();
let { dispose, ...cloudflare } = await getPlatformProxy(
restOptions
);
return { cloudflare };
};
return () => {
if (!viteDevServer.config.server.middlewareMode) {
viteDevServer.middlewares.use(async (nodeReq, nodeRes, next) => {
try {
let build = await viteDevServer.ssrLoadModule(
serverBuildId
);
let handler = (0, import_react_router.createRequestHandler)(build, "development");
let req = fromNodeRequest(nodeReq, nodeRes);
context ??= await getContext();
let loadContext = getLoadContext ? await getLoadContext({ request: req, context }) : context;
let res = await handler(req, loadContext);
await (0, import_node_fetch_server2.sendResponse)(nodeRes, res);
} catch (error) {
next(error);
}
});
}
};
}
};
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
cloudflareDevProxy
});