vue-router 路由组件懒加载完整指南:异步组件、Code-Splitting 与 Chunk 分组实战
vue-router 路由组件懒加载完整指南异步组件、Code-Splitting 与 Chunk 分组实战【免费下载链接】vue-router The official router for Vue 2项目地址: https://gitcode.com/gh_mirrors/vu/vue-router本文以 vue-routerVue 2 官方路由仓库中的 Lazy Loading 文档德文版与 英文版指南 为核心脉络讲解如何利用 Vue 的异步组件机制与 Webpack 的代码分割Code-Splitting能力把每个路由的组件拆分为独立 chunk、仅在路由被访问时才加载从而显著减小首屏 bundle 体积、缩短页面加载时间。读完本文你将掌握require.ensure、AMD 风格require与动态import()三种懒加载写法学会用命名 chunk 将同一路由下的多个组件合并为单个异步 chunk并理解 vue-router 在导航过程中等待异步组件解析完成的底层实现原理。为什么需要懒加载Bundle 膨胀与首屏性能使用打包器Bundler构建应用时所有 JavaScript 会被打包进一个或多个 bundle。随着应用规模增长这个 bundle 会变得相当大直接影响页面加载时间。更高效的做法是把每个路由的组件拆分成独立的 chunk只在路由被访问时才按需加载。这正是 Webpack Code-Splitting代码分割的用武之地。所谓分割就是把原本一个整体的大 bundle按照一定规则切成多个小文件配合 Vue 的异步组件机制vue-router 可以做到路由匹配到哪个组件才去请求哪个 chunk。从仓库的示例配置可以看到 Webpack 对 chunk 命名的支持examples/webpack.config.js 中设置了output.chunkFilename: [id].chunk.js与publicPath: /__build__/动态加载的异步 chunk 会按此规则生成独立的.chunk.js文件与主 bundle 分离存放。基础组合Vue 异步组件 × Webpack Code-Splitting实现路由懒加载的技术基础是两个成熟特性的组合Vue 异步组件Vue 2 允许组件以工厂函数形式定义函数被调用时才真正解析出组件定义。Webpack Code-SplittingWebpack 提供专门语法标注分割点split point被标注的模块会被自动拆成独立异步 chunk并在代码执行到该处时才发起请求。组合方式很简单把路由组件定义成一个异步解析函数。以原德文文档中的经典写法为例使用 Webpack 1 时代的require.ensure语法const Foo resolve { // require.ensure 是 Webpack 用于代码分割的特殊语法 require.ensure([./Foo.vue], () { resolve(require(./Foo.vue)) }) }这里Foo不再是一个普通组件对象而是一个接收resolve回调的工厂函数。Webpack 会把require.ensure的依赖列表中的模块此处为./Foo.vue单独打包成一个异步 chunk当路由首次需要渲染Foo时vue-router 会调用这个工厂函数Webpack 随即发起该 chunk 的网络请求加载完成后通过resolve把组件定义交还给路由。三种懒加载写法对比原德文文档给出了 Webpack 1 时代的两种写法而仓库英文文档与示例则补充了更现代的动态import()语法。三种方式本质等价可按工程年代与团队习惯选用。写法一require.ensureWebpack 1德文文档主推const Foo resolve { // 依赖数组 回调函数回调内 resolve 组件 require.ensure([./Foo.vue], () { resolve(require(./Foo.vue)) }) }写法二AMD 风格require简写德文文档指出还有一种 AMD 风格的简化写法把整个流程压缩成一行const Foo resolve require([./Foo.vue], resolve)require接收依赖数组和回调加载完成后直接把模块传给resolve。这一写法同样在仓库示例中被标注为 Webpack 1 的替代方案见 examples/lazy-loading/app.js 中的注释// If using Webpack 1, you will have to use AMD syntax or require.ensure。写法三动态import()Webpack 2推荐仓库英文文档与示例共同推荐动态import()语法——它本身就是 ES 提案dynamic-importWebpack 2 起支持用它标注代码分割点且返回一个 Promise// 单组件最简写法返回 Promise 的工厂函数 const Foo () import(./Foo.vue)这一写法直接对应 Vue 2.3 异步组件的新形态——工厂函数返回 Promise。在 examples/lazy-loading/app.js 中仓库正是用它定义懒加载组件Foo并注明该语法是已废弃的System.import()的替代。Babel 注意事项英文文档明确指出若使用 Babel 转译需要添加syntax-dynamic-import插件或较新版本 Babel 的对应支持否则 Babel 无法正确解析import()动态导入语法。返回 Promise 的工厂函数写法英文文档还给出了一种不依赖打包器、完全由 Promise 驱动的定义方式可用于演示异步组件的本质工厂函数返回 PromisePromise resolve 出组件定义const Foo () Promise.resolve({ /* component definition */ })仓库 examples/lazy-loading-before-mount/app.js 中有一个更生动的实战版本——用setTimeout模拟异步加载组件在 10ms 后才 resolveconst Foo () new Promise(resolve { setTimeout(() resolve({ template: div classfooThis is Foo/div }) , 10) })路由配置无需任何改动懒加载的核心便利在于组件定义方式变了但路由配置完全不变。原德文文档强调我们照常使用Foo即可const router new VueRouter({ routes: [ { path: /foo, component: Foo } ] })英文文档给出了同样的结论——Nothing needs to change in the route config, just useFooas usual。Foo究竟是普通组件对象还是异步工厂函数对路由表完全透明这让懒加载可以零成本地渐进引入到既有项目中。将同一路由下的组件分组到同一个 Chunk有时我们希望把同一条路由下嵌套的所有组件合并进同一个异步 chunk减少网络请求次数。Webpack 提供了命名 chunknamed chunks特性。Webpack 1require.ensure第三参数指定 chunk 名德文文档给出的是把 chunk 名作为require.ensure的第三个参数const Foo r require.ensure([], () r(require(./Foo.vue)), group-foo) const Bar r require.ensure([], () r(require(./Bar.vue)), group-foo) const Baz r require.ensure([], () r(require(./Baz.vue)), group-foo)Webpack 会把所有具有相同 chunk 名的异步模块打进同一个异步 chunk。同时德文文档特别指出因为 chunk 名已经承担了分组职责require.ensure的依赖数组不再需要显式列出依赖因此传空数组[]即可。Webpack 2.4动态import()的 Magic Comment英文文档展示了 Webpack 2.4 的等价写法——借助import()的 magic comment 语法webpackChunkNameconst Foo () import(/* webpackChunkName: group-foo */ ./Foo.vue) const Bar () import(/* webpackChunkName: group-foo */ ./Bar.vue) const Baz () import(/* webpackChunkName: group-foo */ ./Baz.vue)webpack 会将 chunk 名相同的异步模块归入同一异步 chunk。仓库 examples/lazy-loading/app.js 正是这样实现的Bar与Baz都声明了webpackChunkName: bar随后在路由表中把Baz嵌套为Bar的子路由const Bar () import(/* webpackChunkName: bar */ ./Bar.vue) const Baz () import(/* webpackChunkName: bar */ ./Baz.vue) const router new VueRouter({ mode: history, base: __dirname, routes: [ { path: /, component: Home }, { path: /foo, component: Foo }, { path: /bar, component: Bar, children: [ { path: baz, component: Baz } ] } ] })对应组件 Bar.vue 中渲染router-viewBaz.vue 的模板注释直接写明 Im loaded in the same chunk with Bar.实证了分组效果。源码原理导航如何等待异步组件解析懒加载之所以能无缝融入路由系统是因为 vue-router 在导航确认流程中加入了专门的异步组件解析环节。核心实现在 src/util/resolve-components.js 的resolveAsyncComponents函数中它的执行位置位于 src/history/base.js 的导航守卫队列const queue: Array?NavigationGuard [].concat( // in-component leave guards extractLeaveGuards(deactivated), // global before hooks this.router.beforeHooks, // in-component update hooks extractUpdateHooks(updated), // in-config enter guards activated.map(m m.beforeEnter), // async components resolveAsyncComponents(activated) // ← 异步组件解析挂在这里 )也就是说异步组件解析被当作导航流程中的一个守卫排在全局beforeEach钩子之后执行。resolveAsyncComponents内部做了几件关键的事识别异步组件遍历所有匹配到的路由记录matched若组件定义def是函数且没有cid属性def.cid undefined就认定它是异步解析函数——而不是 Vue 构造器。源码注释解释了这个设计vue-router 刻意不使用 Vue 默认的异步解析机制而是自行挂起导航直到组件解析完成。收集并逐一解析对每个异步组件执行def(resolve, reject)支持回调风格resolve/reject与 Promise 风格检测返回值res.then是否为函数两种异步组件形态与文档中resolve ...回调和() Promise两种写法一一对应。ES Module 兼容解析结果若带__esModule标记或Symbol.toStringTag Module会自动取其.default导出——这保证了import(./Foo.vue)这种 ESM 加载结果能被正确使用。缓存解析结果def.resolved被写回工厂函数match.components[key]被替换为最终组件避免重复加载解析出的普通对象还会经过_Vue.extend转换为组件构造器。全部就绪才放行用pending计数所有异步组件都 resolve 后才调用next()继续导航若任一解析失败reject或被同步throw则构造错误并next(error)中止导航配合导航失败处理机制向调用方暴露错误。防重复回调once包装确保resolve/reject只会生效一次——源码注释提到Webpack 2 中require.ensure也返回 Promise箭头函数简写可能让回调被额外触发一次once正好兜住这种情况。解析完成后组件通过 src/components/view.js 中router-view的渲染逻辑matched.components[name]挂载到视图上。整个链路确保了进入路由 → 按需加载 chunk → 组件就绪 → 渲染用户无需感知加载过程。完整可运行示例与验证方式仓库在 examples/lazy-loading 目录提供了一个可直接运行的完整示例覆盖了本文讨论的所有要点app.js路由配置包含普通组件Home、动态import()懒加载的Foo、命名 chunk 分组的Bar/Baz以及一个带动态参数的懒加载路由/a/:tags*通过setTimeout200ms 模拟异步解析对应 GitHub issue #2719 中动态参数与懒加载结合的边界场景。Foo.vue/Bar.vue/Baz.vue三个被懒加载的组件模板页面文案提示开发者在 Chrome DevTools 的 Network 面板中观察懒加载效果。index.html示例入口页通过script src/__build__/lazy-loading.js加载主 bundle异步 chunk 则按需请求。启动方式在仓库根目录安装依赖后运行 Webpack 开发服务器即可访问/lazy-loading/示例页切换路由时观察 Network 面板能看到对应的.chunk.js文件在首次访问该路由时才被请求。端到端测试 test/e2e/specs/lazy-loading.js 给出了可验证的行为断言包括点击导航切换/foo、/bar、/bar/baz断言对应懒加载组件文本渲染正确This is Foo!、This is Bar!、Baz。直接访问深层懒加载路由/lazy-loading/foo、/lazy-loading/bar/baz验证刷新页面时异步 chunk 同样能按需加载并渲染。验证/a/b/c这种带动态参数的路由无论是直接访问还是从首页点击进入懒加载组件的$route.path均正确显示/a/b/c。这些断言覆盖了首次访问触发加载与直接 URL 进入两条路径说明懒加载不仅对站内跳转有效对深链接deep link同样成立。实践建议与注意事项综合原文档与仓库实现落地懒加载时有几点值得留意工具链版本匹配Webpack 1 项目使用require.ensure或 AMD 风格requireWebpack 2 推荐动态import()。命名 chunk 的 magic comment 写法要求Webpack 2.4英文文档明确标注老版本只能使用require.ensure第三参数。Babel 转译使用 Babel 时需启用动态导入解析插件如syntax-dynamic-import否则import()语法无法被正确解析。分组粒度把同一嵌套路由下的兄弟组件放进同一个命名 chunk如示例中的Bar/Baz既能按路由粒度按需加载又能把同一次导航需要的多个组件合并为一次请求在加载次数与拆包粒度之间取得平衡。异步失败处理从 src/util/resolve-components.js 的实现可见异步组件加载失败会触发导航中止next(error)因此网络异常等场景下建议配合路由错误处理或全局错误上报机制。动态参数场景懒加载与动态路径参数如/a/:tags*可以正常组合但注意如示例所示参数路径不应被错误编码仓库 e2e 测试对此有专门覆盖。围绕按路由拆包、按需加载这一目标vue-router 通过把异步组件解析注入导航守卫队列让懒加载对路由配置完全透明——开发者只需用异步工厂函数替换组件定义即可在几乎零改造成本下获得显著的首屏加载性能收益。相关参考资料Lazy Loading 德文原文档、英文版指南、完整示例、异步解析实现、导航守卫队列、e2e 测试。【免费下载链接】vue-router The official router for Vue 2项目地址: https://gitcode.com/gh_mirrors/vu/vue-router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Sanic Blueprints 与 BlueprintGroup 完全指南:模块化路由、分组、版本化与源码级原理

