路由懒加载

发布时间:2026/6/23 1:22:22
路由懒加载
文章目录前言一、基本原理1.1 动态 import 拆分 chunk1.2 与同步引入对比二、Webpack 魔法注释2.1 自定义 chunk 名称2.2 prefetch空闲时预加载2.3 preload并行高优先级加载2.4 prefetch vs preload三、Vite 批量注册路由3.1 import.meta.glob3.2 按模块分组四、defineAsyncComponent 与路由懒加载4.1 区别五、典型场景5.1 中后台按业务模块懒加载5.2 权限路由动态加载5.3 首屏同步 其余懒加载六、面试聚焦6.1 prefetch 与 preload 区别6.2 懒加载的组件会重复请求吗6.3 路由懒加载 vs defineAsyncComponent七、易混淆点八、思考与练习总结前言路由懒加载是 Vue SPA 首屏优化的常用手段通过动态import()将页面组件拆成独立 chunk访问时才加载。本篇会讲清楚路由懒加载的原理与写法Vite 批量注册与 prefetch / preload 区别defineAsyncComponent 与路由懒加载的场景区别一、基本原理1.1 动态 import 拆分 chunkconstroutes[{path:/,component:()import(/views/Home.vue)// 懒加载},{path:/user,component:()import(/views/User.vue)},{path:/order,component:()import(/views/Order.vue)}]工作流程构建工具Webpack / Vite为每个动态import()生成独立 chunk 文件带 content hash首屏只加载当前路由所需代码其余 chunk 不下载用户导航到对应路由时浏览器再请求该 chunkchunk 下载完成后渲染页面组件1.2 与同步引入对比// ❌ 同步引入所有页面打包进主 bundle首屏体积大importHomefrom/views/Home.vueimportUserfrom/views/User.vueimportOrderfrom/views/Order.vue// ✅ 懒加载按路由拆分首屏只加载 Homecomponent:()import(/views/User.vue)对比项同步引入路由懒加载首屏体积大全部页面小当前页面加载时机应用启动时导航到该路由时适用场景首屏必需页面非首屏业务页面二、Webpack 魔法注释2.1 自定义 chunk 名称constroutes[{path:/order,component:()import(/* webpackChunkName: order *//views/Order.vue)}]// 生成文件order.[hash].js便于调试和缓存分析2.2 prefetch空闲时预加载{path:/dashboard,component:()import(/* webpackPrefetch: true *//views/Dashboard.vue)}浏览器在空闲时提前下载该 chunk用户后续导航时可更快渲染。适合「很可能接下来会访问」的页面。2.3 preload并行高优先级加载{path:/critical,component:()import(/* webpackPreload: true *//views/Critical.vue)}与父 chunk并行加载优先级高。适合当前页面很快就要用到的模块。2.4 prefetch vs preload对比项preloadprefetch加载时机与父 chunk 并行浏览器空闲时优先级高低用途当前页面即将需要未来可能访问典型场景首屏关键子模块其他路由页面!-- preload --linkrelpreloadhrefcritical.jsasscript!-- prefetch --linkrelprefetchhrefdashboard.jsasscriptVite 生产构建同样支持这些 magic comment行为与 Webpack 类似。三、Vite 批量注册路由3.1 import.meta.glob页面较多时可批量扫描并自动生成懒加载路由// router/routes.jsconstmodulesimport.meta.glob(../views/**/*.vue)constroutesObject.entries(modules).map(([path,component]){// ../views/user/List.vue → /user/listconstroutePathpath.replace(../views,).replace(/\.vue$/,).replace(/\/index$/,).toLowerCase()return{path:routePath||/,component// 已是 () import() 形式}})3.2 按模块分组// 只扫描 admin 目录constadminModulesimport.meta.glob(../views/admin/**/*.vue)// eager: true 则同步加载非懒加载constsyncModulesimport.meta.glob(./dir/*.js,{eager:true})适合中后台系统大量页面模块的自动注册减少手动维护 routes 数组。四、defineAsyncComponent 与路由懒加载4.1 区别// 路由懒加载Vue Router 直接使用动态 import{path:/user,component:()import(/views/User.vue)}// defineAsyncComponent用于非路由场景的异步组件import{defineAsyncComponent}fromvueconstAsyncChartdefineAsyncComponent({loader:()import(/components/Chart.vue),loadingComponent:LoadingSpinner,errorComponent:ErrorDisplay,delay:200,timeout:10000})对比项路由懒加载defineAsyncComponent使用场景路由页面组件弹窗、Tab、动态组件加载配置NProgress / 全局 loadingloading / error / timeout代码分割按路由拆 chunk按组件拆 chunk路由场景直接用() import()即可需要 loading/error 降级时用defineAsyncComponent包装后再作为 component。五、典型场景5.1 中后台按业务模块懒加载constroutes[{path:/user,component:()import(/views/user/index.vue)},{path:/order,component:()import(/views/order/index.vue)},{path:/report,component:()import(/views/report/index.vue)}]5.2 权限路由动态加载// 根据角色动态 addRoute模块本身也是懒加载constadminRoutes[{path:/admin,component:()import(/layouts/AdminLayout.vue),children:[{path:users,component:()import(/views/admin/Users.vue)}]}]if(roleadmin){adminRoutes.forEach(routerouter.addRoute(route))}5.3 首屏同步 其余懒加载importHomefrom/views/Home.vue// 首屏同步加载constroutes[{path:/,component:Home},{path:/about,component:()import(/views/About.vue)},{path:/contact,component:()import(/views/Contact.vue)}]首屏关键页面同步引入其余全部懒加载平衡 FCP 与总体积。六、面试聚焦6.1 prefetch 与 preload 区别preload高优先级与父 chunk 并行当前页面很快需要prefetch低优先级浏览器空闲时加载未来可能访问的路由6.2 懒加载的组件会重复请求吗不会正常情况下。首次访问后 chunk 被浏览器缓存后续导航直接使用缓存。只有构建后文件 hash 变化发版更新才会重新请求。6.3 路由懒加载 vs defineAsyncComponent路由懒加载用于页面级代码分割defineAsyncComponent用于组件级异步加载可配置 loading/error 状态两者场景不同。七、易混淆点懒加载 ≠ 不加载首次进入该路由仍会请求 chunk只是不在首屏加载。chunk 会缓存除非 hash 变化否则不会重复下载。defineAsyncComponent 不替代路由懒加载路由直接用() import()更简洁。import.meta.glob 默认懒加载不加eager: true时返回的都是动态 import 函数。prefetch 不是立即加载在浏览器空闲时才预取不要与 preload 混用场景。八、思考与练习1.路由懒加载的原理是什么解析路由 component 使用动态import()构建工具拆成独立 chunk导航到该路由时才下载并执行减小首屏 bundle。2.prefetch 和 preload 如何选择解析preload 用于当前页面即将需要的模块高优先级并行prefetch 用于其他路由页面空闲时预取。3.懒加载后第二次访问还会请求吗解析不会重复请求浏览器已缓存该 chunk发版后 hash 变化才会重新下载。4.如何给路由切换加 Loading 效果解析常用 NProgress 配合路由守卫beforeEach 开始、afterEach 结束或使用defineAsyncComponent的loadingComponent配置加载态组件。5.Vite 如何批量注册懒加载路由constmodulesimport.meta.glob(../views/**/*.vue)// 遍历 modules 生成 routes 数组总结原理动态import()按路由拆分 chunk访问时才加载减小首屏体积魔法注释webpackChunkName命名、webpackPrefetch空闲预取、webpackPreload并行加载import.meta.globVite 批量扫描页面自动生成懒加载路由选型路由用() import()非路由异步组件用defineAsyncComponent