ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

TanStack Router 文件路由(File-Based Routing)完全指南:从目录约定到生成式路由树

TanStack Router 文件路由(File-Based Routing)完全指南:从目录约定到生成式路由树 TanStack Router 文件路由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本指南基于 TanStack Router 官方路由文档与仓库源码系统讲解文件路由File-Based Routing的核心机制如何用文件系统定义路由层级、/目录与.点号两种嵌套写法、完整的文件命名约定、以及通过 TanStack Router 插件自动生成routeTree.gen.ts的配置与全部可调参数。读完本文你将能独立完成文件路由项目的初始化配置并掌握目录路由、扁平路由、混合路由、无路径布局、动态参数段等在真实项目中的落地写法。什么是文件路由文件路由是一种用文件系统来配置路由的方式。与在代码中手写路由树不同你通过一系列文件与目录来表达应用的 URL 层级结构TanStack Router 会读取这些文件并自动生成对应的路由配置。绝大多数 TanStack Router 官方文档都以文件路由为默认视角撰写它也是官方推荐的首选路由配置方式若你偏好纯代码方式可参考 代码路由。文件路由带来的核心收益包括简单Simplicity路由结构一目了然对新老开发者都极其直观组织性Organization路由的组织方式天然镜像应用的 URL 结构可扩展Scalability应用增长时新增路由、维护既有路由都非常容易代码分割Code-Splitting文件路由让 TanStack Router 能够自动按路由进行代码分割优化首屏性能类型安全Type-Safety文件路由通过自动生成并维护路由的类型联动把类型安全的上限拉到最高——这在代码路由下往往要靠繁琐的手工维护才能实现一致性Consistency文件路由强制统一的路由结构便于维护、更新以及在不同项目间迁移。路由树Route Tree是这一切的基石TanStack Router 用一棵嵌套的路由树把 URL 与正确的组件树匹配起来。以 URL/blog/posts/123为例你可以建立blog → posts → $postId的层级并渲染出BlogPostsPost postId123 //Posts/Blog的组件树。完整的嵌套概念见 Route Trees。用/目录还是.点号长期以来目录一直被用来表达路由层级文件路由在此基础上引入了一个新概念使用文件名中的.字符来表示路由嵌套。这样少量深度嵌套的路由不必为此创建目录而宽而浅的路由层级依然可以使用目录来组织。下面分别介绍这两种形态。目录路由Directory Routes目录用于表达路由层级适合把多个路由组织为逻辑分组也能大幅缩短深层嵌套路由的文件名长度。假设routes目录下的结构如下文件名路由路径组件输出ʦ__root.tsxRootʦindex.tsx/精确匹配RootRootIndexʦabout.tsx/aboutRootAboutʦposts.tsx/postsRootPostsposts┄ ʦindex.tsx/posts精确匹配RootPostsPostsIndex┄ ʦ$postId.tsx/posts/$postIdRootPostsPostposts_┄ $postId┄ ┄ ʦedit.tsx/posts/$postId/editRootEditPostʦsettings.tsx/settingsRootSettingssettingsRootSettings┄ ʦprofile.tsx/settings/profileRootSettingsProfile┄ ʦnotifications.tsx/settings/notificationsRootSettingsNotificationsʦ_pathlessLayout.tsxRootPathlessLayout_pathlessLayout┄ ʦroute-a.tsx/route-aRootPathlessLayoutRouteA┄ ʦroute-b.tsx/route-bRootPathlessLayoutRouteBfiles┄ ʦ$.tsx/files/$RootFilesaccount┄ ʦroute.tsx/accountRootAccount┄ ʦoverview.tsx/account/overviewRootAccountOverview值得注意的几个细节posts_目录名以_结尾表示posts_下的$postId子路由不再嵌套进posts路由而是作为顶层路由渲染RootEditPost这正是“非嵌套路由Non-Nested Routes”的目录写法_pathlessLayout以_开头是无路径布局路由Pathless Layout不参与 URL 匹配只为子路由提供包裹组件files/$.tsx中的$是 Splat / Catch-All 路由捕获$之后 URL 的全部剩余片段account/route.tsx利用route令牌在目录的路径上创建一个路由文件等价于account.tsx。扁平路由Flat Routes扁平路由允许你用.来表示路由嵌套层级。当你有大量深度各不相同的路由、又不想为每一条都建目录时扁平路由是最佳选择文件名路由路径组件输出ʦ__root.tsxRootʦindex.tsx/精确匹配RootRootIndexʦabout.tsx/aboutRootAboutʦposts.tsx/postsRootPostsʦposts.index.tsx/posts精确匹配RootPostsPostsIndexʦposts.$postId.tsx/posts/$postIdRootPostsPostʦposts_.$postId.edit.tsx/posts/$postId/editRootEditPostʦsettings.tsx/settingsRootSettingsʦsettings.profile.tsx/settings/profileRootSettingsProfileʦsettings.notifications.tsx/settings/notificationsRootSettingsNotificationsʦ_pathlessLayout.tsxRootPathlessLayoutʦ_pathlessLayout.route-a.tsx/route-aRootPathlessLayoutRouteAʦ_pathlessLayout.route-b.tsx/route-bRootPathlessLayoutRouteBʦfiles.$.tsx/files/$RootFilesʦaccount.tsx/accountRootAccountʦaccount.overview.tsx/account/overviewRootAccountOverview对比目录路由可以发现posts_$postId/edit.tsx三层结构在扁平写法下被压缩为一个文件posts_.$postId.edit.tsx语义完全一致。混合扁平与目录路由100% 目录或 100% 扁平的路由结构都很难适配所有项目。TanStack Router 允许你将扁平路由与目录路由混合使用在合适的位置各取所长文件名路由路径组件输出ʦ__root.tsxRootʦindex.tsx/精确匹配RootRootIndexʦabout.tsx/aboutRootAboutʦposts.tsx/postsRootPostsposts┄ ʦindex.tsx/posts精确匹配RootPostsPostsIndex┄ ʦ$postId.tsx/posts/$postIdRootPostsPost┄ ʦ$postId.edit.tsx/posts/$postId/editRootPostsPostEditPostʦsettings.tsx/settingsRootSettingsʦsettings.profile.tsx/settings/profileRootSettingsProfileʦsettings.notifications.tsx/settings/notificationsRootSettingsNotificationsʦaccount.tsx/accountRootAccountʦaccount.overview.tsx/account/overviewRootAccountOverview上例中posts下较深的子路由用了目录$postId.edit.tsx而settings、account这类不深的层级用了扁平点号两种风格共存于同一棵树中。[!TIP] 如果默认的文件路由结构无法满足你的需求可以改用 Virtual File Routes用代码rootRoute/route/index/layout/physical等函数以编程方式构建引用真实文件的路由树在保留文件路由性能收益的同时完全掌控路由来源。文件命名约定速查要让路由被正确生成需要遵循一组简单的文件命名约定完整概念见 Route Trees。下表是核心约定的速查特性说明__root.tsx根路由文件必须命名为__root.tsx且必须放在所配置routesDirectory的根目录下。.分隔符文件名中的.表示嵌套路由例如blog.post会生成为blog的子路由。$令牌带$的路由段是参数化段会从 URL 路径名中提取该段作为路由param。_前缀以_开头的路由段是无路径布局路由Pathless Layout在 URL 匹配子路由时不会消耗任何路径段。_后缀以_结尾的路由段会从父路由中“脱离”不再嵌套在父路由之下。-前缀以-开头的文件/文件夹会被排除在路由树之外不会进入routeTree.gen.ts可用于在路由目录中就近存放逻辑代码。(folder)目录模式匹配该模式的文件夹被视为路由组Route Group文件夹本身不会进入 URL 路径。[x]转义方括号用于转义文件名中原本具有路由语义的特殊字符例如script[.]js.tsx生成/script.jsapi[.]v1.tsx生成/api.v1。index令牌以index结尾在文件扩展名之前的路由段在 URL 精确匹配父路由时命中父路由的索引路由。可通过indexToken配置项自定义支持字符串与正则见 API 参考。.route.tsx文件类型使用目录组织路由时route后缀可在目录的路径上创建路由文件。例如blog.post.route.tsx或blog/post/route.tsx都可作为/blog/post路由文件。可通过routeToken配置项自定义支持字符串与正则见 API 参考。[!WARNING] 请勿将routeFilePrefix、routeFileIgnorePrefix或routeFileIgnorePattern配置为与上表命名约定中的令牌冲突的值否则可能引发意外行为。动态路径参数Dynamic Path Params$令牌在扁平与目录路由中都可用于创建匹配 URL 动态段的路由。例如posts.$postId.tsx生成路由/posts/$postIdURL/posts/123命中后params为{ postId: 123 }在组件中通过Route.useParams()读取。动态段作用于路径的每一段例如/posts/$postId/$revisionId会同时捕获两段参数。详细的参数用法见 Path Params 指南。无路径布局Pathless Routes无路径布局路由用_前缀标记为子路由包裹逻辑或组件而不要求 URL 路径。例如文件名路由路径组件输出ʦ_app.tsxʦ_app.a.tsx/aRootAppAʦ_app.b.tsx/bRootAppB_之后的部分如_app中的app会作为该路由的 ID每个路由必须有唯一 ID这也是 TypeScript 类型正确性与自动补全的前提。注意由于无路径布局不参与 URL 段匹配它不支持动态段不能写出_$postId/这样的结构。完整解释见 Routing Concepts - Pathless Layout Routes。路由核心概念速览文件路由背后是一整套路由概念。理解它们你才能在路由文件中写出正确、强大的配置完整的 React/Solid 双框架代码示例见 Routing Concepts路由的解剖除根路由外所有路由都用createFileRoute创建其参数是文件路由的路径字符串如createFileRoute(/about)。这个路径由插件或 CLI 自动写入并维护——当你新建、移动或重命名路由文件时它会自动更新这是 TanStack Router 实现文件级类型安全的关键。根路由Root Route由createRootRoute()或带 Context 的createRootRouteWithContextMyRouterContext()创建位于树的最顶端没有路径、始终被匹配、始终被渲染。索引路由Index Route当 URL 精确匹配父路由且没有子路由命中时渲染索引路由例如posts.index.tsx对应createFileRoute(/posts/)注意尾斜杠。Splat / Catch-All 路由路径仅为$的路由捕获$之后 URL 的全部剩余片段存放在params._splat中。例如/files/documents/hello-world命中files/$时_splat为documents/hello-world。可选路径参数Optional Path Params使用{-$paramName}语法定义可缺失的段例如posts.{-$category}.tsx同时匹配/posts与/posts/tech可选参数路由的优先级低于精确匹配。布局路由Layout Routes如app.tsx包裹app.dashboard.tsx、app.settings.tsx组件内用Outlet /渲染子路由也常配合目录写法app/route.tsx。非嵌套路由Non-Nested Routes父路由段后缀_如posts_.$postId.edit.tsx不再嵌套在posts下作为顶层路由独立渲染。排除文件与文件夹-前缀的文件/文件夹如-posts-table.tsx、-components/不会进入routeTree.gen.ts但可以从路由文件正常导入非常适合就近放置组件、hook 等逻辑。路由组目录Route Group Directories(app)/、(auth)/这类()目录纯粹用于组织文件不影响路由树与组件树。开始使用文件路由要启用文件路由需要让项目构建工具接入TanStack Router 插件Bundler Plugin或TanStack Router CLI二者都会在构建与开发过程中自动生成路由配置这也是使用路由生成功能最省力的方式。当前需要配合受支持的框架React / Solid / Vue与打包器使用各组合的安装指南如下React Vite React Rspack/Rsbuild React Webpack React EsbuildSolid Vite Solid Rspack/Rsbuild Solid Webpack Solid Esbuild使用 CLI 的方式见 Router CLI 安装以 Vite 为例的接入步骤首先安装tanstack/router-plugin包然后在vite.config.ts中把插件放在框架插件之前注册import { defineConfig } from vite import react from vitejs/plugin-react import { tanstackRouter } from tanstack/router-plugin/vite export default defineConfig({ plugins: [ // 注意tanstack/router-plugin 必须放在 vitejs/plugin-react 之前 tanstackRouter({ target: react, autoCodeSplitting: true, }), react(), ], })import { defineConfig } from vite import solid from vite-plugin-solid import { tanstackRouter } from tanstack/router-plugin/vite export default defineConfig({ plugins: [ tanstackRouter({ target: solid, autoCodeSplitting: true, }), solid(), ], })仓库中的 quickstart-file-based 示例 展示了真实项目的完整写法——使用tanstackRouter({ target: react, autoCodeSplitting: true })即可零额外配置启动文件路由。默认配置与无需配置的开箱体验插件为文件路由提供了一组合理的默认值大多数项目无需任何额外配置{ routesDirectory: ./src/routes, generatedRouteTree: ./src/routeTree.gen.ts, routeFileIgnorePrefix: -, quoteStyle: single }忽略生成的路由树文件routeTree.gen.ts由 TanStack Router 全权管理不应被 lint / 格式化工具改动。建议在 Prettier.prettierignore、ESLint、Biome 中忽略它若使用 VSCode可在.vscode/settings.json中将其标记为只读并排除出搜索与文件监听避免重命名路由后文件异常弹出{ files.readonlyInclude: { **/routeTree.gen.ts: true }, files.watcherExclude: { **/routeTree.gen.ts: true }, search.exclude: { **/routeTree.gen.ts: true } }生成的路由树长什么样以 quickstart-file-based 示例 为例插件会根据src/routes/下的__root.tsx、index.tsx、about.tsx自动生成如下路由树文件节选关键结构import { Route as rootRouteImport } from ./routes/__root import { Route as IndexRouteImport } from ./routes/index import { Route as AboutRouteImport } from ./routes/about const IndexRoute IndexRouteImport.update({ id: /, path: /, getParentRoute: () rootRouteImport, } as any) const AboutRoute AboutRouteImport.update({ id: /about, path: /about, getParentRoute: () rootRouteImport, } as any) export interface FileRoutesByFullPath { /: typeof IndexRoute /about: typeof AboutRoute } // ... FileRoutesByTo / FileRoutesById / FileRouteTypes ... export const routeTree rootRouteImport ._addFileChildren(rootRouteChildren) ._addFileTypesFileRouteTypes()这段代码揭示了文件路由的两个核心机制类型映射FileRoutesByFullPath、FileRoutesByTo、FileRoutesById等接口把 URL、导航目标、路由 ID 与具体路由类型一一绑定并通过模块扩充declare module tanstack/react-router注入FileRoutesByPath这正是Link、useNavigate等 API 获得全类型补全与校验的根源运行时装配每个路由文件导出的Route被update后挂到父路由上最终通过rootRouteImport._addFileChildren(...)._addFileTypes(...)组装成一棵完整的、类型完备的路由树。从源码结构看路由生成发生在打包器的构建管线内——router-generator-plugin.ts 会根据配置的routesDirectory解析路径并启动文件监听watch一旦你在路由目录中新增、删除或重命名文件就会触发路由树的重新生成与热更新开发时几乎无需手动干预。文件路由配置选项详解文件路由的灵活性来自一组可配置项。以下选项在tanstackRouter({ ... })插件配置或tsr.config.jsonRouter CLI中均可设置完整说明见 File-Based Routing API Reference配置项默认值说明routesDirectory必填./src/routes路由文件所在目录相对于当前工作目录不能为空字符串或undefined。generatedRouteTree必填./src/routeTree.gen.ts生成路由树文件的保存路径相对于当前工作目录若disableTypes为true扩展名变为.js。virtualRouteConfigundefined用于配置 Virtual File Routes传入路由文件路径或直接传入路由树对象。routeFilePrefix空串只有以该前缀开头的文件才会被当作路由文件默认空串表示目录内所有文件都参与路由。routeFileIgnorePrefix-忽略以该前缀开头的文件/目录用于就近放置非路由逻辑文件。routeFileIgnorePatternundefined以正则忽略文件/目录例如.((css\|const).ts)\|test-page会忽略名称含.css.ts、.const.ts或test-page的文件/目录。routeTokenroute标识目录路径上的布局路由文件例如posts.route.tsx与posts/route.tsx都等价于posts.tsx均生成/posts支持正则。indexTokenindex标识索引路由文件的令牌例如posts.index.tsx与posts/index.tsx等价均生成/posts/支持正则。quoteStylesingle生成路由树与新建路由文件时使用的引号风格。semicolonsfalse为true时生成的路由树/新路由文件带分号。autoCodeSplittingfalse仅 Bundler 插件可用为true时自动对非关键路由配置做代码分割注意TanStack Router v2 起该值将默认开启。disableTypesfalse为true时关闭路由树类型生成输出.js文件。addExtensionsfalse控制生成导入路径的文件扩展名false剥离扩展名true保留原扩展名字符串如js则替换扩展名——ESM 项目常用js以满足 Node.js ESM 的.js导入要求。disableLoggingfalse关闭路由生成过程的控制台日志。routeTreeFileHeader[/* eslint-disable */, // ts-nocheck, // noinspection JSUnusedGlobalSymbols]在生成的路由树文件头部追加内容。routeTreeFileFooter[]在生成的路由树文件尾部追加内容。enableRouteTreeFormattingtrue是否对生成的路由树文件执行格式化大项目中该步骤耗时明显可关闭。tmpDir.tanstack/tmp相对于 cwd原子写入路由文件与路由树文件所用临时目录相对路径会解析到当前工作目录未设置时依次回退到process.env.TSR_TMP_DIR与默认值。用正则定制routeToken与indexToken当需要匹配多种命名风格时可以把routeToken/indexToken配置成正则。在tsr.config.json中使用{ regex, flags }对象{ routeToken: { regex: [a-z]-layout, flags: i } }在代码内联配置中直接使用原生RegExp{ routeToken: /[a-z]-layout/i }例如dashboard.main-layout.tsx、posts.protected-layout.tsx都会因匹配[a-z]-layout被识别为布局路由。需要注意的是正则针对的是路由路径最后一个段的完整内容——dashboard.main-layout.tsx匹配main-layout是完整段而dashboard.my-layout-extra.tsx不匹配该段是my-layout-extra。同理indexToken可用/[a-z]-page/之类的模式把home-page.tsx、posts.list-page.tsx识别为索引路由若想保留字面量段例如段名就叫home-page用方括号转义为[home-page].tsx即可。小结文件路由把“URL 结构 ↔ 文件系统 ↔ 组件树”三者统一起来/目录与.点号分别适配宽/深两种层级形态__root.tsx、$参数、_前缀/后缀、-忽略、()路由组、[]转义等约定覆盖了从根路由到 Catch-All 的完整路由谱系而 TanStack Router 插件与 CLI 则在构建期替你生成并维护类型完备的routeTree.gen.ts让全栈类型安全与自动代码分割成为文件路由的默认能力。若默认约定不满足需求还有 Virtual File Routes 与 API 参考 供你按需定制。【免费下载链接】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),仅供参考
返回列表