diff --git a/docs/app/components/ui/Sparkles.tsx b/docs/app/components/ui/Sparkles.tsx
index faf6ccc6..73060dac 100644
--- a/docs/app/components/ui/Sparkles.tsx
+++ b/docs/app/components/ui/Sparkles.tsx
@@ -39,7 +39,6 @@ export const SparklesCore = (props: ParticlesProps) => {
const particlesLoaded = async (container?: Container) => {
if (container) {
- console.log(container)
controls.start({
opacity: 1,
transition: {
diff --git a/package-lock.json b/package-lock.json
index 9663b765..46afb9dd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "react-router-devtools",
- "version": "1.1.8",
+ "version": "5.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "react-router-devtools",
- "version": "1.1.8",
+ "version": "5.0.0",
"license": "MIT",
"workspaces": [
".",
@@ -29,7 +29,8 @@
"react-d3-tree": "^3.6.4",
"react-diff-viewer-continued": "^4.0.5",
"react-hotkeys-hook": "^4.6.1",
- "react-tooltip": "^5.28.0"
+ "react-tooltip": "^5.28.0",
+ "tailwind-merge": "^3.0.1"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
@@ -41,8 +42,6 @@
"@types/babel__core": "^7.20.5",
"@types/beautify": "^0.0.3",
"@types/node": "^22.12.0",
- "@types/react": "^19.0.8",
- "@types/react-dom": "^19.0.3",
"@vitest/coverage-v8": "^3.0.4",
"@vitest/ui": "^3.0.4",
"autoprefixer": "^10.4.20",
@@ -55,13 +54,13 @@
"npm-run-all": "^4.1.5",
"postcss": "^8.5.1",
"prompt": "^1.3.0",
- "tailwind-merge": "^3.0.1",
"tailwindcss": "^3.4.0",
"tailwindcss-animate": "^1.0.7",
"tsup": "^8.3.6",
"tsx": "^4.19.2",
"typescript": "^5.7.3",
"vite": "^6.0.11",
+ "vite-node": "^3.1.2",
"vitest": "^3.0.4"
},
"optionalDependencies": {
@@ -70,6 +69,8 @@
"@rollup/rollup-linux-x64-gnu": "^4.32.1"
},
"peerDependencies": {
+ "@types/react": ">=17",
+ "@types/react-dom": ">=17",
"react": ">=17",
"react-dom": ">=17",
"react-router": ">=7.0.0",
@@ -2354,6 +2355,28 @@
"node": ">=10"
}
},
+ "node_modules/@react-router/dev/node_modules/vite-node": {
+ "version": "3.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.0-beta.2.tgz",
+ "integrity": "sha512-ofTf6cfRdL30Wbl9n/BX81EyIR5s4PReLmSurrxQ+koLaWUNOEo8E0lCM53OJkb8vpa2URM2nSrxZsIFyvY1rg==",
+ "license": "MIT",
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.4.0",
+ "es-module-lexer": "^1.5.4",
+ "pathe": "^1.1.2",
+ "vite": "^5.0.0 || ^6.0.0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
"node_modules/@react-router/express": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/@react-router/express/-/express-7.1.4.tgz",
@@ -3135,7 +3158,6 @@
"version": "19.0.3",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.3.tgz",
"integrity": "sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==",
- "devOptional": true,
"peerDependencies": {
"@types/react": "^19.0.0"
}
@@ -10966,7 +10988,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.0.1.tgz",
"integrity": "sha512-AvzE8FmSoXC7nC+oU5GlQJbip2UO7tmOhOfQyOmPhrStOGXHU08j8mZEHZ4BmCqY5dWTCo4ClWkNyRNx1wpT0g==",
- "dev": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
@@ -12438,14 +12459,16 @@
}
},
"node_modules/vite-node": {
- "version": "3.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.0-beta.2.tgz",
- "integrity": "sha512-ofTf6cfRdL30Wbl9n/BX81EyIR5s4PReLmSurrxQ+koLaWUNOEo8E0lCM53OJkb8vpa2URM2nSrxZsIFyvY1rg==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.1.2.tgz",
+ "integrity": "sha512-/8iMryv46J3aK13iUXsei5G/A3CUlW4665THCPS+K8xAaqrVWiGB4RfXMQXCLjpK9P2eK//BczrVkn5JLAk6DA==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.4.0",
- "es-module-lexer": "^1.5.4",
- "pathe": "^1.1.2",
+ "es-module-lexer": "^1.6.0",
+ "pathe": "^2.0.3",
"vite": "^5.0.0 || ^6.0.0"
},
"bin": {
@@ -12458,6 +12481,13 @@
"url": "https://opencollective.com/vitest"
}
},
+ "node_modules/vite-node/node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/vite-plugin-inspect": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-10.1.0.tgz",
diff --git a/package.json b/package.json
index 9a9ea8c5..a7cd46de 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "react-router-devtools",
"description": "Devtools for React Router - debug, trace, find hydration errors, catch bugs and inspect server/client data with react-router-devtools",
"author": "Alem Tuzlak",
- "version": "1.1.10",
+ "version": "5.0.0",
"license": "MIT",
"keywords": [
"react-router",
@@ -19,7 +19,6 @@
],
"private": false,
"type": "module",
- "main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
@@ -105,6 +104,8 @@
"peerDependencies": {
"react": ">=17",
"react-dom": ">=17",
+ "@types/react": ">=17",
+ "@types/react-dom": ">=17",
"react-router": ">=7.0.0",
"vite": ">=5.0.0 || >=6.0.0"
},
@@ -118,8 +119,6 @@
"@types/babel__core": "^7.20.5",
"@types/beautify": "^0.0.3",
"@types/node": "^22.12.0",
- "@types/react": "^19.0.8",
- "@types/react-dom": "^19.0.3",
"@vitest/coverage-v8": "^3.0.4",
"@vitest/ui": "^3.0.4",
"autoprefixer": "^10.4.20",
@@ -132,13 +131,13 @@
"npm-run-all": "^4.1.5",
"postcss": "^8.5.1",
"prompt": "^1.3.0",
- "tailwind-merge": "^3.0.1",
"tailwindcss": "^3.4.0",
"tailwindcss-animate": "^1.0.7",
"tsup": "^8.3.6",
"tsx": "^4.19.2",
"typescript": "^5.7.3",
"vite": "^6.0.11",
+ "vite-node": "^3.1.2",
"vitest": "^3.0.4"
},
"dependencies": {
@@ -158,7 +157,8 @@
"react-d3-tree": "^3.6.4",
"react-diff-viewer-continued": "^4.0.5",
"react-hotkeys-hook": "^4.6.1",
- "react-tooltip": "^5.28.0"
+ "react-tooltip": "^5.28.0",
+ "tailwind-merge": "^3.0.1"
},
"optionalDependencies": {
"@biomejs/cli-darwin-arm64": "^1.9.4",
diff --git a/src/client/components/RouteInfo.tsx b/src/client/components/RouteInfo.tsx
index cb42eb6d..d5847d93 100644
--- a/src/client/components/RouteInfo.tsx
+++ b/src/client/components/RouteInfo.tsx
@@ -3,6 +3,7 @@ import type { MouseEvent } from "react"
import { Link } from "react-router"
import { useSettingsContext } from "../context/useRDTContext.js"
import { type ExtendedRoute, constructRoutePath } from "../utils/routing.js"
+import { findParentErrorBoundary } from "../utils/sanitize.js"
import { Input } from "./Input.js"
import { Tag } from "./Tag.js"
import { Icon } from "./icon/Icon.js"
@@ -14,39 +15,49 @@ interface RouteInfoProps {
onClose?: () => void
}
-export const RouteInfo = ({ route, className, openNewRoute, onClose }: RouteInfoProps) => {
+export const RouteInfo = ({ route: routeToUse, className, openNewRoute, onClose }: RouteInfoProps) => {
+ const route = window.__reactRouterManifest?.routes[routeToUse.id] || routeToUse
const { settings, setSettings } = useSettingsContext()
const { routeWildcards, routeViewMode } = settings
- const { hasWildcard, path, pathToOpen } = constructRoutePath(route, routeWildcards)
+ const { hasWildcard, path, pathToOpen } = constructRoutePath(routeToUse, routeWildcards)
const isTreeView = routeViewMode === "tree"
- const hasParentErrorBoundary = route.errorBoundary.errorBoundaryId && route.errorBoundary.errorBoundaryId !== route.id
- const hasErrorBoundary = route.errorBoundary.hasErrorBoundary
+ const { hasErrorBoundary, errorBoundaryId } = findParentErrorBoundary(route)
+ const hasParentErrorBoundary = errorBoundaryId && errorBoundaryId !== route.id
+
return (
{isTreeView && (
<>
-
{route.url}
+
{routeToUse.url}
- Path: {path}
+ Path:
+ {path}
- Url: {pathToOpen}
+ Url: {pathToOpen}
>
)}
Route file:
- {route.id}
+ {route.module ?? routeToUse.file}
+
Components contained in the route:
-
+
Loader
+
+ Client Loader
+
+
+ Client Action
+
Action
@@ -60,9 +71,7 @@ export const RouteInfo = ({ route, className, openNewRoute, onClose }: RouteInfo
{hasErrorBoundary ? (
- {hasParentErrorBoundary
- ? `Covered by parent ErrorBoundary located in: ${route.errorBoundary.errorBoundaryId}`
- : ""}
+ {hasParentErrorBoundary ? `Covered by parent ErrorBoundary located in: ${errorBoundaryId}` : ""}
) : null}
@@ -70,7 +79,7 @@ export const RouteInfo = ({ route, className, openNewRoute, onClose }: RouteInfo
<>
Wildcard parameters:
- {route.url
+ {routeToUse.url
.split("/")
.filter((p) => p.startsWith(":"))
.map((param) => (
diff --git a/src/client/tabs/RoutesTab.tsx b/src/client/tabs/RoutesTab.tsx
index 5b96daaf..b5831495 100644
--- a/src/client/tabs/RoutesTab.tsx
+++ b/src/client/tabs/RoutesTab.tsx
@@ -1,4 +1,4 @@
-import { type MouseEvent, useState } from "react"
+import { type MouseEvent, useEffect, useState } from "react"
import { useMatches, useNavigate } from "react-router"
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../components/Accordion.js"
import { NewRouteForm } from "../components/NewRouteForm.js"
@@ -22,7 +22,7 @@ const RoutesTab = () => {
const { detachedWindow } = useDetachedWindowControls()
const [activeRoute, setActiveRoute] = useState
(null)
const [routes] = useState(createExtendedRoutes() as ExtendedRoute[])
- const [treeRoutes] = useState(createRouteTree(window.__reactRouterManifest?.routes))
+ const [treeRoutes, setTreeRoutes] = useState(createRouteTree(window.__reactRouterManifest?.routes))
const isTreeView = routeViewMode === "tree"
const openNewRoute = (path: string) => (e?: MouseEvent) => {
e?.preventDefault()
@@ -32,6 +32,26 @@ const RoutesTab = () => {
}
}
+ useEffect(function fetchAllRoutesOnMount() {
+ import.meta.hot?.send("routes-info")
+ const cb = (event: any) => {
+ const parsed = JSON.parse(event)
+ const data = parsed.data as Record[]
+
+ const routeObject: Record = {}
+ for (const route of data) {
+ routeObject[route.id] = route
+ }
+
+ routeObject.root = window.__reactRouterManifest?.routes?.root
+
+ setTreeRoutes(createRouteTree(routeObject))
+ }
+ import.meta.hot?.on("routes-info", cb)
+ return () => {
+ import.meta.hot?.off("routes-info", cb)
+ }
+ }, [])
return (
@@ -40,7 +60,11 @@ const RoutesTab = () => {
- activeRoutes.includes((link.target.data.attributes as any).id) ? "stroke-yellow-500" : "stroke-gray-400"
+ activeRoutes.includes((link.target.data.attributes as any).id)
+ ? "stroke-yellow-500"
+ : window.__reactRouterManifest?.routes?.[link.target.data.attributes.id]
+ ? "stroke-gray-400"
+ : "stroke-gray-400/20"
}
renderCustomNodeElement={(props) =>
RouteNode({
diff --git a/src/client/utils/routing.ts b/src/client/utils/routing.ts
index 573d149d..5792280f 100644
--- a/src/client/utils/routing.ts
+++ b/src/client/utils/routing.ts
@@ -48,18 +48,29 @@ const ROUTE_FILLS = {
PURPLE: "fill-purple-500 text-white",
} as const
+const UNDISCOVERED_ROUTE_FILLS = {
+ GREEN: "fill-green-500/20 text-white",
+ BLUE: "fill-blue-500/20 text-white",
+ PURPLE: "fill-purple-500/20 text-white",
+}
+
export function getRouteColor(route: Route) {
+ const isDiscovered = !!window.__reactRouterManifest?.routes[route.id]
+ const FILL = isDiscovered ? ROUTE_FILLS : UNDISCOVERED_ROUTE_FILLS
switch (getRouteType(route)) {
case "ROOT":
- return ROUTE_FILLS.PURPLE
- case "LAYOUT":
- return ROUTE_FILLS.BLUE
+ return FILL.PURPLE
+
case "ROUTE":
- return ROUTE_FILLS.GREEN
+ return FILL.GREEN
+
+ case "LAYOUT":
+ return FILL.BLUE
}
}
export type ExtendedRoute = EntryRoute & {
url: string
+ file?: string
errorBoundary: { hasErrorBoundary: boolean; errorBoundaryId: string | null }
}
@@ -89,8 +100,7 @@ export const createExtendedRoutes = () => {
...route,
// biome-ignore lint/style/noNonNullAssertion:
url: convertReactRouterPathToUrl(window.__reactRouterManifest!.routes, route),
- // biome-ignore lint/style/noNonNullAssertion:
- errorBoundary: findParentErrorBoundary(window.__reactRouterManifest!.routes, route),
+ errorBoundary: findParentErrorBoundary(route),
}
})
.filter((route) => isLeafRoute(route as any))
diff --git a/src/client/utils/sanitize.ts b/src/client/utils/sanitize.ts
index 6a9309b1..3b67eab7 100644
--- a/src/client/utils/sanitize.ts
+++ b/src/client/utils/sanitize.ts
@@ -21,7 +21,9 @@ export const convertReactRouterPathToUrl = (routes: any, route: Route) => {
return output === "" ? "/" : output
}
-export const findParentErrorBoundary = (routes: RouteManifest, route: Route) => {
+export const findParentErrorBoundary = (route: Route) => {
+ // biome-ignore lint/style/noNonNullAssertion:
+ const routes = window.__reactRouterManifest?.routes!
let currentRoute: Route | null = route
while (currentRoute) {
@@ -56,6 +58,7 @@ const constructTree = (routes: any, parentId?: string): RawNodeDatum[] => {
const routeKeys = Object.keys(routes)
for (const key of routeKeys) {
const route = routes[key]
+
if (route.parentId === parentId) {
const url = convertReactRouterPathToUrl(routes, route)
const node: RawNodeDatum = {
@@ -64,9 +67,10 @@ const constructTree = (routes: any, parentId?: string): RawNodeDatum[] => {
...route,
url,
},
- errorBoundary: findParentErrorBoundary(routes, route),
+ errorBoundary: findParentErrorBoundary(route),
children: constructTree(routes, route.id),
}
+
nodes.push(node)
}
}
diff --git a/src/vite/node-server.ts b/src/vite/node-server.ts
new file mode 100644
index 00000000..7d995574
--- /dev/null
+++ b/src/vite/node-server.ts
@@ -0,0 +1,51 @@
+import { createServer, version as viteVersion } from "vite"
+import { ViteNodeRunner } from "vite-node/client"
+import { ViteNodeServer } from "vite-node/server"
+import { installSourcemapsSupport } from "vite-node/source-map"
+
+// create vite server
+const server = await createServer({
+ mode: "development",
+ root: process.cwd(),
+ server: {
+ preTransformRequests: false,
+ hmr: false,
+ watch: null,
+ },
+
+ optimizeDeps: {
+ noDiscovery: true,
+ },
+ configFile: false,
+ envFile: false,
+ plugins: [],
+})
+// For old Vite, this is need to initialize the plugins.
+if (Number(viteVersion.split(".")[0]) < 6) {
+ await server.pluginContainer.buildStart({})
+}
+
+// create vite-node server
+const node = new ViteNodeServer(server)
+
+// fixes stacktraces in Errors
+installSourcemapsSupport({
+ getSourceMap: (source) => node.getSourceMap(source),
+})
+
+// create vite-node runner
+const runner = new ViteNodeRunner({
+ root: server.config.root,
+ base: server.config.base,
+ // when having the server and runner in a different context,
+ // you will need to handle the communication between them
+ // and pass to this function
+ fetchModule(id) {
+ return node.fetchModule(id)
+ },
+ resolveId(id, importer) {
+ return node.resolveId(id, importer)
+ },
+})
+
+export { runner }
diff --git a/src/vite/plugin.tsx b/src/vite/plugin.tsx
index 666e0e67..f5509189 100644
--- a/src/vite/plugin.tsx
+++ b/src/vite/plugin.tsx
@@ -7,6 +7,7 @@ import type { ActionEvent, LoaderEvent } from "../server/event-queue.js"
import type { RequestEvent } from "../shared/request-event.js"
import { DEFAULT_EDITOR_CONFIG, type EditorConfig, type OpenSourceData, handleOpenSource } from "./editor.js"
import { type WriteFileData, handleWriteFile } from "./file.js"
+import { runner } from "./node-server.js"
import { handleDevToolsViteRequest, processPlugins } from "./utils.js"
import { augmentDataFetchingFunctions } from "./utils/data-functions-augment.js"
import { injectRdtClient } from "./utils/inject-client.js"
@@ -41,6 +42,15 @@ type ReactRouterViteConfig = {
editor?: EditorConfig
}
+type Route = {
+ id: string
+ file: string
+ path?: string
+ index?: boolean
+ caseSensitive?: boolean
+ children?: Route[]
+}
+
export const defineRdtConfig = (config: ReactRouterViteConfig) => config
export const reactRouterDevTools: (args?: ReactRouterViteConfig) => Plugin[] = (args) => {
@@ -53,6 +63,8 @@ export const reactRouterDevTools: (args?: ReactRouterViteConfig) => Plugin[] = (
const includeServer = args?.includeInProd?.server ?? false
const includeDevtools = args?.includeInProd?.devTools ?? false
+ let routes: Route[] = []
+ let flatRoutes: Route[] = []
const appDir = args?.appDir || "./app"
const appDirName = appDir.replace("./", "")
const shouldInject = (mode: string | undefined, include: boolean) => mode === "development" || include
@@ -61,12 +73,23 @@ export const reactRouterDevTools: (args?: ReactRouterViteConfig) => Plugin[] = (
if (!extensions.some((ext) => id.endsWith(ext))) {
return
}
- const isRoute = id.includes(`${appDirName}/root`) || id.includes(`${appDirName}/routes`)
- if (id.includes("node_modules") || id.includes("dist") || id.includes("build") || id.includes("?") || !isRoute) {
+ if (id.includes("node_modules") || id.includes("dist") || id.includes("build") || id.includes("?")) {
return
}
- const routeId = id.replace(normalizePath(process.cwd()), "").replace(`/${appDirName}/`, "").replace(".tsx", "")
+ const isRoute =
+ id.includes(`${appDirName}/root`) ||
+ flatRoutes.some((route) => id.endsWith(route.file.replace(/^\.\//, "").replace(/^\.\.\//, "")))
+
+ if (!isRoute) {
+ return
+ }
+
+ const routeId = id
+ .replace(normalizePath(process.cwd()), "")
+ .replace(`/${appDirName}/`, "")
+ .replace(".tsx", "")
+ .replace(".ts", "")
return routeId
}
// Set the server config on the process object so that it can be accessed by the plugin
@@ -80,6 +103,64 @@ export const reactRouterDevTools: (args?: ReactRouterViteConfig) => Plugin[] = (
return shouldInject(config.mode, includeClient)
},
async configResolved(resolvedViteConfig) {
+ try {
+ const path = await import("node:path")
+ // Set the route config
+ const routeConfigExport = (await runner.executeFile(path.join(process.cwd(), "./app/routes.ts"))).default
+ const routeConfig = await routeConfigExport
+ routes = routeConfig
+
+ const recursiveFlatten = (routeOrRoutes: Route | Route[]): Route[] => {
+ if (Array.isArray(routeOrRoutes)) {
+ return routeOrRoutes.flatMap((route) => recursiveFlatten(route))
+ }
+ if (routeOrRoutes.children) {
+ return [
+ routeOrRoutes,
+ ...recursiveFlatten(
+ routeOrRoutes.children.map((child) => {
+ // ./path.tsx => path
+ // ../path.tsx => path
+ const withoutExtension = child.file
+ .split(".")
+ .slice(0, -1)
+ .join(".")
+ .replace(/^\.\//, "")
+ .replace(/^\.\.\//, "")
+ // ./path.tsx => path
+ // ../path.tsx => path
+ const withoutExtensionParent = routeOrRoutes.file
+ .split(".")
+ .slice(0, -1)
+ .join(".")
+ .replace(/^\.\//, "")
+ .replace(/^\.\.\//, "")
+
+ return {
+ ...child,
+ id: child.id ?? withoutExtension,
+ parentId: withoutExtensionParent,
+ }
+ })
+ ),
+ ]
+ }
+ return [routeOrRoutes]
+ }
+ flatRoutes = routes
+ .map((route) => {
+ // ./path.tsx => path
+ // ../path.tsx => path
+ const withoutExtension = route.file
+ .split(".")
+ .slice(0, -1)
+ .join(".")
+ .replace(/^\.\//, "")
+ .replace(/^\.\.\//, "")
+ return { ...route, parentId: "root", id: route.id ?? withoutExtension }
+ })
+ .flatMap(recursiveFlatten)
+ } catch (e) {}
const reactRouterIndex = resolvedViteConfig.plugins.findIndex((p) => p.name === "react-router")
const devToolsIndex = resolvedViteConfig.plugins.findIndex((p) => p.name === "react-router-devtools")
if (reactRouterIndex >= 0 && devToolsIndex > reactRouterIndex) {
@@ -203,6 +284,15 @@ export const reactRouterDevTools: (args?: ReactRouterViteConfig) => Plugin[] = (
})
)
})
+ server.hot.on("routes-info", (data, client) => {
+ client.send(
+ "routes-info",
+ JSON.stringify({
+ type: "routes-info",
+ data: flatRoutes,
+ })
+ )
+ })
if (!server.config.isProduction) {
channel?.on("remove-event", (data, client) => {
diff --git a/test-apps/react-router-vite/app/root.tsx b/test-apps/react-router-vite/app/root.tsx
index 956163c4..2f650825 100644
--- a/test-apps/react-router-vite/app/root.tsx
+++ b/test-apps/react-router-vite/app/root.tsx
@@ -28,7 +28,7 @@ export const loader = ({context, devTools }: LoaderFunctionArgs) => {
});
const start =devTools?.tracing.start("test")!;
devTools?.tracing.end("test", start);
- return data({ message: "Hello World", mainPromise, bigInt: BigInt(10) }, { headers: { "Cache-Control": "max-age=3600, private" } });
+ return data({ message: "Hello World", mainPromise, bigInt: BigInt(10) }, );
}
export const action =async ({devTools}: ActionFunctionArgs) => {
diff --git a/test-apps/react-router-vite/app/routes.ts b/test-apps/react-router-vite/app/routes.ts
index b8a61f25..7efea74a 100644
--- a/test-apps/react-router-vite/app/routes.ts
+++ b/test-apps/react-router-vite/app/routes.ts
@@ -1,3 +1,8 @@
import { flatRoutes } from "@react-router/fs-routes";
-export default flatRoutes()
\ No newline at end of file
+import { type RouteConfig, index, layout, prefix, route } from "@react-router/dev/routes"
+import subroutes from "./subroutes.js"
+
+
+
+export default [...await flatRoutes(), ...subroutes ]
\ No newline at end of file
diff --git a/test-apps/react-router-vite/app/subroutes.ts b/test-apps/react-router-vite/app/subroutes.ts
new file mode 100644
index 00000000..8f2b3be7
--- /dev/null
+++ b/test-apps/react-router-vite/app/subroutes.ts
@@ -0,0 +1,7 @@
+import { type RouteConfig, index, layout, prefix, route } from "@react-router/dev/routes"
+
+
+export default [
+ route("outside", "./routes/_index.tsx", { id: "something" }),
+
+] satisfies RouteConfig
diff --git a/test-apps/react-router-vite/vite.config.ts b/test-apps/react-router-vite/vite.config.ts
index e0905b6c..03409038 100644
--- a/test-apps/react-router-vite/vite.config.ts
+++ b/test-apps/react-router-vite/vite.config.ts
@@ -37,10 +37,10 @@ export default defineConfig({
tsconfigPaths()
],
optimizeDeps: {
- exclude: ["react-router-devtools"]
+ noDiscovery: true
},
server: {
open: true,
- port: 3005,
+ port: 3000,
},
});
diff --git a/tsup.config.ts b/tsup.config.ts
index 93f53d0f..87abce49 100644
--- a/tsup.config.ts
+++ b/tsup.config.ts
@@ -7,4 +7,5 @@ export default defineConfig({
clean: false,
dts: true,
format: ["esm"],
+ external: ["vite-node"],
})