☰
Webpack迁到Vite第七节(四):全家桶移除 — 保留项、脚本与数据收尾
2026/10/18 7:26:33 网站建设 项目流程

Webpack迁到Vite第七节(四):全家桶移除 — 保留项、脚本与数据收尾

本篇定位:依赖从 48 个精简到 40 个(共移除 17 个、新增 9 个,净减 8 个)——留下的每个都有留下的理由。本篇梳理保留原因、脚本命令的对应关系、.eslintrc.js清理了什么,以及最终的依赖数量、构建时间、配置文件体积的对比数据。

思维导图

保留项、脚本与数据收尾 ├── 1.3 保留的依赖包(23 个)— 为什么这些包没有被移除 │ ├── less + autoprefixer(Less 编译器 + CSS 前缀) │ ├── browserslist(共享给 autoprefixer + plugin-legacy) │ ├── vue-template-compiler(仅 @vue/test-utils 需要) │ └── eslint + 插件链 + 测试工具链 ├── 1.4 脚本命令更新 │ ├── 原则:核心脚本名不变(serve/build/lint) │ ├── serve / serve:params / build / build:params / analyze │ ├── lint / lint:fix(独立于构建工具) │ └── 测试脚本(vitest + Playwright,迁移前已配置) ├── 1.5 .eslintrc.js 清理 │ ├── import/resolver webpack → custom-alias │ └── import/extensions: off(Vue 生态惯例) ├── 1.6 依赖数量对比 │ ├── 48 → 40(净减 8 个包) │ ├── 配置文件:332 → 200 行(约 -40%) │ ├── 构建时间:3m31s → 37s(-82%) │ └── npm install:70s → 15s(-79%) └── 总结

1.3 保留的依赖包(23 个)

为什么这些包被保留

包名保留原因详细说明
vite新的构建工具替代 Webpack + @vue/cli-service
@vitejs/plugin-vue2Vue 2 SFC 编译Vite 需要这个插件来解析.vue文件
@vitejs/plugin-legacyES5 降级双构建为旧浏览器额外产出nomodule传统产物(详见第七节(五))
vite-plugin-compression.gz 预压缩替代compression-webpack-plugin
rollup-plugin-visualizer构建分析替代webpack-bundle-analyzer
vitest单元测试独立测试框架,与构建工具无关
@vitest/coverage-v8测试覆盖率vitest 的覆盖率插件
@playwright/testE2E 测试独立测试框架,与构建工具无关
@vue/test-utilsVue 组件测试测试 Vue 组件的工具库
jsdom测试 DOM 环境vitest 的 DOM 模拟环境
eslint代码检查独立于构建工具
eslint-plugin-vueVue 规则ESLint 的 Vue 语法规则
eslint-plugin-importImport 规则ESLint 的 import 规则
@vue/eslint-config-airbnbAirbnb 规则预设ESLint 规则集
eslint-import-resolver-custom-aliasESLint import 别名解析替代eslint-import-resolver-webpack,解析@/别名和.vue扩展名
lessCSS 预处理器编译器本身,Vite 不内置
autoprefixerCSS 浏览器前缀Vite 内置 PostCSS,但 autoprefixer 需要单独安装
vue-template-compiler模板编译vitest 需要(Vite 构建时由 @vitejs/plugin-vue2 处理)
core-js保留(^3.38.1 → ^3.50.0 升级)迁移前已有,迁移后升级;供 plugin-legacy 传统构建注入 polyfill
regenerator-runtimeasync/await 运行时配合 @vitejs/plugin-legacy 为传统构建提供 regenerator 运行时
terser传统产物压缩plugin-legacy 产出的 legacy chunk 由 terser 压缩(esbuild 不做 ES5 降级)
ioredis测试 Redis 查询测试辅助工具,与构建工具无关
mysql2测试数据库查询测试辅助工具,与构建工具无关

关键保留项说明

less+autoprefixer为什么保留?

less:Vite 内置了 Less 集成层(调用的胶水代码),但不是"编译器"本身。less包是 Less 语言的编译器,负责把 Less 语法解析并编译为 CSS。Vite 没有重写这个编译器。

autoprefixer:完整的工具链分工如下:

Vite(构建工具) └── 内置 PostCSS 集成(自动检测 postcss.config.js) └── postcss.config.js → plugins: { autoprefixer: {} } └── autoprefixer(npm 包,需单独安装) └── 读取 browserslist 配置,确定要加哪些 CSS 前缀

Vite 内置了 PostCSS 的"集成管道"——自动检测项目中的postcss.config.js,把它接入构建流程。但 PostCSS 的具体插件(如autoprefixer)需要自己安装——Vite 只负责管道,不打包插件。

browserslist为什么保留?

browserslist从package.json中保留,原因是它仍然是两个独立消费方的共享配置:

消费者用途是否还在用
Babel(Webpack 时代)@babel/preset-env根据它确定需要降级哪些 ES6+ 语法❌ 已移除
autoprefixer根据它确定要为哪些浏览器添加 CSS 前缀(-webkit-等)✅ 仍在使用
@vitejs/plugin-legacyH5 签署端 ES5 降级,plugin-legacy依赖它确定传统构建的转译目标✅ 已实施(详见第七节(五))

Babel 移除不意味着browserslist应该删除——它从来不是 Babel 独占的配置。autoprefixer通过postcss.config.js接入 Vite 的 PostCSS 管线,读取browserslist生成 CSS 前缀。@vitejs/plugin-legacy同样依赖它确定传统构建的转译目标。

完整链路:

postcss.config.js → autoprefixer → browserslist → CSS 前缀 ← 现在 @vitejs/plugin-legacy → Babel → browserslist → ES5 语法降级 ← 已实施(见第七节(五))

package.json中的最终配置(与 Webpack 时期一致):

"browserslist":["> 1%","last 2 versions","not ie <= 10"]

不删除的另一个原因是可控性:browserslist默认值会随 npm 包版本升级而变化,显式声明锁定项目意图,避免某天默认值改变导致构建产物意外变化。

vue-template-compiler为什么保留?

vue-template-compiler只有一个消费者:@vue/test-utils@1.3.6。

vitest(测试运行器) → 加载测试文件 → mount(Component) ← @vue/test-utils → require('vue-template-compiler').compileToFunctions() → 将 Vue 模板编译为 render 函数

源码验证(node_modules/@vue/test-utils/dist/vue-test-utils.js):

varvueTemplateCompiler=require('vue-template-compiler');varel=vueTemplateCompiler.compileToFunctions("<div><template slot="+name+">"+slotValue+"</template></div>");

@vue/test-utils在 mount 组件时需要将模板字符串编译为 render 函数——这是 Vue 2 特有的步骤(Vue 3 的@vue/test-utils不再需要)。@vue/test-utils将其声明为peerDependency,由消费项目提供。

与@vitejs/plugin-vue2无关:@vitejs/plugin-vue2的 peerDeps 只有vite和vue,不依赖vue-template-compiler——它使用自己的内部编译器处理.vue文件。生产构建不需要vue-template-compiler。

结论:保留它的唯一原因是@vue/test-utils需要。如果项目不使用@vue/test-utils(或升级到 Vue 3),就可以移除。


1.4 脚本命令更新

原则:核心脚本名不变

脚本名是 CI/CD 流水线、Dockerfile、开发文档中的硬编码引用。迁移策略是:核心脚本名(serve/build/lint)保持不变,只替换内部调用的命令。带参数的辅助脚本在后续优化中统一为:params命名风格(如serveStart→serve:params)。

逐命令分析

npm run serve:vite
"serve":"vite"

为什么叫serve而不是dev?这是直接从 Vue CLI 时期继承的命名。Vue CLI 使用vue-cli-service serve启动开发服务器,所以脚本名叫serve。保持这个命名,CI/CD 中写npm run serve的地方不需要改。

vite命令不带参数时,默认启动开发服务器,默认端口 5173(本项目在vite.config.js中配置为8080,并开启host: true与strictPort: false——详见第九节 §1.5)。

npm run serve:params:npm run serve --brand_color=#DC143C --custom_path=/privatiza20 --tag_name=
"serve:params":"npm run serve --brand_color=#DC143C --custom_path=/privatiza20 --tag_name="

(迁移初期名为serveStart,后续统一为:params命名风格。)

npm_config_机制详解:

当执行npm run serve --brand_color=#DC143C时(注意:没有--分隔符):

  1. npm 把--brand_color=#DC143C当作 npm 自身的配置参数
  2. npm 设置环境变量npm_config_brand_color=#DC143C
  3. npm 执行serve脚本(即vite)
  4. vite.config.js中process.env.npm_config_brand_color读取到'#DC143C'

关键区分——npm 的两种参数传递方式(实测验证):

方式 A: npm run serve --brand_color=#DC143C ← 项目实际用法 → npm 解析 --brand_color → 设置 npm_config_brand_color 环境变量 → ✅ 方式 B: npm run serve -- --port 8080 ← 传给 vite 的 CLI 参数 → -- 后面的是给脚本的 → node/vite 的 process.argv 接收 → 不设环境变量

#为什么安全?实测npm run env-test --brand_color=#DC143C:npm 在 shell 解释之前解析参数,#DC143C完整保留,不会触发 shell 的注释行为。如果直接写vite --brand_color=#DC143C(不通过 npm),bash 会把#后的内容当作注释截断。

npm run build:vite build
"build":"vite build"

vite build使用 Rollup 执行生产构建。默认输出到dist/目录,产物经过代码分割、压缩、css 提取等处理。

相比vue-cli-service build --no-module:

Webpack 时代使用--no-module是因为构建产物是 ES5,用普通<script>标签加载,所有浏览器都能执行。Vite 的构建产物是 ESM,必须用<script type="module">加载:

<!-- Webpack 产物(ES5) --><scriptsrc="/js/chunk-vendors.js"></script>← 所有浏览器都能加载<!-- Vite 产物(ESM) --><scripttype="module"src="/assets/index-abc.js"></script>← 仅现代浏览器能加载

<script type="module">在 HTML 规范中的行为:

浏览器行为结果
支持 ESM(Chrome 61+)正常下载、解析、执行✅
不支持 ESM(IE11、旧 Android WebView)静默跳过此标签,不下载不报错❌ 白屏

这是 HTML 规范的刻意设计——不支持的浏览器不会尝试降级,直接忽略。Vite 默认只生成<script type="module">,没有<script nomodule>兜底。这意味着旧浏览器用户看到的将是空白页面——与 Webpack 时代的 ES5 bundle 兼容性存在本质差异。

这正是@vitejs/plugin-legacy解决的问题(详见 第七节(五):ES5 降级方案专题):双构建后同时输出现代产物(type="module")和传统产物(nomodule),旧浏览器通过<script nomodule>加载 ES5 版本。

npm run analyze:npm run build --report
"analyze":"npm run build --report"

--report参数通过npm_config_report环境变量传递给vite.config.js。vite.config.js中判断process.env.npm_config_report是否存在,若存在则启用rollup-plugin-visualizer:

// vite.config.js 的 visualizer 条件插件...(process.env.npm_config_report?[visualizer({...})]:[]),

注意:npm run build --report会用--report参数调用vite build,但vite build本身不认识--report。关键在于npm把--report转换为npm_config_report环境变量,vite.config.js读取的是这个环境变量,不是 CLI 参数。

npm run build:params:带参数的构建
"build:params":"npm run build --brand_color=#DC143C --custom_path=/privatiza20 --tag_name=v4.3.0"

--tag_name=v4.3.0通过npm_config_tag_name传递给vite.config.js,最终注入到import.meta.env.APP_TAGNAME编译时常量中。

为什么tag_name、brand_color、custom_path同时出现?项目构建时,版本标识(tag)、品牌色和部署路径是独立配置的。build:params在同一个脚本中组合这三个参数,覆盖实际部署时的完整需求。(迁移初期名为build:tagName,参数仅有--tag_name=我是好人,后续统一为:params命名风格并补齐参数。)

npm run lint:fix:eslint --ext .js,.vue src --fix
"lint":"eslint --ext .js,.vue src","lint:fix":"eslint --ext .js,.vue src --fix"

逐参数拆解:

参数值作用
--ext.js,.vue指定检查的文件扩展名。逗号分隔多个扩展名,ESLint 只检查匹配这些扩展名的文件
srcsrc指定检查目录。ESLint 递归扫描src/下所有匹配--ext的文件
--fix—自动修复可修复的问题(如缩进、分号、引号风格等)。不可修复的问题(如逻辑错误)只报告不修复

为什么从vue-cli-service lint --fix改为eslint --ext .js,.vue src --fix?

vue-cli-service lint是@vue/cli-plugin-eslint提供的命令,它封装了 ESLint 的调用。移除 Vue CLI 后,直接使用eslint命令。

@vue/cli-plugin-eslint的 lint 命令做了什么额外的事情?它实际上做了三件事:

  1. 调用 ESLint API 检查代码
  2. 如果 lint 失败,阻止 Webpack 编译(开发环境)
  3. 在vue-cli-service build时,lint 错误会阻止构建

Vite 不集成 ESLint,所以这些"阻止构建"的行为不再需要。ESLint 作为独立工具运行,不影响构建流程。

lintvslint:fix的区别:lint只检查不修复(用于 CI 流水线),lint:fix检查并自动修复(用于本地开发)。两者共用同一套参数,只是--fix的有无。

测试脚本(迁移前已配置,保留不变)

以下 6 个测试脚本自 2026-08-13 起已配置,迁移过程中保留不变:

"test":"vitest run","test:watch":"vitest","test:e2e":"playwright test","test:e2e:headed":"playwright test --headed","test:e2e:ui":"playwright test --ui","test:coverage":"vitest run --coverage"
脚本命令作用
testvitest run运行单元测试(单次,不监听)
test:watchvitest运行单元测试(监听模式,文件变更自动重跑)
test:e2eplaywright test运行 E2E 测试(无头浏览器)
test:e2e:headedplaywright test --headed运行 E2E 测试(有头浏览器,弹出可见窗口查看页面实际操作)
test:e2e:uiplaywright test --ui打开 Playwright 交互式测试面板,可浏览用例列表、按需重跑、开启时间旅行调试
test:coveragevitest run --coverage运行单元测试并生成覆盖率报告

--headedvs--ui的区别:

--headed--ui
本质让浏览器窗口可见Playwright交互式测试面板
浏览器窗口弹出可见窗口默认 headless(可在面板中手动切换)
交互性无,跑完即结束有——点击重跑、查看 Trace、按用例筛选
适用场景调试某个测试,想看页面实际操作开发阶段持续跑测试、浏览用例列表、复盘失败

--headed只是把浏览器露出来——和执行普通命令的唯一区别是"能看到画面"。--ui打开的是 VS Code 风格的完整测试管理面板,是开发阶段的主力工具。

为什么是 vitest + Playwright 这套组合?迁移过程本身需要验证——每次改动后需要运行测试确认没有回归。vitest 与 Vite 共享同一套配置(vite.config.js中的resolve.alias、css.preprocessorOptions等),无需额外配置测试环境。Playwright 则独立于构建工具,通过@playwright/test包提供。


1.5.eslintrc.js清理

移除的配置

原settings['import/resolver']中配置的是webpackresolver,指向已不存在的@vue/cli-service配置文件。该 resolver 已替换为custom-alias(见下文"为什么移除后还能正常工作"):

// .eslintrc.js — webpack resolver(已移除,替换为 custom-alias)settings:{'import/resolver':{webpack:{// ← 这个 resolver 被移除config:'node_modules/@vue/cli-service/webpack.config.js'}}}

当前.eslintrc.js中settings块保留,内容改为:

settings:{'import/resolver':{'custom-alias':{// ← 替换为 custom-aliasalias:{'@':'./src'},extensions:['.js','.vue','.json','.less','.png','.svg'],},},},

逐行拆解:

settings:ESLint 配置中的顶层键,用于给插件传递共享配置。与rules(控制规则开关)不同,settings是给插件内部使用的数据,不直接影响 lint 规则。

'import/resolver':eslint-plugin-import的配置项。import/前缀表示这是eslint-plugin-import插件的专属配置。resolver告诉插件"如何解析 import 路径"。

webpack:指定使用eslint-import-resolver-webpack这个 resolver。ESLint 插件系统支持多种 resolver——node(默认,只解析node_modules)、webpack(读取 webpack 配置解析别名)、typescript(读取 tsconfig 解析路径映射)等。

config: 'node_modules/@vue/cli-service/webpack.config.js':指定 webpack 配置文件的路径。resolver 会读取这个文件,从中提取resolve.alias配置,从而理解@/→src/的映射。

完整工作流程:

ESLint 检查 import 语句时: import { getList } from '@/api/user' ↑ 路径别名 @/ 需要解析 ① 检查 settings['import/resolver'] ② 发现配置了 webpack resolver ③ 读取 node_modules/@vue/cli-service/webpack.config.js ④ 找到 resolve.alias: { '@': 'src/' } ⑤ 把 @/api/user 解析为 src/api/user ⑥ 检查 src/api/user 文件是否存在 → 存在 → 通过

为什么移除后还能正常工作

两个原因:

  1. Webpack 配置文件不存在了:node_modules/@vue/cli-service/webpack.config.js在移除@vue/cli-service后已经不存在,这个配置指向了一个不存在的文件。

  2. eslint-import-resolver-custom-alias替代:通过alias: { '@': './src' }和extensions: ['.js', '.vue', ...]配置,提供@/别名和.vue扩展名解析,使import/no-unresolved规则恢复到正常工作状态。

为什么import/extensions: 'off'必须保持

.eslintrc.js中'import/extensions': 'off'关闭了一条规则。Airbnb 默认对其是启用的:

// eslint-config-airbnb-base 的默认配置"import/extensions":["error","ignorePackages",{"js":"never",// import .js 文件时禁止写 .js 后缀"mjs":"never","jsx":"never",}]

这条规则的含义:

场景规则行为示例
.js/.jsx文件禁止写扩展名import util from './util'✅ /import util from './util.js'❌
npm 包(ignorePackages)不检查import Vue from 'vue'✅
未列出的扩展名(含.vue)要求必须写import X from './X'❌ 必须写成import X from './X.vue'

如果开启,项目中所有不带.vue后缀的 import 全部报错:

import CanvasSignature from './CanvasSignature' ❌ Missing file extension "vue" import SealCard from './sealCard' ❌ Missing file extension "vue"

Vue 社区的约定俗成是从来不写.vue后缀——这不是项目的个别选择,而是整个 Vue 生态的惯例。Airbnb 规则不了解.vue的存在,eslint-plugin-vue也不处理import/extensions。因此在 Vue 项目中这条规则必须'off'——与 Webpack 迁移到 Vite 无关,在 Webpack 时期就应该关闭。


1.6 依赖数量对比

精确对比

迁移前(Webpack 时期):

分类包名数量
构建核心webpack,@vue/cli-service,@vue/cli-plugin-babel,@vue/cli-plugin-eslint4
Babel 相关@babel/core,@babel/preset-env,@babel/plugin-transform-runtime,babel-plugin-import4
Loader/Pluginless-loader,style-resources-loader,svg-sprite-loader,compression-webpack-plugin,copy-webpack-plugin,git-revision-webpack-plugin6
其他webpack-bundle-analyzer,eslint-import-resolver-webpack2
后续替换lodash→lodash-es(1 换 1,迁移后独立提交)1
保留所有保留的 31 个包(含core-js,保留项:^3.38.1 → ^3.50.0 升级)31
总计48

迁移后(Vite 时期):

分类包名数量
构建工具vite,@vitejs/plugin-vue2,vite-plugin-compression,rollup-plugin-visualizer4
ES5 降级@vitejs/plugin-legacy,core-js,regenerator-runtime,terser4
测试vitest,@vitest/coverage-v8,@playwright/test,@vue/test-utils,jsdom5
Linteslint,eslint-plugin-vue,eslint-plugin-import,@vue/eslint-config-airbnb,eslint-import-resolver-custom-alias5
样式less,autoprefixer2
编译vue-template-compiler1
辅助ioredis,mysql22
运行时依赖vue,vuex,axios等 17 个(迁移前后不变;lodash-es替换lodash)17
总计40

对比:48 → 40。共移除 17 个、新增 9 个,净减 8 个(迁移提交移除 16 个 + 后续 lodash → lodash-es 1 换 1 替换)。

配置文件体积对比

文件迁移前迁移后减少
构建配置vue.config.js310 行vite.config.js200 行35%
转译配置babel.config.js22 行无100%
合计332 行200 行约 40%

这些减少意味着什么

npm install 时间(--prefer-offline,实测):Webpack 项目 ~70s,Vite 项目 ~15s,减少 79%。这是因为:

  1. 净少装 8 个包(及其传递依赖),依赖树更浅
  2. Vite 生态的包体积更小(esbuild 是 Go 写的,发布为原生二进制文件,没有 JS 依赖链)

node_modules 体积:估计减少 40-50%。Babel 及其插件生态(@babel/core、@babel/preset-env、@babel/plugin-transform-runtime等)的传递依赖非常多,仅@babel/core就有 20+ 个传递依赖。移除 Babel 后,node_modules 中减少约 100+ 个文件。

构建速度(3 轮实测平均值):

Webpack(优化项目)Vite(当前项目)
第 1 轮3m 37s35s
第 2 轮3m 24s38s
第 3 轮3m 31s38s
平均~3m 31s (211s)~37s

Vite 构建速度快约5.7 倍(减少 82%)。差距远超"esbuild 比 Babel 快 10-20 倍"所能解释的范围——Webpack 的大部分时间消耗在模块依赖图构建和打包上(JS 实现),而 Vite 开发模式根本不打包,生产模式的 Rollup 打包效率也远高于 Webpack。


总结

维度Webpack 时期Vite 时期
配置文件vue.config.js(310行) +babel.config.js(22行)vite.config.js(197行)
构建核心webpack + 80+ 个 loader/pluginVite + esbuild + Rollup
转译Babel(JS 实现,慢)esbuild(Go 实现,快 10-20 倍)
打包Webpack(JS 实现)Rollup(JS 实现,tree-shaking 更优)
压缩terser(JS 实现)esbuild(Go 实现)
CSS 变量注入style-resources-loaderadditionalData
SVG 图标svg-sprite-loadervirtual module 插件(virtual:svg-icons)
文件复制copy-webpack-pluginconfigureServer + closeBundle 钩子
Git 版本git-revision-webpack-pluginexecSync('git rev-parse')
构建分析webpack-bundle-analyzerrollup-plugin-visualizer
依赖数量48 个40 个
构建时间~3m 31s~37s
npm install~70s~15s

核心代价:去掉了手动子路径导入的样式按需加载能力,改为antd.less全量样式文件替代。但 Rollup 的 tree-shaking 对 JS 代码的处理效果与子路径导入一致(实验验证 bundle 大小几乎相同)。eslint-import-resolver-webpack替换为eslint-import-resolver-custom-alias(已安装),通过alias和extensions配置恢复了import/no-unresolved的完整功能。

核心理念:Vite 的设计哲学是"内置常见功能,减少配置"。共移除 17 个包、新增 9 个(净减 8 个)——不是因为它们的功能消失了,而是因为 Vite 把这些功能内置到了自己的代码中,或者用更简单的方式(execSync、additionalData、closeBundle钩子)替代了。


本节小结:迁移的核心指标——依赖 48 → 40(净减 8),配置文件 332 → 200 行(约 -40%),构建 3m31s → 37s(-82%),npm install 70s → 15s(-79%)。代码量减少靠的是"壳"的消除(vue.config.js不再是 Webpack 配置的中间层),速度提升靠的是"活"的减少(目标浏览器升级消除了转译需求)。保留的 23 个包各有各的理由——less 编译器是必需品、autoprefixer + browserslist 是共享配置、vue-template-compiler 是测试依赖——没有一个是为了保留而保留。

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

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

立即咨询