Sanic Blueprints 与 BlueprintGroup 完全指南:模块化路由、分组、版本化与源码级原理

后端Web框架 【免费下载链接】sanic Accelerate your web app development | Build fast. Run fast. 项目地址: https://gitcode.com/gh_mirrors/sa/sanic 点击查看 免费下载 Sanic 的 Blueprint(蓝图)是用于"子路由"的模块化对象…

2026/9/20 15:07:26 阅读更多 →
技术指标实战拆解:均线、MACD、KDJ与量价共振交易系统

技术指标实战拆解:均线、MACD、KDJ与量价共振交易系统

简介:从大盘势能到个股买卖点,《股票实战技术指标详解大全》PDF适合希望系统提升技术分析能力的股票投资者、交易新手及量化研究员作为常备工具书。资源包共1个PDF文件,压缩包仅1.11MB,按大势型、超买超卖型、路径型等指标类别组织…

2026/9/20 15:07:26 阅读更多 →
AssetRipper 完整上手:免费开源的 Unity 游戏文件分析与资源提取工具

AssetRipper 完整上手:免费开源的 Unity 游戏文件分析与资源提取工具

AssetRipper 完整上手:免费开源的 Unity 游戏文件分析与资源提取工具 【免费下载链接】AssetRipper GUI application to analyze game files 项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipper 接手游戏项目时,你常会碰到包里塞了不…

