☰
JeecgBoot前端从Vite2升级到Vite5:冷启动与构建耗时减半的实战指南
2026/9/30 13:02:05 网站建设 项目流程

如果你还在 JeecgBoot 老版本上做低代码平台二次开发,大概率见过这样的场景:早上到公司打开终端执行npm run dev,然后去接杯水、看看消息,回来 Vite 才完成依赖预构建。更有甚者,改了一个公共组件的代码,页面白屏一两秒才算缓过来。这不是个例,JeecgBoot 这类后台管理系统的前端依赖动辄几百个包,Vite2 在冷启动和依赖优化上的疲态非常明显。我手上这套项目从 Vite2 一路升到 Vite5,整个过程踩了不少坑,也实打实拿到了构建耗时减半、页面秒开的效果。这篇文章不聊原理书上的车轱辘话,只讲我实际怎么改的、遇到了什么问题、每步为什么这么做。适合正在维护 JeecgBoot 或类似 Vue3 低代码平台前端的同学参考,也适合准备把旧构建链升级到 Vite5 的人避坑。

1. 升级前把性能账算清楚:JeecgBoot前端慢在哪

1.1 慢的根源不是“代码乱”,而是依赖规模和构建链路

JeecgBoot 的前端不是普通的管理后台,它默认集成了非常多东西:ant-design-vue 组件库、vxe-table 表格、echarts 图表、wangEditor 富文本、Online 表单和 Online 报表的动态渲染、流程设计器等等。这些依赖在 npm 里都是体积很大的包。Vite2 时代,冷启动要做依赖预构建,把所有依赖预先用 esbuild 打包一遍,几百个依赖塞进去,再快的机器也得十几秒。项目越大,这个时间越接近线性上涨。等它预构建完,第一次页面加载还要重新请求依赖,浏览器里经常能看到一个长时间的白屏。

另一个痛点是人多的时候:上午大家同时开机,dev server 第一次响应奇慢,一会儿就提示optimized dependencies changed. reloading,然后整个页面刷新。热更新理论上很快,但 Vite2 面对这种庞大依赖图,经常退化成全量刷新。改一个按钮的文字,整个页面重新加载,开发节奏直接被打断。

1.2 Vite5 在底层到底改了什么

这里只说几个和性能直接相关的点,理论不展开太多:

  • 依赖预构建效率更高。Vite5 底层仍是 esbuild 做预构建,但它对依赖扫描和缓存的策略做了很多修正,不会没事就把整包依赖重扫一遍。实际感受就是冷启动后不再频繁出现“reloading”白屏。
  • Rollup 4 接管生产构建。生产构建部分 Vite5 用了 Rollup4,tree-shaking、模块合并、缓存方面都比旧版强。低代码平台这种大量动态路由、import.meta.glob 的代码结构,收益尤其明显。
  • 默认浏览器目标进步。Vite5 把默认构建目标从“广泛兼容”调整为现代浏览器基线(大致是 Chrome 87+、Edge 88+ 这一档)。这意味着生产包不用再为远古浏览器做大量转译和 polyfill,产物体积自然下来。
  • 包体更小、热更新路径更短,这是开发体验上最直观的飞跃。

用户视角就是:同样的项目代码,什么都不优化,从 Vite2 升到 Vite5,冷启动从几十秒降到个位数,构建耗时减掉一半以上,首屏资源也能小一截。

1.3 预期收益和风险清单

在动手之前,我给团队拉了一张简单的收益/风险表:

维度收益预期风险点
冷启动从 30s+ 降到 10s 内依赖预构建缓存失效需容忍首次启动
生产构建耗时减半以上部分旧插件不兼容,可能报错
开发体验HMR 更跟手,不易全量刷新需要 Node 18 及以上环境
产物性能gzip 体积变小,首屏更快老的浏览器兼容目标需重新定义

这个表很关键,它决定了我们要不要在这个迭代里动构建链。最后我们决定升,因为收益足够大,风险可回滚。顺便说一句,网上经常有人问 JeecgBoot 和若依哪个好,我不好直接下结论,但至少在前端构建链上,JeecgBoot 从 Vite2 升到 Vite5 的动作是实打实的,对长期维护者来说这是加分项。

2. 升级前的准备清单:版本基线、依赖对齐与回滚方案

2.1 先摸清家底:当前版本和环境

不要一上来就动 package.json。我习惯先执行:

node -v npm -v grep -E '"vite"|"vue"|"@vitejs/plugin-vue"' package.json

