news 2026/9/14 19:55:24

Vue3+Vite打包体积优化实战:从2.8M到500K的完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue3+Vite打包体积优化实战:从2.8M到500K的完整方案

先说个真实场景。上个月接手一个 Vue3 后台管理系统,用的是 Vite 做构建工具,功能其实不算复杂:登录鉴权、用户管理、订单列表、数据报表、还有几个大屏展示页。但同事提了个问题——每次npm run build之后,打包出来的 dist 目录里就躺着一个 2.8M 的 JS 文件,加载时首屏白屏两三秒,客户在低配置电脑上打开尤其明显。我当时第一反应是:这项目到底塞了多少东西,能把一个前端应用打到 2.8M?

把这个问题排查下来,其实整个过程挺典型的。一番操作之后,打包体积从 2.8M 降到了 500K 左右,优化幅度超过 80%。这篇文章就把完整方案写出来,包括每一步的决策逻辑、具体配置、还有我踩坑的过程。文章覆盖的核心关键词是 Vue3、Vite、打包体积优化,适合的人群主要是:用 Vite 构建 Vue3 项目的开发者、遇到首屏加载慢问题的前端工程师、以及想系统了解构建优化思路的人。

1. 优化前先看现状:定位体积“大头”在哪

1.1 环境与项目情况说明

先交代一下项目背景。技术栈是 Vue 3.2 + Vite 3 + Vue Router 4 + Pinia + Element Plus + ECharts + Axios,路由大概 30 多个页面,其中大概 8 个页面用到了 ECharts 图表,4 个页面引用了 Element Plus 的表格、弹窗、表单等组件。整个项目没有做任何分包和懒加载处理,所有组件都在 main.js 里集中注册。

当时在本地执行构建命令:

npm run build

输出结果大概是这样的:

dist/index.html 0.46 KB dist/assets/index-xxxx.js 2798.32 KB / gzip: 812.36 KB dist/assets/index-xxxx.css 156.22 KB / gzip: 24.15 KB

2798KB 的 JS 文件,gzip 之后也有 812KB。这个体积放到服务器上,不考虑 HTTP 缓存的情况下,用户每次访问首屏都要下载将近 1M 的压缩资源,再加上浏览器解析执行 JS 的时间,白屏时长可想而知。

我去查了浏览器开发工具里的网络面板,发现这个 JS 文件下载耗时其实还行(本地 100M 带宽测试),但脚本执行和解析花了将近 2 秒。也就是说问题不只是网络传输,还有浏览器在启动阶段就要去解析、编译这个巨大的 JS bundle。这也是为什么大家都说“打包体积越大,首屏越慢”的根本原因。

1.2 用构建分析工具给打包产物做“体检”

做体积优化,第一步绝对不是凭感觉去猜哪块大,而是用工具看清楚每个模块占了多少体积。这里推荐一个我用了好几次的插件:rollup-plugin-visualizer

安装命令:

npm install -D rollup-plugin-visualizer

vite.config.js里配置:

import { visualizer } from 'rollup-plugin-visualizer'; export default defineConfig({ plugins: [ vue(), visualizer({ open: true, gzipSize: true, brotliSize: true, filename: 'analyze.html' }) ] });

重新执行npm run build,构建结束后会自动打开一个analyze.html的交互式图表页面。这个页面会以矩形树图的方式展示所有模块体积,鼠标移到色块上就能看到具体是哪个依赖、占了多少字节、gzip 之后又是多少。

我当时看到分析结果时,基本可以一眼锁定问题:

依赖包打包体积(未压缩)占比
echarts1094 KB39.1%
element-plus674 KB24.1%
vue-router / pinia / vue346 KB12.4%
axios / dayjs / lodash-es262 KB9.4%
业务代码及其他422 KB15%

一个 ECharts 全量包就占了接近 40%。Element Plus 全量引入也占了将近四分之一。这两个是绝对的大头,优先处理它们,收益会非常明显。

1.3 从分析结果判断后续优化优先级

很多人看到体积大就直接上 CDN,其实这是不严谨的。我的建议是先判断“哪些体积是可以避免的”,再判断“哪些体积是必须传输的”。

ECharts 全量引入的问题在于:项目里只用到了折线图、柱状图、饼图这几个常用图表,但全量包会把所有地图、所有图表类型、所有组件都打包进来。这就好比去超市买一瓶酱油,结果把整个货架都搬回家了。按需引入可以把 ECharts 的体积压缩到 300KB 左右,如果能配合 gzip,最终传输只有 100KB 上下。

Element Plus 全量注册的情况也类似。项目中用到的组件大概 20 个左右,但全量引入会让所有组件都进入 bundle。而且还要注意一个问题:Element Plus 的样式文件也是大头,如果按需引入组件但不按需引入样式,CSS 体积也不会降下来。

Vue 相关的依赖体积算是比较合理的,不需要做太多处理,但它们可以通过拆包策略共享到单独 chunk,这样配合浏览器的缓存策略能明显提升二次访问体验。

整体判断下来,优化优先级是这样排的:

  • 第一优先:ECharts 按需引入
  • 第二优先:Element Plus 按需引入
  • 第三优先:路由懒加载
  • 第四优先:构建拆包 + gzip

这个优先级是按照“体积下降幅度 × 改动风险”来排的。ECharts 和 Element Plus 改动只影响业务代码的引用方式,不影响构建配置,风险较低。路由懒加载改动每个页面的引入方式,工作量略大。构建拆包和 gzip 是纯配置层面的事,随时可以加。

2. 优化方案的选型与取舍:为什么这么做

2.1 先从“路由懒加载”开始

路由懒加载的实现方式,本质上就是利用 Vite(底层是 Rollup)对动态import()的支持。把原来在路由配置里直接 import 组件,改成箭头函数返回动态 import:

// 优化前:所有组件都会打包进同一个 chunk import UserManage from '@/views/user/UserManage.vue'; // 优化后:组件会在路由被访问时才加载 const UserManage = () => import('@/views/user/UserManage.vue');

如果把所有路由都改成这种写法,原来 2.8M 的 index.js 会按路由被拆成若干个更小的 chunk。用户访问首页时只加载首页相关的 JS,访问用户管理页时才加载用户管理页的 JS。

这个方案之所以放在前面,是因为它不改变代码逻辑、不改变依赖体系、不引入外部服务,纯粹是改变模块的加载时机。收益很稳定,风险几乎为零。而且它带来一个额外的好处:不同页面之间各自独立,修改其中某页的代码后再发版,浏览器可以只重新下载这个小 chunk,配合强缓存策略,老用户的下一次访问也会更快。

如果你用的是 Vue Router,还有一个细节值得注意:在createWebHistorycreateWebHashHistory的选择上,懒加载不受影响,但历史模式会要求服务器做 history fallback 配置,这点在后端部署时容易踩坑,下面第四部分会专门说。

2.2 第三方库“按需引入”的收益边界

按需引入并不是所有场景都有收益,一定要分情况看。

如果是 UI 组件库,比如说 Element Plus,按需引入的收益取决于你这个项目用了它多少组件。用得多,按需引入省得少;用得少,省得多。而且现在 Element Plus 官方给出了一个比较省事的方案:配合unplugin-vue-componentsunplugin-auto-import插件做自动按需引入。插件会在编译阶段扫描模板中用到的组件,自动 import 对应的组件和样式。

npm install -D unplugin-vue-components unplugin-auto-import

配置到 vite.config.js 里:

import Components from 'unplugin-vue-components/vite'; import AutoImport from 'unplugin-auto-import/vite'; import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'; export default defineConfig({ plugins: [ vue(), AutoImport({ resolvers: [ElementPlusResolver()] }), Components({ resolvers: [ElementPlusResolver()] }) ] });

这个方案用起来确实香,我不用手动去写import { ElButton } from 'element-plus',模板里直接写<el-button>就行。插件会自动注入。

但实际上我自己在项目里没有直接用这个自动方案,而是选择手动按需引入。原因是这个项目里用了很多 Element Plus 的指令(比如v-loading)和消息提示组件(ElMessageElMessageBox),这些组件不是写在模板里的,自动按需引入插件对它们的处理偶尔会漏。手动按需引入虽然代码看起来啰嗦一点,但可控性更高。

手动按需引入的做法是这样的:

import { ElButton, ElTable, ElDialog, ElMessage, ElMessageBox } from 'element-plus'; import 'element-plus/es/components/button/style/css'; import 'element-plus/es/components/table/style/css'; import 'element-plus/es/components/dialog/style/css';

注意样式文件要单独引,而且路径要对应组件。这个写起来确实繁琐,但胜在一目了然。

如果是图表库 ECharts,按需引入的收益会相当可观。因为 ECharts 是按模块设计的,你可以只注册需要的图表类型和组件。完整写法下一部分细说。

这里要特别提醒一句:如果项目里用了超过 30 个 Element Plus 组件,按需引入和不按需引入的体积差距会变得很小。这时候考虑分析一下是不是应该把整个组件库拆到单独的 chunk,让浏览器走缓存。说到底,按需引入是减少“首次加载”的体积,拆包是提高“二次访问”的速度,两者目标不同,混着用才合理。

2.3 CDN 外部化:适合在什么条件下做

把一些体积大、更新频率低、基本不会变的第三方库通过 CDN 加载,是前端性能优化的经典方法。它的本质是让构建工具把某些依赖标记为 external,不打包进产物,然后在 index.html 里通过<script>标签引用外部链接。

这个方案的优势是极端的“首包小”——比如 vue、vue-router、pinia、echarts 这些库都走 CDN,业务代码可能只有几百 KB。劣势也很明显:

  • 需要外网能访问到 CDN 域名,内网部署环境下这是硬伤
  • 一旦 CDN 挂了,或者某个依赖更新后出现兼容问题,排障成本很高
  • 开发环境下 external 容易引入跨域问题,需要额外处理

我的个人建议是:如果项目部署在公网的服务器上,CDN 方案可以试;如果是内网环境,或者对资源可控性要求很高,那建议用“本地静态资源 + 拆包”的方式,把高频依赖进行单独 chunk,并设置强缓存。

在 Vite 里配置 externals 其实不算最直观,因为 Vite 的构建底层是 Rollup,external 属于build.rollupOptions的配置项。对于一个用 CDN 的 Vue3 项目,配置大致是这样的:

export default defineConfig({ build: { rollupOptions: { external: ['vue', 'vue-router', 'pinia', 'echarts'], output: { globals: { vue: 'Vue', 'vue-router': 'VueRouter', pinia: 'Pinia', echarts: 'echarts' } } } } });

同时,写一个公共方法去动态插入 script 标签加载这些 CDN 文件:

const cdnScripts = [ 'https://unpkg.com/vue@3.2.47/dist/vue.global.prod.js', 'https://unpkg.com/vue-router@4.1.6/dist/vue-router.global.prod.js', 'https://unpkg.com/pinia@2.0.36/dist/pinia.iife.prod.js', 'https://unpkg.com/echarts@5.4.3/dist/echarts.min.js' ]; function loadCdnScript(src) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } // 在应用入口挂载前加载 async function bootstrap() { await Promise.all(cdnScripts.map(loadCdnScript)); createApp(App).use(router).use(pinia).mount('#app'); } bootstrap();

说实话,这套做法我自己在正式项目里用过,效果确实立竿见影,但它不是没有坑。下面第四部分说到“CDN 引入但被重复打包”这个问题时会展开讲。

3. 实操:从 2.8M 到 500K 的完整落地

3.1 路由懒加载改造后的中期数据

先看路由懒加载这步单独的效果。我改造完所有路由后重新构建,产物从单个index-xxxx.js变成了多个 chunk,结构大概是这样的:

dist/index.html 0.46 KB dist/assets/index-xxxx.js 821.33 KB / gzip: 236.21 KB dist/assets/UserManage-xxxx.js 356.51 KB / gzip: 92.18 KB dist/assets/DataReport-xxxx.js 184.22 KB / gzip: 48.44 KB dist/assets/Login-xxxx.js 42.33 KB / gzip: 12.08 KB dist/assets/vendor-xxxx.js 276.89 KB / gzip: 86.12 KB

整体看来,首屏加载的 JS 从 2.8M 降到了大约 821KB(index + vendor),再加上其他异步 chunk,至少把首屏必须执行的代码量降了一个量级。这里面 vendor 是 Rollup 根据依赖自动提取出来的公共模块,包含 vue、vue-router、pinia、axios 这些。

这一步做完,我发现一个有意思的现象:gzip 后体积下降的比例比原始体积下降的比例更大。原因是 ECharts 和 Element Plus 这类库中重复的代码模式很多,gzip 对它们的压缩率本身就很高,拆包后每个 chunk 内部的重复度降低,压缩效果反而更好。

3.2 ECharts 手动按需引入的完整代码

这一步是全场收益最大的一块。ECharts 从全量引入改成按需引入,体积直接少了 700 多 KB。

全量引入的写法很常见,很多人会这样:

import * as echarts from 'echarts';

这样的写法会打包整个 echarts 包。按需引入则要分两步:先引入核心模块,再注册需要使用的图表和组件。

我在项目里建了一个utils/echarts.js,统一处理按需注册:

// 引入 echarts 核心模块 import * as echarts from 'echarts/core'; // 按需引入图表类型 import { LineChart, BarChart, PieChart } from 'echarts/charts'; // 按需引入组件 import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, DataZoomComponent } from 'echarts/components'; // 引入 Canvas 渲染器 import { CanvasRenderer } from 'echarts/renderers'; // 注册必须的模块 echarts.use([ LineChart, BarChart, PieChart, TitleComponent, TooltipComponent, GridComponent, LegendComponent, DataZoomComponent, CanvasRenderer ]); export default echarts;

之后在每个业务页面里,不再从echarts引入,而是从utils/echarts.js引入:

import echarts from '@/utils/echarts';

这样 ECharts 的体积会从 1094KB 降到大概 300KB 左右。如果你项目中还用到了地图(Geo 或 MapChart),记得再引入对应的地图数据,但注意地图 JSON 数据本身是纯数据文件,体积可能非常大,强烈建议把地图数据也单独拆出来做异步加载,不要和业务代码搅在一起。

这里有一个真实的坑要说明:按需引入后,ECharts 的 tooltip 里如果要使用formatter回调函数,并且函数里引用了echarts命名空间下的一些方法,比如echarts.format.addCommas,那就需要额外引入对应的工具方法。像这样:

import { format } from 'echarts/core';

这种细节往往在开发环境没问题,但在切换成按需引入后突然报Cannot read properties of undefined。排查方式是打开控制台看具体报错点,再用全局搜索在代码里定位到echarts.的调用位置,逐个确认是否在按需引入白名单里。

3.3 构建配置:manualChunks 拆包与 gzip 预压缩

路由懒加载和按需引入解决的是“代码量”的问题,但还有一个“缓存效率”的问题:如果把 vue、vue-router、pinia、axios 这些不怎么变化的第三方库塞到业务 bundle 里,那么每次业务代码发版后,用户都要重新下载整个大文件。所以最好是把它们拆成独立的 vendor chunk,设置长缓存。

Vite 自带了一些拆包策略,但默认行为可能不完全符合预期。我习惯在构建配置里自定义manualChunks

export default defineConfig({ build: { rollupOptions: { output: { manualChunks(id) { if (id.includes('node_modules')) { if (id.includes('vue') || id.includes('pinia') || id.includes('vue-router')) { return 'vendor-vue'; } if (id.includes('axios') || id.includes('dayjs')) { return 'vendor-utils'; } if (id.includes('echarts')) { return 'vendor-echarts'; } if (id.includes('element-plus')) { return 'vendor-element'; } return 'vendor'; } } } } } });

这样构建产物里会出现vendor-vuevendor-utilsvendor-echartsvendor-element这样的 chunk,每个 chunk 内部都是比较稳定的依赖集合。用户第二次访问时,这些 chunk 可以命中浏览器强缓存,只有业务代码发生变化时才重新拉取。

另外一步:gzip。Vite 构建默认不会给你生成 .gz 文件,需要装插件。

npm install -D vite-plugin-compression

配置:

import viteCompression from 'vite-plugin-compression'; export default defineConfig({ plugins: [ vue(), viteCompression({ verbose: true, disable: false, threshold: 10240, algorithm: 'gzip', ext: '.gz' }) ] });

threshold: 10240表示只有大于 10KB 的文件才会被压缩。这个值可以根据自己的实际产物调整,压缩太多小文件收益有限,反而增加构建时间。

生成 .gz 文件之后,还要确认服务器端是否开启了 gzip 或 brotli。如果你用的是 Nginx,且没有配置gzip_static on;,那服务器会实时压缩再返回,虽然也能生效,但会消耗 CPU。比较推荐的做法是让 Nginx 开启gzip_static on;,这样它会优先读取静态的 .gz 文件,直接发送给客户端,CPU 开销最低。

gzip on; gzip_static on; gzip_min_length 1k; gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;

3.4 CDN 映射与 externals 配置完整示例

如果你决定走 CDN 这条路,那配置方式要严谨一些。我把当时用的 CDN 版配置拿出来做个演示。

先说思路:把 vue、vue-router、pinia、echarts 这四个体积大户全部 externals 掉,业务代码里正常 import,构建时 Rollup 不打包它们,而是把 import 映射成window上的全局变量。运行时通过 index.html 里的<script>加载 CDN 文件,确保全局变量已经存在。

vite.config.js 核心配置:

export default defineConfig({ build: { rollupOptions: { external: ['vue', 'vue-router', 'pinia', 'echarts'], output: { globals: { vue: 'Vue', 'vue-router': 'VueRouter', pinia: 'Pinia', echarts: 'echarts' } } } }, define: { // 避免开发环境报错 __VUE_PROD_DEVTOOLS__: false } });

index.html 中手动添加:

<!DOCTYPE html> <html lang="zh-CN"> <head> <script src="https://unpkg.com/vue@3.2.47/dist/vue.global.prod.js"></script> <script src="https://unpkg.com/vue-router@4.1.6/dist/vue-router.global.prod.js"></script> <script src="https://unpkg.com/pinia@2.0.36/dist/pinia.iife.prod.js"></script> <script src="https://unpkg.com/echarts@5.4.3/dist/echarts.min.js"></script> </head> <body> <div id="app"></div> <script type="module" src="/src/main.js"></script> </body> </html>

使用 CDN 模式时,需要注意pinia的全局包名是Piniavue-router的全局包名是VueRouter。globals 里写错会导致运行时找不到对象,控制台会报XXX is not defined。还有个坑是 echarts,如果你在业务代码里用了echarts/core的按需引入,那 CDN 方式下 externals 配置就得拆开细粒度处理,否则打包后会报echarts/core is not defined。当时我为了省事,CDN 方式下干脆直接把 echarts 指向echarts全量包,只在按需引入方案里才用核心模块。

CDN 方案做完后,构建产物体积很夸张。把所有第三方库都排除后,整个 JS 只有大概 250KB 未压缩、80KB 左右 gzip。当然,代价是首屏多加载了几个外部 script,网络请求数会增加。至于这个 trade-off 值不值,取决于你的部署环境、CDN 稳定性和团队对第三方资源的掌控力。我的结论是:对公网项目,CDN 是很成熟的手段;对私网或对稳定性要求极高的系统,建议别依赖公共 CDN,改成本地 vendor 文件更稳妥。

4. 常见问题与排查技巧实录

4.1 改了懒加载后按预期生效,但首屏变快不明显

这种情况一般有两个原因。第一,某些页面体积特别大,比如数据报表页本身就带了一堆 ECharts 图表,整个异步 chunk 的体积可能超过 300KB。这种情况下,路由懒加载只是把压力从首屏挪到了点击路由的那一瞬间,用户在该页面上的等待时间并没有减少。解决办法是继续对这个页面做组件级懒加载或数据懒加载,比如图表组件在进入视口时才渲染。

第二,首页本身把很多模块同步 import 了。比如很多新手喜欢在根组件 layout 里一次性 import 所有子页面组件,这样懒加载就失效了。检查一下首页相关组件里有没有import UserManage from这种同步写法,如果你在 setup 里同时 import 了 UserManage 和 DataReport,而它们本身是懒加载组件,这里不会报错,但会让它们被同时拉取。排查方式是看浏览器 Network 面板里的 JS 请求,如果一进入首页就有多个业务 chunk 同时加载,那就是某个同步链路把异步组件引用了。

4.2 按需引入 ECharts 后,页面图表直接报错

按需引入之后最容易遇到的就是Component series.line not exists. Load it first.这类错误。

这通常意味着LineChart没有被注册。但如果你确实注册了,还会报这个错,那就要检查是不是之前某个文件里用了echarts.init然后传入了'line'字符串,但注册时用的是LineChart的类。写法上echarts.use([LineChart])是正确的,不需要额外做映射。

还有一类问题出现在 ECharts 5 中,tooltipformatter里用了paramsmarkeraxisValueLabel,这些功能都是挂在 TooltipComponent 上的,如果你忘了TooltipComponent,页面会直接白屏。建议所有使用 ECharts 的页面至少在utils/echarts.js里把常用组件全部注册好,不要只注册图表类型而漏了组件类型。

4.3 CDN 引入了,但打包产物里还是能看到完整依赖

这种问题的根因在于 external 配置没有生效。最常见的情况是:业务代码里 import 的路径和 external 里声明的模块名不一致。比如:

import { createRouter } from 'vue-router'

如果 external 里写的是'VueRouter',大小写对不上、路径对不上,就不会被识别。

还有一种情况是用路径导入的写法:

import { ElMessage } from 'element-plus/lib/components/message'

这种带路径的导入,Rollup 不会把它和element-plus这个模块关联起来,externals 无法命中。尽量不要写深层路径导入。

排查方法很简单:构建完之后,在 dist 产物里搜vue.global或者echarts.min相关内容,如果看到了,说明 CDN 文件内容已经被打进去了;如果看不到,说明 external 生效。另外,也可以看 analyze.html 里有没有这些依赖的色块。

4.4 gzip 文件生成了,但线上体积没降

让我碰到的比较典型的坑是:vite-plugin-compression生成了 .gz 文件,但 Nginx 没有开启gzip_static,服务器实时压缩的结果跟预压缩内容不一致。这中间最让人迷惑的是,浏览器开发者工具里的 Transfer-Encoding 显示gzip,体积看起来还是没变。原因是实时压缩时 Nginx 可能没有启用 gzip,或者是网络面板显示的是原始大小没走预压缩。

解决办法是在 Nginx 里加上:

gzip_static on; gzip_vary on;

然后保存、重新加载配置:

nginx -t nginx -s reload

重新部署后再看响应头里的Content-Encoding是否为 gzip,以及响应头里的ETag是否带上了.gz后缀。如果你用的是其他 Web 服务器,比如 Caddy 或 Tomcat,也需要各自确认静态文件模块是否支持预压缩文件优先返回。

4.5 Vue Router 懒加载与 history 模式部署的配合问题

这个坑和体积优化本身无关,但如果你刚好在优化期间改用 history 路由,就会遇到。生产环境下如果使用createWebHistory(),刷新某个子路由页面时,Nginx 如果没有做 fallback,会直接 404。

处理方式是在 Nginx 的 server 配置里加上:

location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; }

同时,如果你的应用部署在子路径下,比如https://example.com/admin,那 Vite 的base也要相应改掉。这个base配置,很多人容易忽略。它不只是影响静态资源路径,还影响 Vite 构建时对 script 标签、css 标签的引用路径。不配置的话,部署到子路径后会出现资源 404。

export default defineConfig({ base: process.env.NODE_ENV === 'production' ? '/admin/' : '/' });

4.6 问题排查速查表

现象可能原因解决方案
路由懒加载后首屏体积没降首页中同步引用了异步组件检查 layout 和首页组件,把异步组件改成动态 import 引用
ECharts 报 series 不存在未注册对应图表类型在 utils 里调用echarts.use([LineChart, BarChart, PieChart])
externals 不生效,库被重复打包import 路径和 externals 模块名不一致统一用包名导入,不要用深层路径
构建产物里有大量 .gz,但线上未压缩服务器未开启 gzip_static配置 Nginx 的gzip_static on;
页面刷新 404history 路由 + 服务器未 fallbackNginx 配置try_files $uri $uri/ /index.html;
部署到子路径后资源 404Vite base 未配置设置base为子路径
Element Plus 按需引入后样式丢失样式文件未按需引入引入对应组件的 style/css 文件

5. 优化过程的最终数据对比与经验总结

这里贴一下我做完整套优化之后,最终构建产物的对比数据:

优化项优化前优化后
首屏 JS 体积(未压缩)2798 KB517 KB
首屏 JS 体积(gzip)812 KB145 KB
构建产物 chunk 数18
首屏 HTTP 请求数1 个 JS4 个 JS(其中 2 个命中强缓存)
总构建时间约 25s约 18s

这个 500K 的数字,最开始我以为是按需引入 Element Plus 带来的收益最大,但实际分析后发现,ECharts 按需引入的收益贡献占了一半还要多。Element Plus 按需引入大概贡献了 200KB,路由懒加载贡献了首屏 1.8M 的削减。拆包和 gzip 更多是提升了传输效率和缓存效率。

说几个实操后的心得体会。第一,体积优化不要一次性把方案全上。每做一步就构建一次,记录一下产物数据变化,这样出了问题能快速定位。我就是先做路由懒加载,确认没问题,再做 ECharts 按需引入,最后才动构建配置。第二,所有优化措施都要过一遍“可真机验证”的流程,特别是改了 CDN 或 externals 之后,一定要在无痕模式里完整走一遍核心业务流程,防止全局变量被错误引用导致白屏。第三,优化之后最好把analyze.html保存下来,作为后续版本对比的基线。以后每次加依赖、加页面,都能快速判断体积变化是否合理。

最后再分享一个小技巧。很多人不知道,Vite 构建时支持--report这样的模式,也可以直接用vite build --watch监听构建,配合 visualizer 插件,每次构建后自动刷新分析页面。我自己喜欢把这个流程写进 package.json 的 script 里,比如:

{ "scripts": { "build": "vite build", "build:analyze": "vite build && open analyze.html" } }

这样每次想检查产物体积,一条命令就行,不用临时去改配置文件。这套流程稳定以后,我在后续几个项目里都复用了同样的思路,效果都很稳定。如果你现在正被 Vite 打包体积问题困扰,照着这份方案走一遍,应该能把首屏体积实实在在地降下来。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 19:53:51

FlowingLight:基于Canvas的数据大屏流光动效插件设计与接入

做可视化数据大屏这几年&#xff0c;我最大的感受是&#xff1a;图表好写&#xff0c;动效难调。尤其是领导或客户走近大屏的那一刻&#xff0c;如果页面全是干巴巴的柱状图和折线图&#xff0c;哪怕数据再准确&#xff0c;观感上总觉得少了一口气。后来我在自己的大屏项目里沉…

作者头像 李华
网站建设 2026/9/14 19:53:48

mongoose-android-x86_64 编译报 PIE?TaoToken 这样让 Codex 改 examples.mk

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

作者头像 李华
网站建设 2026/9/14 19:53:43

Python编程实战:11个经典题目解析与技巧

1. Python编程实战的价值与意义Python作为当下最流行的编程语言之一&#xff0c;其简洁优雅的语法和强大的生态系统吸引了无数开发者。但很多初学者在学习基础语法后&#xff0c;常常陷入"知道语法却写不出代码"的困境。这正是编程实战练习的价值所在——通过解决具体…

作者头像 李华
网站建设 2026/9/14 19:52:26

综合能源系统低碳优化:P2G与碳捕集技术应用

1. 项目背景与研究意义在"双碳"目标背景下&#xff0c;综合能源系统(Integrated Energy System, IES)的低碳化运行已成为能源领域的研究热点。热电联供(Combined Heat and Power, CHP)系统作为IES的核心组成部分&#xff0c;其传统运行模式往往以经济性为单一优化目标…

作者头像 李华
网站建设 2026/9/14 19:51:54

银行网点数字化转型:布局优化与效能提升策略

1. 银行物理网点布局现状分析 银行物理网点作为传统金融服务的重要载体&#xff0c;在当前数字化浪潮中正经历着前所未有的转型压力。根据最新行业数据显示&#xff0c;2022年全国银行网点总量约为22.8万个&#xff0c;较2019年峰值下降约5.3%。这种收缩趋势在北上广深等一线城…

作者头像 李华
网站建设 2026/9/14 19:51:23

PLC在电梯控制系统中的核心应用与设计

1. 电梯控制系统的基本组成与工作原理电梯作为现代建筑中不可或缺的垂直运输工具&#xff0c;其控制系统设计直接关系到运行的安全性和效率。一套完整的电梯系统主要由六大核心部件构成&#xff1a;曳引系统&#xff1a;这是电梯的动力来源&#xff0c;由电动机、减速箱、制动器…

作者头像 李华