首屏转了三秒才出来?给路由做懒加载把包拆开

举报
茉莉风铃 发表于 2026/09/27 18:56:26 2026/09/27
【摘要】 Vue3后台首屏白屏3秒,用Vite路由懒加载+manualChunks把包拆开,首屏js从1.2MB降到400kb,白屏压到1秒内的一些方法;

一、背景:打包完首屏白等三秒

之前做的一个 Vue3 后台管理系统,菜单挂了二十多个页面。刚开始为了省事,所有视图都在入口 main.ts 里静态 import 进来,Rollup 把它们全打进同一个 app.js。打包完一看,app.js 有 1.2MB(gzip 之后还有 380KB 左右)。用户登录后点进首页,要白屏转三秒多才出内容,弱网环境更夸张,体验很差。问题就出在:用户只想看一个首页,浏览器却把二十多个页面的代码全下载执行了一遍。当时运营侧也收到过用户反馈说后台点开很卡,但后端接口监控显示响应并不慢,瓶颈其实全卡在前端打包体积上,属于典型的前端性能问题,这锅后端不背。

二、路由懒加载:用到哪个页面才加载哪个

最直接的改法,是把静态导入换成动态导入。路由表里原来写 component: OrderView,改成 component: () => import('../views/Order.vue')。Vite 底层是 Rollup,看到这种动态 import 会自动把每个视图拆成独立的 chunk 文件。用户访问哪个路由,才去下载那个路由对应的 chunk,没访问的页面代码根本不进首屏。首页只加载登录态和首页本身那一两个 chunk,首屏 JS 直接从 1.2MB 掉到 400KB 上下,白屏时间压到了 1 秒以内。改完打包,dist 里会多出一堆 Order-xxxx.js 这样的文件,正是按路由拆出来的独立 chunk。

// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
  { path: '/', component: () => import('../views/Home.vue') },
  { path: '/order', component: () => import('../views/Order.vue') },
  { path: '/report', component: () => import('../views/Report.vue') },
]
export default createRouter({ history: createWebHistory(), routes })

三、再拆公共 vendor:第三方库单独缓存

光做路由懒加载还不够。vue、vue-router、pinia、element-plus、echarts 这些第三方库,默认会进公共 chunk,每次刷新首屏还是得下它们。解决办法是在 vite.config.ts 里用 build.rollupOptions.output.manualChunks,把体积大的库单独拆出来:

// vite.config.ts
export default defineConfig({
  base: '/admin/',
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          echarts: ['echarts'],
          vendor: ['vue', 'vue-router', 'pinia', 'element-plus'],
        },
      },
    },
  },
})

拆完之后,vendor 和 echarts 这种不常变的库能走浏览器长缓存,业务代码发版更新时它们命中缓存不用重新下,首屏又能再快一截。

四、关键点

第一,路由部署在子路径(比如整个后台挂在 https://域名/admin/ 下)时,动态 import 的 chunk 请求默认是相对当前页面路径的。用户直接刷新 /admin/order 子路由,chunk 的相对路径会算错,结果 404。修法是给 vite.config.ts 配 base: '/admin/',或者用 import.meta.env.BASE_URL 拼绝对路径,保证 chunk 永远走正确的绝对地址。

第二,echarts 一开始是 import * as echarts from 'echarts' 全量引入,光这一个库就吃了将近 1MB 打进 vendor。后来改成按需引入,只注册用到的图表和组件,vendor 又小了一半:

import * as echarts from 'echarts/core'
import { LineChart, BarChart } from 'echarts/charts'
import { GridComponent, TooltipComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([LineChart, BarChart, GridComponent, TooltipComponent, CanvasRenderer])

第三,懒加载之后首屏请求数会变多(可能十几个小 chunk),在 HTTP/1.1 下受并发数限制反而可能更慢;要么上 HTTP/2,要么把极小的 chunk 通过 build.assetsInlineLimit 内联进主文件,缓解请求数。

五、怎么验证真的瘦了

打包完别凭感觉,看两处:一是 dist/assets 目录,确认每个路由都对应一个独立 chunk 文件;二是浏览器开 DevTools → Network,勾上「Disable cache」刷新首页,看实际下载的 JS 总大小。想更直观,可以装 rollup-plugin-visualizer,npm run build 后生成一张体积构成图,哪个包最大一目了然,缺哪块优化很清楚。

六、文章总结

路由懒加载加 manualChunks 分包,是前端首屏优化里性价比最高的一步——不改业务逻辑、纯配置,白屏就能从三秒压到一秒内。再叠上 CDN 和 gzip/brotli 压缩,基本就把首屏体量的问题解决了。这也是我后来每个项目初始化必做的一步。后来顺手用 Lighthouse 跑了下首屏评分,从 40 多分涨到 80 分以上,算是配置优化顺手拿到的副产品。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。