我们项目的基线是:Node 14.21.3、npm 6.14.18、Vite 2.9.16、Vue 3.2.45、ant-design-vue 3.2.20。这基本就是 JeecgBoot 3.5.x 时代的前端标配,Vite2 跑起来已经吃力了。

这一步的价值在于:后面所有报错,都能对照基线判断是不是“升级引入的”。如果没有这个基线,报一个错你都不知道是本来就有,还是版本升级造成的,排查效率会低很多。

2.2 制定升级矩阵:一次只升一条链路

很多项目死在“顺手把 UI 库也升了”。我强烈建议,构建链升级是构建链升级,UI 库升级是 UI 库升级,分两个迭代做。这次我们的矩阵很简单:

依赖升级前升级后说明
node14.21.318.20.4 LTSVite5 硬性要求,推荐 LTS
vite2.9.165.2.12核心升级
@vitejs/plugin-vue2.3.45.0.5必须同步升
@vitejs/plugin-legacy不启用5.4.2视浏览器兼容需求决定
vue3.2.453.4.31建议同步,兼容 Vite5
ant-design-vue3.2.20维持 3.x与本次升级解耦
样式插件vite-plugin-style-importunplugin 方案Vite5 下旧插件不可靠

当时刚好 Vite5 是稳定主流,Vite6 刚出但生态插件适配还参差不齐,所以锁定 5.x 是稳妥选择。如果你在阅读时已经到 Vite7 时代,同理选一个生态内反馈最稳的当前主流版本就行。关键不是版本号最新,而是团队能不能稳定跑起来。

2.3 备份、回滚和基线数据

改动之前,我做三件事:

  • 从主线切一个feature/vite5-upgrade分支,整个前端目录单独提交;
  • 保留旧package-lock.json的 git 记录,如果升级失败可以随时 reset 回来;
  • 在升级前先测一轮基线数据:冷启动耗时、生产构建耗时、dist 体积、首页 FCP。没有基线数据,后面说“性能提升多少”都是拍脑袋。

这一步千万别省。我见过太多团队升级完说“变快了”,结果一问快多少,谁也说不出来。特别是低代码平台这种大项目,优化效果往往不是线性的,没有前后数据对比,很难向团队交代这次升级到底值不值。

3. 核心迁移动作:依赖升级与 vite.config 改造

3.1 package.json 和依赖安装

改动后的关键片段:

{ "engines": { "node": ">=18.0.0", "npm": ">=9.0.0" }, "scripts": { "dev": "vite", "build:prod": "vite build --mode production", "preview": "vite preview" }, "dependencies": { "vue": "^3.4.31", "ant-design-vue": "3.2.20" }, "devDependencies": { "@vitejs/plugin-legacy": "^5.4.2", "@vitejs/plugin-vue": "^5.0.5", "unplugin-auto-import": "^0.17.6", "unplugin-vue-components": "^0.27.2", "vite": "^5.2.12" } }

安装前先把 Node 切到 18。用 nvm 最省事:

nvm install 18.20.4 nvm use 18.20.4 node -v rm -rf node_modules package-lock.json npm install

这里有个细节:Vite5 及大部分新版本依赖都是 ESM-only,旧 lockfile 在 npm6 下生成后,npm9 去安装会有格式冲突,所以直接删掉 package-lock 重新生成,能省一堆莫名其妙的 peer 依赖报错。

3.2 vite.config 的改造点

这是我最终收敛下来的配置骨架,几个重点都加了注释:

import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers' export default defineConfig({ plugins: [ vue(), AutoImport({ imports: ['vue', 'vue-router', 'pinia'], dts: 'src/auto-imports.d.ts' }), Components({ resolvers: [AntDesignVueResolver()], dts: 'src/components.d.ts' }) ], resolve: { alias: { '@': '/src' } }, server: { host: '0.0.0.0', port: 3000, proxy: { '/jeecg-boot': { target: 'http://localhost:8080', changeOrigin: true } } }, optimizeDeps: { include: ['ant-design-vue', 'axios', 'vxe-table', 'echarts', 'wangeditor'] }, build: { chunkSizeWarningLimit: 1500, rollupOptions: { output: { manualChunks: { antd: ['ant-design-vue'], vxetable: ['vxe-table'], echarts: ['echarts'], editor: ['wangeditor'], vendor: ['vue', 'vue-router', 'pinia', 'axios'] } } } } })