2026/9/20 15:06:26 阅读更多 →

最新新闻

Qt 5.15.19 终结与 Qt for MCUs 2.11 LTS 发布:ESP32-S3 和 RA8D1 支持及地图渲染解析

Qt 5.15.19 终结与 Qt for MCUs 2.11 LTS 发布:ESP32-S3 和 RA8D1 支持及地图渲染解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 16:20:55 阅读更多 →
Snowpack + Preact + TypeScript 项目模板完全指南:从 create-snowpack-app 脚手架到生产构建

Snowpack + Preact + TypeScript 项目模板完全指南:从 create-snowpack-app 脚手架到生产构建

Snowpack Preact TypeScript 项目模板完全指南:从 create-snowpack-app 脚手架到生产构建 【免费下载链接】snowpack ESM-powered frontend build tool. Instant, lightweight, unbundled development. ✌️ 项目地址: https://gitcode.com/gh_mirrors/sn/snowp…

2026/9/20 16:20:55 阅读更多 →
Python自动化测试完整指南:接口、UI、数据驱动与持续集成

Python自动化测试完整指南:接口、UI、数据驱动与持续集成

做自动化测试这行久了,经常被问到同一个问题:“到底怎么用 Python 写自动化测试?”问的人有刚转行的测试新人,也有写了好几年功能用例但想突破的老手。我发现大家普遍不缺学习热情,缺的是一个能从零讲清楚、又带真实代…

