ARTICLE DETAIL

资讯详情

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

TanStack Router `createLazyFileRoute` 深度指南:基于 `.lazy.tsx` 后缀的手动代码分割路由配置

TanStack Router `createLazyFileRoute` 深度指南:基于 `.lazy.tsx` 后缀的手动代码分割路由配置 TanStack RoutercreateLazyFileRoute深度指南基于.lazy.tsx后缀的手动代码分割路由配置【免费下载链接】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本仓库文档 createLazyFileRoute function 展开讲解该函数在文件路由体系中的定位、完整 API 形态与使用约束并结合仓库源码剖析惰性路由实例LazyRoute是如何在路由匹配时被加载、挂载的。读完后你可以独立完成.lazy.tsx手动代码分割并理解其背后的lazyFn加载链路与 HMR 热替换机制。一、createLazyFileRoute 是什么createLazyFileRoute用于创建一个部分partial文件路由实例当路由被匹配到时该实例才会被惰性加载。它只能用来配置路由的非关键属性non-critical properties即componentpendingComponenterrorComponentnotFoundComponent这与 Code Splitting 指南 中的分类完全对应TanStack Router 把路由代码分为两类——Critical Route Configuration关键配置路径解析/序列化、Search Param 校验、loaders 与 beforeLoad、路由上下文、静态数据、links、scripts、styles 等必须在路由匹配时立即可用Non-Critical / Lazy Route Configuration非关键配置路由组件、错误组件、pending 组件、not-found 组件可以在匹配后按需加载。createLazyFileRoute就是承载第二类配置的载体关键配置放在主路由文件createFileRoute中非关键的 UI 组件配置放入带.lazy.tsx后缀的文件createLazyFileRoute从而让打包器把组件代码切到独立 chunk。⚠️ 指南中特别指出__root.tsx根路由文件无论使用createRootRoute还是createRootRouteWithContext不支持代码分割因为它无论当前路由是什么都会被渲染。二、API 参数详解path类型string必需但由tsr generate和tsr watch命令自动插入并维护表示路由所生成自的文件完整路径也就是说开发者写代码时不需要关心这个字符串是什么路由生成器Router Generator / Plugin 的generate/watch能力会在文件树变化时自动把它写成对应的路由路径字面量例如/posts并在文件重命名、移动后自动更新。返回值调用createLazyFileRoute(path)后返回一个新函数接受一个RouteOptions的部分对象用于配置文件的Route实例。其类型精确地Pick了四个非关键选项Pick RouteOptions, component | pendingComponent | errorComponent | notFoundComponent 在仓库源码中这个约束类型定义在 LazyRouteOptionsexport type LazyRouteOptions Pick UpdatableRouteOptions..., component | errorComponent | pendingComponent | notFoundComponent 这从类型层面硬性保证了惰性文件里不可能误配置loader、validateSearch等关键选项——它们是编译期错误而不是运行时静默失效。⚠️ 文档强调的注意事项为了让tsr generate和tsr watch正常工作文件路由实例必须使用Route标识符从文件中导出。生成器依赖这个约定的导出名来识别并改写路由文件。完整示例以下是文档给出的标准用法根路由场景import { createLazyFileRoute } from tanstack/react-router export const Route createLazyFileRoute(/)({ component: IndexComponent, }) function IndexComponent() { const data Route.useLoaderData() return div{data}/div }一个更贴近实战的.lazy.tsx拆分开合来自 Code Splitting 指南拆分前单文件src/routes/posts.tsx同时包含 loader 和组件// src/routes/posts.tsx import { createFileRoute } from tanstack/react-router import { fetchPosts } from ./api export const Route createFileRoute(/posts)({ loader: fetchPosts, component: Posts, }) function Posts() { // ... }拆分后关键配置保留在主文件src/routes/posts.tsx// src/routes/posts.tsx import { createFileRoute } from tanstack/react-router import { fetchPosts } from ./api export const Route createFileRoute(/posts)({ loader: fetchPosts, })非关键组件配置移入带.lazy.tsx后缀的文件并改用createLazyFileRoute// src/routes/posts.lazy.tsx import { createLazyFileRoute } from tanstack/react-router export const Route createLazyFileRoute(/posts)({ component: Posts, }) function Posts() { // ... }指南同时解释了为什么 loader 不会被拆分loader 本身已经是异步边界再拆分等于为拿到 chunk 和执行 loader 双重付出等待且 loader 通常比组件更不容易造成大 bundleloader 是最值得预载的资产之一例如 hover 链接这类默认预载意图必须可以在没有额外异步开销的情况下被拿到。三、源码实现从工厂函数到 LazyRoute 实例1. 工厂函数本体React 版本的实现位于 packages/react-router/src/fileRoute.ts并在 packages/react-router/src/index.tsx 中对外导出export function createLazyFileRoute TFilePath extends keyof FileRoutesByPath, TRoute extends FileRoutesByPath[TFilePath][preLoaderRoute], (id: TFilePath): (opts: LazyRouteOptions) LazyRouteTRoute { if (typeof id object) { return new LazyRouteTRoute(id) as any } return (opts: LazyRouteOptions) new LazyRouteTRoute({ id, ...opts }) }从源码结构看有几个细节值得注意第一个类型参数TFilePath约束为keyof FileRoutesByPath——这个接口由路由生成器在类型声明文件中填充因此路径字符串一旦写错会立即产生类型错误路径与文件树是一一对应的第二个类型参数TRoute取自该文件路径对应的preLoaderRoute即主路由文件中通过createFileRoute创建的“去掉 loader 之前的”路由类型这让.lazy.tsx文件里的Route.useLoaderData()等钩子能推断出 loader 的数据类型函数内部还保留了一个typeof id object的分支直接从对象构造LazyRoute这是面向框架适配非标准字符串路径的容错路径。同仓库的 Solid 与 Vue 版本tanstack/solid-router、tanstack/vue-router提供语义一致的createLazyFileRouteCode Splitting 指南的示例即从这两个包导入。2. LazyRoute 类与路由级 HookcreateLazyFileRoute(path)(opts)的返回对象是 LazyRoute 类 的实例。它虽然只是一个“配置存根stub”但从源码结构看它与完整的Route实例暴露了同一组路由级 Hook——每个 Hook 内部都会自动补上from: this.options.iduseMatchuseRouteContextuseSearchuseParamsuseLoaderDepsuseLoaderDatauseNavigate正因为如此上面文档示例中IndexComponent才能直接在.lazy.tsx里写const data Route.useLoaderData()——尽管 loader 定义在主路由文件中。这个行为有专门的测试保障packages/react-router/tests/fileRoute.test.ts 遍历getRouteApi的所有use*钩子断言createLazyFileRoute创建出的惰性路由实例上每个同名钩子都已定义。四、运行时机制lazyFn 加载链路与 HMR 替换惰性配置在何时、如何被合并进真实路由实例核心逻辑在 packages/router-core/src/load-client.ts 中的loadRouteChunkL69-L107路由匹配完成后渲染流程发现该路由带有lazyFn由 bundler 插件注入的import(./xxx.lazy.tsx)动态导入函数执行route.lazyFn()拿到.lazy.tsx模块里导出的LazyRoute实例从lazyRoute.options中剔除id字段将其余选项Object.assign到真实路由的route.options上并把route._lazy置为true表示惰性选项已就位加载失败时route._lazy复位为undefined并向上抛出错误此时通常由errorComponent边界接管。_lazy字段还承担去重职责若已有进行中的加载 Promise后续调用直接复用该 Promiseroute._lazy存的就是它避免同一 chunk 被并发拉取多次。开发体验方面HMR 场景由 replaceRouteChunk 支持export function replaceRouteChunk( route: AnyRoute, lazyFn: AnyRoute[lazyFn], ): void { route.lazyFn lazyFn ?? route.lazyFn route._lazy undefined }即热更新时把旧的lazyFn替换为新模块的导入函数并清空惰性状态下次匹配时重新加载新 chunk。Router Core 侧的 HMR 处理器packages/router-plugin/src/core/hmr/handle-route-update.ts正是通过_replaceRouteChunk触发这条链路。与 autoCodeSplitting 的关系bundler 插件侧packages/router-plugin/src/core/code-splitter实现了两种拆分策略SplitStrategy lazyFn | lazyRouteComponent其中lazyFn策略会向路由的 props 中注入一个携带import()动态导入的lazyFn调用。从源码结构看使用autoCodeSplitting: true时插件会自动为所有文件路由完成上述关键/非关键拆分开发者无需手写.lazy.tsx手动.lazy.tsx后缀方案则适用于无法启用自动拆分的场景指南明确它是最简单的替代路径。此外仓库的 e2e 场景 e2e/react-router/basic-file-based-code-splitting 提供了拆分后文件路由的端到端集成验证可作参考。五、使用要点与限制小结事项说明可配置的选项仅限component、pendingComponent、errorComponent、notFoundComponent类型层强约束见 LazyRouteOptionspath参数手动编写无必要由tsr generate/tsr watch自动插入并维护导出约定必须使用Route标识符导出否则tsr generate/tsr watch无法正确工作loader保留在主路由文件的关键配置中不进入.lazy.tsx根路由__root.tsx不支持代码分割类型安全路径受FileRoutesByPath约束loader 数据类型经由preLoaderRoute贯通到惰性文件运行时匹配后经lazyFn()动态导入选项合并到真实路由loadRouteChunkHMR 下经replaceRouteChunk支持热替换参考文件文档docs/router/api/router/createLazyFileRouteFunction.md、docs/router/guide/code-splitting.md、docs/router/api/router/RouteOptionsType.md、docs/router/api/router/RouteType.md实现packages/react-router/src/fileRoute.ts、packages/router-core/src/fileRoute.ts、packages/router-core/src/load-client.ts插件与 HMRpackages/router-plugin/src/core/code-splitter、packages/router-plugin/src/core/hmr/handle-route-update.ts测试与 e2epackages/react-router/tests/fileRoute.test.ts、e2e/react-router/basic-file-based-code-splitting【免费下载链接】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),仅供参考
返回列表