几个容易踩的配置项:

  • server.proxy配置不用动,低代码平台前端调后端接口基本全靠/jeecg-boot这个代理前缀,改坏了登录都会挂。
  • 如果你之前用了define传大段字符串,Vite5 对这个字段的解析更严格。我的建议是能不用就不用,环境变量走import.meta.env。
  • build.target:Vite5 默认值比较激进(现代浏览器)。JeecgBoot 用户里可能还有大量老款办公浏览器,如果确认要兼容 Chrome 80 这类,就显式写build.target: 'es2015',或者启用@vitejs/plugin-legacy。我们最终选择保留 legacy 做降级,代价是产物会多一些 polyfill,但首屏关键包不受影响。
  • chunkSizeWarningLimit调大不是掩盖问题,是为了把 manualChunks 拆包后的 warning 收敛,别让 CI 刷屏。

3.3 动态渲染组件和 import.meta.glob

低代码平台升级后最怕的就是“某个由元数据配置生成的页面白屏”。JeecgBoot 的 Online 表单、Online 报表,很多视图组件是运行时通过 glob 动态加载的。Vite5 对import.meta.glob语义和 Vite2 基本一致,但这里我建议做一次显式收敛:

// 原来可能散在各处的动态加载 const modules = import.meta.glob('../views/**/*.vue') // 升级后我更推荐在核心渲染处维护一份显式列表 const onlineViewModules = import.meta.glob('../views/online/**/*.vue')

也就是把动态导入范围从“所有 views”缩小到“在线表单相关目录”。好处很明显:glob 范围小了,构建时的模块图更小,热更新不必要的依赖链路更短,性能又提升一截。同时还能避免因为路径大小写不一致导致的生产构建找不到模块。

这一步不会立刻体现在某个单次构建数据里,但它决定了升级后大页面还有没有可能偶发白屏。

3.4 manualChunks 拆包

这个配置直接关系首屏加载。JeecgBoot 这种项目,如果不拆包,ant-design-vue、vxe-table、echarts 会全部塞进一个超大 vendor,首屏解析卡死。升级到 Vite5 后 Rollup4 对 chunk 合并策略更智能,但我还是坚持手动拆。

拆包的核心思路:

  • 常用且稳定的库单独成 chunk,比如 antd、vxe-table、echarts;
  • Vue 全家桶放 vendor,保证框架代码的强缓存;
  • 业务代码和第三方库隔离,业务发布更新时不会让用户重新下载大 vendor。

实测下来,拆包后首屏请求数量多一点,但每个包都小得多,浏览器并发加载后整体白屏时间更短。

4. 升级过程里最折磨人的几类坑

4.1 Node 版本不够,vite 直接起不来

最开始的报错是这样的:

Error: Cannot find module 'node:stream/web' Require of node:stream/web is not supported by Node 14.

这就是 Vite5 要求 Node 18+ 最直白的体现。解决办法就是前面说的 nvm 切换。这里提醒两点:

  • 让团队都装.nvmrc,文件里写18.20.4,避免有人用不同版本;
  • CI 和 Docker 镜像也要同步改,否则本地跑得欢,发布机直接挂。

4.2 老样式插件 vite-plugin-style-import 的兼容问题

项目早期的 JeecgBoot 前端都是靠vite-plugin-style-import按需引入 antd 样式。这个插件更新已经滞后,在 Vite5 下经常出现:

  • 启动不报错,但按钮、表格样式全丢;
  • 运行时报某个内部方法 undefined。

原因很简单:插件内部依赖的 API 在 Vite5 中已经调整,它没有跟进。解决不是修它,而是换官方推荐的unplugin-vue-components+unplugin-auto-import组合。上面配置里的AntDesignVueResolver就是干这个的,按需引入组件和样式更干净。注意换完后要删掉之前手动 import 的全量样式文件,比如import 'ant-design-vue/dist/antd.css'这类,否则样式重复,部分组件会出现覆盖问题。

4.3 JavaScript heap out of memory

升级后第一次执行生产构建,我的项目跑到了JavaScript heap out of memory,直接崩。这是因为 Rollup4 的并发打包更激进,大项目占用堆内存更多。加大 Node 内存即可:

NODE_OPTIONS=--max-old-space-size=4096 vite build --mode production

如果是在 Jenkins 里跑,记得在构建脚本里加上这行。这个问题在 Vite2 时代不常见,升级后反而容易冒出来,遇到别慌。

4.4 动态组件找不到,在线页面白屏

这是低代码平台特有的坑。我们升级后在“流程中心”打开一个流程配置页,直接白屏,控制台报:

Failed to fetch dynamically imported module: /src/views/flow/xxx.vue

排查链路由浅到深:

  • 先看路由配置里的 component 路径对不对;
  • 再排查是否有目录改名/大小写变化;
  • 最后是动态 import 路径的 glob 匹配是否覆盖到该目录。