2026/9/20 16:20:55 阅读更多 →
antd Tag.CheckableTag 实战:实现类似 Checkbox 的完全受控可勾选标签

antd Tag.CheckableTag 实战:实现类似 Checkbox 的完全受控可勾选标签

前端UI组件设计系统 【免费下载链接】ant-design An enterprise-class UI design language and React UI library 项目地址: https://gitcode.com/gh_mirrors/ant/ant-design 点击查看 免费下载 Tag.CheckableTag 是 ant-design 中 Tag 组件的可勾选形态&#xff0…

2026/9/20 16:20:55 阅读更多 →
GetQzonehistory:QQ空间历史说说、留言与评论完整导出到本地

GetQzonehistory:QQ空间历史说说、留言与评论完整导出到本地

GetQzonehistory:QQ空间历史说说、留言与评论完整导出到本地 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory QQ空间从未提供数据导出入口;互动列表会被逐批截断&…

2026/9/20 16:20:55 阅读更多 →
.NET 物理文件提供程序深入解析:Microsoft.Extensions.FileProviders.Physical 的查找、监视与轮询机制

.NET 物理文件提供程序深入解析:Microsoft.Extensions.FileProviders.Physical 的查找、监视与轮询机制

语言运行时标准库JIT编译编译器 【免费下载链接】runtime .NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps. 项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime 点击查看 免费下载 Microsoft.Extensions.FileProviders…

2026/9/20 16:19:53 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →