资讯动态

如何用虚拟文件路由把现有目录结构映射成 TanStack Router 路由树

发布时间:2026/9/15 19:16:22 来源:尧图企业网站定制
如何用虚拟文件路由把现有目录结构映射成 TanStack Router 路由树【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router如果你已经有一套按自己习惯组织的组件目录又不想把它重排成 TanStack Router 的文件式路由约定可以使用虚拟文件路由Virtual File Routes在一份routes.ts配置里用代码把 URL 路径映射到项目里真实存在的文件然后让tanstack/router-plugin照常生成类型安全的路由树。适用前提是你的构建工具是 Vite/Rspack/Webpack 并使用tanstackRouter插件或者使用 TanStack Router CLI。官方示例见 basic-virtual-file-basedReact Vite。准备安装依赖并配置插件先在项目里安装tanstack/router-plugin和tanstack/virtual-file-routes两个包示例项目的 package.json 中对应的依赖为{ dependencies: { tanstack/react-router: ^1.170.35, tanstack/router-plugin: ^1.168.37, tanstack/virtual-file-routes: ^1.162.0 } }然后在vite.config.ts中把virtualRouteConfig指向你的路由配置文件并保证tanstack/router-plugin排在vitejs/plugin-react之前Installation with Vite 明确要求import { defineConfig } from vite import react from vitejs/plugin-react import { tanstackRouter } from tanstack/router-plugin/vite export default defineConfig({ plugins: [ tanstackRouter({ target: react, virtualRouteConfig: ./routes.ts, }), react(), ], })这里./routes.ts是相对于vite.config.ts的路由配置文件路径。也可以不写文件直接在插件配置里传路由对象import { defineConfig } from vite import react from vitejs/plugin-react import { tanstackRouter } from tanstack/router-plugin/vite import { rootRoute } from tanstack/virtual-file-routes const routes rootRoute(root.tsx, [ // ... the rest of your virtual route tree ]) export default defineConfig({ plugins: [ tanstackRouter({ virtualRouteConfig: routes, target: react }), react(), ], })Solid 项目同理把target改为solid、框架插件换成vite-plugin-solid。插件的默认配置中路由目录为./src/routes、生成的路由树文件为./src/routeTree.gen.tswith-vite.mdroutes.ts里引用的文件名都相对于路由目录解析。在 routes.ts 中描述你的目录结构tanstack/virtual-file-routes导出五个函数用来逐层描述路由树见 virtual-file-routes.md函数作用参数rootRoute创建虚拟根路由根文件路径、子路由数组route创建虚拟路由URL 路径、文件路径、子路由数组index创建虚拟 index 路由文件路径layout创建无路径pathless布局路由可选的 pathless ID、文件路径、子路由数组physical挂载一个按标准文件式约定组织的目录URL 路径前缀、目录路径示例项目的 routes.ts 是一个完整的真实映射对应src/routes下的实际文件import { index, layout, physical, rootRoute, route, } from tanstack/virtual-file-routes export const routes rootRoute(root.tsx, [ index(home.tsx), route(/posts, posts/posts.tsx, [ index(posts/posts-home.tsx), route($postId, posts/posts-detail.tsx), ]), layout(first, layout/first-layout.tsx, [ layout(layout/second-layout.tsx, [ route(route-without-file, [ route(/layout-a, a.tsx), route(/layout-b, b.tsx), ]), ]), ]), physical(/classic, file-based-subtree), ])这份配置表达的意思是rootRoute(root.tsx, ...)根路由由src/routes/root.tsx提供index(home.tsx)/由home.tsx渲染route(/posts, posts/posts.tsx, [...])/posts由posts/posts.tsx渲染其下 index 路由和$postId动态路由分别指向posts/posts-home.tsx和posts/posts-detail.tsxlayout(first, ...)无路径布局路由第一个参数first是 pathless ID区别于文件名route(route-without-file, [...])展示了不带文件名的 route 用法——它只为子路由提供公共路径前缀。两个容易踩坑的点来自文档原文route接收的是显式 URL 路径首尾下划线按字面处理不会被当作无路径标记需要无路径布局时用layout。physical的用途是挂载一个标准文件式路由目录到某个 URL 下。当你只想用虚拟路由定制树上层的一小部分、子树继续按文件式约定走时用它最省事。用 physical 挂载整个文件式目录如果你的项目里有一大片目录完全遵循 TanStack Router 的文件式命名约定index.tsx、$param.tsx、_pathless.tsx等不必逐条写route用physical一行挂载即可。以示例项目为例physical(/classic, file-based-subtree)把src/routes/file-based-subtree目录整体挂到/classic下生成的路由如下可从 routeTree.gen.ts 中核对/classic/hello——file-based-subtree/hello/route.tsx/classic/hello(exact) ——file-based-subtree/hello/index.tsx/classic/hello/world、/classic/hello/universe—— 同目录下的world.tsx、universe.tsx另外physical支持空路径前缀或只传一个参数把目录里的路由合并到当前层级而不添加路径前缀适合按目录拆分、但希望路由出现在同一 URL 层级的组织方式import { physical, rootRoute, route } from tanstack/virtual-file-routes export const routes rootRoute(__root.tsx, [ route(/about, about.tsx), // Merge features/ routes at root level (no path prefix) physical(features), // Or equivalently: physical(, features) ])目录结构为__root.tsx、about.tsx、features/index.tsx、features/contact.tsx时会产出/about、/来自features/index.tsx、/contact三条路由。注意文档中的明确警告合并到同一层级时虚拟路由与物理目录路由之间不能出现路径冲突例如两边都定义了/about否则生成器会抛错。反向场景在文件式路由树中局部切换为虚拟配置虚拟文件路由还可以反过来用——主体仍按文件式约定组织只在某些子树切到虚拟配置。做法是在该目录下放一个名为__virtual.ts的特殊文件它指示生成器对这个目录及其子目录改用虚拟文件路由配置// routes/foo/bar/__virtual.ts import { defineVirtualSubtreeConfig, index, route, } from tanstack/virtual-file-routes export default defineVirtualSubtreeConfig([ index(home.tsx), route($id, details.tsx), ])与根级配置的唯一区别是这个子树里不定义rootRoute。defineVirtualSubtreeConfig的默认导出可以是子树配置对象、返回配置对象的函数、或返回配置对象的异步函数。文档还给出了混合嵌套的深度示例从文件式约定切入/posts的虚拟配置、再切回文件式约定、更深层再次切入虚拟配置两种方式可以在路由树的任意层级自由交替。CLI 用户的配置方式如果不用 bundler 插件而是用 TanStack Router CLI虚拟文件路由通过tsr.config.json配置写法与插件对应// tsr.config.json { virtualRouteConfig: ./routes.ts }也可以直接把tanstack/virtual-file-routes各函数生成的 JSON 对象写进virtualRouteConfig其中每个节点带typeroot/route/index/layout、file、path、children等字段例如{ virtualRouteConfig: { type: root, file: root.tsx, children: [ { type: index, file: home.tsx }, { type: route, file: posts/posts.tsx, path: /posts, children: [ { type: index, file: posts/posts-home.tsx }, { type: route, file: posts/posts-detail.tsx, path: $postId } ] } ] } }验证生成的路由树配置完成后路由树会在 bundler 的 dev 和 build 过程中由插件自动重新生成参见 file-based-routing.md产物默认位于src/routeTree.gen.ts。验证方式就是读这个文件确认其中每条路由的id、path与你routes.ts中的映射一一对应。示例项目提交在仓库里的 routeTree.gen.ts 展示了正确的结果长什么样import { Route as rootRouteImport } from ./routes/root import { Route as homeRouteImport } from ./routes/home import { Route as postsPostsRouteImport } from ./routes/posts/posts // ... const postsPostsRoute postsPostsRouteImport.update({ id: /posts, path: /posts, getParentRoute: () rootRouteImport, } as any)可以看到每条导入都指向routes.ts里声明的真实文件id/path与虚拟配置中的路径一致physical挂载出来的/classic/hello等路由也出现在同一文件里。文件头部的注释明确写着该文件由 TanStack Router 自动生成不要手工修改且应从 linter/formatter 中排除with-vite.md 给出了针对 Prettier/ESLint/Biome 的排除建议以及 VSCode 中把**/routeTree.gen.ts标记为 readonly 的设置。日常跑通流程可以用示例项目的脚本package.jsonpnpm install pnpm dev # 启动开发服务器vite --port 3000在浏览器访问各路由验证渲染 pnpm build # vite build tsc --noEmit验证类型安全pnpm build里的tsc --noEmit同时验证了路由树类型链路的完整性——这是虚拟文件路由相对纯手写代码路由保留下来的类型收益。限制与排查同层路径冲突physical以空前缀合并目录时若虚拟路由与物理目录路由定义了相同路径生成器会直接抛错需要调整其中一侧的路径或文件名。下划线路径route(/_foo, ...)中的下划线是字面路径段不会创建 pathless 路由需要无路径布局请使用layout。生成文件被误改routeTree.gen.ts会被覆盖手工编辑没有意义如果 VSCode 在重命名路由后意外打开该文件并报红按 with-vite 文档的设置将其标记为只读并从搜索/文件监听中排除。文档中未提及的行为如与 HMR、代码分割的交互细节以 virtual-file-routes.md 为准本文不做补充推断。当你的目录结构稳定下来、且完全能套进文件式命名约定时可以退回标准的 File-Based Routing两者也可以按上面的反向场景在同一棵路由树里混用。【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价