最终发现是流程设计器某个组件用了import.meta.glob匹配了../views/**/process/*.vue,但新分支下目录名从process改成了bpm,glob 没匹配到。这不是 Vite5 的问题,是升级过程中顺手整理目录造成的副作用。经验就是:升级构建工具时,尽量不要同时重构目录结构,否则出了问题很难定位是构建链还是代码层的锅。

5. 实测对比:冷启动、构建耗时与首屏指标

5.1 冷启动对比

测试方法:清空node_modules/.vite缓存,执行npm run dev,从命令开始到终端输出 Local 地址为止计时。

指标Vite2Vite5
冷启动时间约 35s约 8s
首次依赖预构建经常要两次 reload一次到位
保存代码后的 HMR 感知2s 左右,重页面全刷500ms 内,局部更新

冷启动对 JeecgBoot 的价值很大,因为后台项目要登录、要进菜单,开发调试时等启动真的非常磨人。这个数字已经足够说服团队动手。

5.2 生产构建与产物体积

指标Vite2Vite5
生产构建耗时约 3 分钟约 1 分钟
dist 目录总大小约 68MB约 51MB
首屏 gzip 后资源约 3.4MB约 2.1MB

这些数字来自这台 16G 内存的 MacBook,机械硬盘和服务器上效果会不一样,但趋势是一致的:Rollup4 的 tree-shaking 和现代浏览器目标确实能砍掉不少冗余。

5.3 首屏指标

我在局域网部署环境用 Chrome DevTools 测了登录页和首页(清缓存、不额外做网络限速):

  • FCP:从约 2.1s 降到约 1.2s;
  • LCP:从约 2.6s 降到约 1.5s;
  • 首屏请求体积小了一截,登录验证接口的等待不再是瓶颈。

首屏变快不全是 Vite5 的功劳,manualChunks 拆包也贡献很大。但如果没有 Vite5 的默认 target 优化和 Rollup4 的产物收敛,光靠拆包不会降这么多。所以这步就是标题里说的“性能飞跃的关键一步”。

6. 收尾验证与低代码平台特有回归点

6.1 功能回归清单

构建链升级完,最忌讳的就是只测一个登录页就宣告完成。低代码平台至少要过一遍这些场景:

  • 登录、退出、菜单权限动态加载;
  • Online 表单的列表查询、表单新增、表单编辑、表单删除;
  • Online 表单设计器的打开和保存;
  • Online 报表的 SQL 渲染和导出;
  • 流程中心(flowable)的流程定义、流程设计器、待办列表;
  • 系统监控、系统日志、定时任务的页面;
  • 主题定制和 less 变量是否还生效;
  • 低代码平台调用外部 API 的场景,比如流程回调、Online 表单数据源配置。

其中 Online 表单和流程中心是我特意标红的,因为这类页面强依赖动态组件加载,最容易受 glob 和按需引入影响。

如果你生产库是达梦这类国产数据库,前端升级本身不影响数据库连接,但建议后端接口一起联调一遍,确保列表分页、字典翻译等接口没有因为前后端版本交替出现联调遗漏。

6.2 CI/CD 同步适配

不要忘掉发布链路:

  • Dockerfile 里的node:14镜像改成node:18-alpine或更合适的 LTS 镜像;
  • CI 脚本里 npm 版本同步升到 9+;
  • 构建命令加上NODE_OPTIONS=--max-old-space-size=4096,免得在服务器上内存不足;
  • package.json 里加上engines字段,让环境不匹配的人第一时间看到提示。

我把这些都放进了团队的发布检查单,避免“代码能跑,但一上构建机就挂”的尴尬。

6.3 给团队沉淀的经验

升级完不是终点,我建议把这次过程整理成一篇团队内部的升级笔记,至少包含:

  • 升级前后的性能基线数据;
  • 常见报错速查表(Node 版本、样式插件、内存溢出、动态组件白屏);
  • 约定的 Node 版本和 .nvmrc 位置;
  • 后续升级到新 Vite 版本时的操作顺序:先看 breaking changes、再只动构建链、最后动业务依赖。

这套沉淀比单纯升版本更有价值,下次再做类似升级,团队能省一个下午。

这次 Vite5 升级给我最大的体会是:别迷信“升级是小事”,也别被“兼容性一堆坑”吓住。真正值钱的是动手前那半个小时的基线摸底,它把后面所有报错都收敛到了可解释的范围,也让最后的数据对比有说服力。JeecgBoot 这种重前端低代码平台,构建链越顺,团队生产力释放得越明显。如果你们也还困在 Vite2 的冷启动里,建议找个小版本迭代窗口,把这事提上日程,早升早省心。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询