每个Vue3开发者在开始新项目时,首先面临的一个技术选型就是:使用Vite还是Vue CLI?Vue CLI作为Vue生态的"老牌"脚手架,陪伴了无数开发者走过Vue2时代;而Vite作为新一代构建工具,以极致的开发体验和性能优势迅速崛起,并已成为Vue官方推荐的默认选项。本文将从原理、性能、生态、迁移等多个维度全面对比两者,帮助你做出最适合自己项目的选择。全文约12000字,是Vue3工具链学习的关键篇章。
一、什么是项目脚手架?为什么它如此重要?
1.1 脚手架的定义
"脚手架"(Scaffolding)一词源于建筑行业,指建筑工地上为工人搭建的临时结构。在软件开发领域,项目脚手架扮演着类似的角色------它帮助开发者在项目启动阶段快速搭建出标准化的项目结构,配置好开发环境,让开发者可以专注于业务代码的编写。
在Vue生态中,脚手架工具负责:
- 生成标准化的项目目录结构
- 配置构建工具(打包、编译、压缩等)
- 预置开发服务器(支持热更新)
- 集成常用的开发依赖(ESLint、Prettier等)
- 提供插件系统以扩展功能
#mermaid-svg-p0nyqWZqOvfwlKvu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-p0nyqWZqOvfwlKvu .error-icon{fill:#552222;}#mermaid-svg-p0nyqWZqOvfwlKvu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-p0nyqWZqOvfwlKvu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-p0nyqWZqOvfwlKvu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-p0nyqWZqOvfwlKvu .marker.cross{stroke:#333333;}#mermaid-svg-p0nyqWZqOvfwlKvu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-p0nyqWZqOvfwlKvu p{margin:0;}#mermaid-svg-p0nyqWZqOvfwlKvu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-p0nyqWZqOvfwlKvu .cluster-label text{fill:#333;}#mermaid-svg-p0nyqWZqOvfwlKvu .cluster-label span{color:#333;}#mermaid-svg-p0nyqWZqOvfwlKvu .cluster-label span p{background-color:transparent;}#mermaid-svg-p0nyqWZqOvfwlKvu .label text,#mermaid-svg-p0nyqWZqOvfwlKvu span{fill:#333;color:#333;}#mermaid-svg-p0nyqWZqOvfwlKvu .node rect,#mermaid-svg-p0nyqWZqOvfwlKvu .node circle,#mermaid-svg-p0nyqWZqOvfwlKvu .node ellipse,#mermaid-svg-p0nyqWZqOvfwlKvu .node polygon,#mermaid-svg-p0nyqWZqOvfwlKvu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-p0nyqWZqOvfwlKvu .rough-node .label text,#mermaid-svg-p0nyqWZqOvfwlKvu .node .label text,#mermaid-svg-p0nyqWZqOvfwlKvu .image-shape .label,#mermaid-svg-p0nyqWZqOvfwlKvu .icon-shape .label{text-anchor:middle;}#mermaid-svg-p0nyqWZqOvfwlKvu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-p0nyqWZqOvfwlKvu .rough-node .label,#mermaid-svg-p0nyqWZqOvfwlKvu .node .label,#mermaid-svg-p0nyqWZqOvfwlKvu .image-shape .label,#mermaid-svg-p0nyqWZqOvfwlKvu .icon-shape .label{text-align:center;}#mermaid-svg-p0nyqWZqOvfwlKvu .node.clickable{cursor:pointer;}#mermaid-svg-p0nyqWZqOvfwlKvu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-p0nyqWZqOvfwlKvu .arrowheadPath{fill:#333333;}#mermaid-svg-p0nyqWZqOvfwlKvu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-p0nyqWZqOvfwlKvu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-p0nyqWZqOvfwlKvu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p0nyqWZqOvfwlKvu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-p0nyqWZqOvfwlKvu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p0nyqWZqOvfwlKvu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-p0nyqWZqOvfwlKvu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-p0nyqWZqOvfwlKvu .cluster text{fill:#333;}#mermaid-svg-p0nyqWZqOvfwlKvu .cluster span{color:#333;}#mermaid-svg-p0nyqWZqOvfwlKvu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-p0nyqWZqOvfwlKvu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-p0nyqWZqOvfwlKvu rect.text{fill:none;stroke-width:0;}#mermaid-svg-p0nyqWZqOvfwlKvu .icon-shape,#mermaid-svg-p0nyqWZqOvfwlKvu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-p0nyqWZqOvfwlKvu .icon-shape p,#mermaid-svg-p0nyqWZqOvfwlKvu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-p0nyqWZqOvfwlKvu .icon-shape .label rect,#mermaid-svg-p0nyqWZqOvfwlKvu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-p0nyqWZqOvfwlKvu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-p0nyqWZqOvfwlKvu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-p0nyqWZqOvfwlKvu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 开发者输入命令
脚手架工具
生成项目目录结构
配置构建工具链
安装基础依赖
配置开发服务器
集成代码规范工具
标准化的项目模板
开发者开始编写业务代码
1.2 脚手架解决了什么问题?
在没有脚手架工具的年代,前端开发者启动一个新项目需要手动完成以下工作:
| 步骤 | 手动操作 | 脚手架自动完成 |
|---|---|---|
| 项目初始化 | 手动创建文件夹,npm init |
一条命令生成完整项目 |
| 构建配置 | 手写webpack.config.js(上百行) | 预置最佳配置,开箱即用 |
| 依赖安装 | 逐个安装vue、vue-router、pinia等 | 一键安装所有基础依赖 |
| 开发服务器 | 手动配置webpack-dev-server | 内置开发服务器,支持HMR |
| 代码规范 | 手动配置ESLint、Prettier | 交互式选择,自动配置 |
| 环境变量 | 手动创建.env文件 | 预置环境变量模板 |
| 项目结构 | 自己设计目录结构 | 遵循社区最佳实践的目录结构 |
对于一个有经验的开发者,手动完成这些配置可能需要2-4小时,而且容易出错。使用脚手架工具,这个过程缩短到2-5分钟,且配置质量有保障。
1.3 现代前端脚手架的核心能力
一个优秀的现代前端脚手架应该具备以下核心能力:
(1)快速初始化
通过简单的命令行交互,在几分钟内生成一个可运行的项目。开发者只需要回答几个问题(项目名称、是否需要TypeScript、是否需要路由等),脚手架就能自动生成对应的项目代码。
(2)开发体验优化
- 热模块替换(HMR):修改代码后浏览器自动更新,无需手动刷新
- 快速冷启动:开发服务器应在秒级内启动
- 错误提示:编译错误时提供清晰的错误信息和位置定位
(3)生产构建优化
- 代码压缩:移除空白、注释,压缩变量名
- 代码分割:将代码拆分为多个小块,按需加载
- Tree Shaking:移除未使用的代码
- 资源优化:图片压缩、CSS提取、字体优化
(4)可扩展性
- 插件系统:支持通过插件扩展功能
- 配置可定制:允许开发者覆盖默认配置
- 社区生态:丰富的第三方插件和解决方案
二、Vue CLI:老牌Vue项目脚手架
2.1 Vue CLI简介
Vue CLI(Command Line Interface)是Vue.js官方提供的标准开发工具,从Vue 2.x时代开始就一直是Vue项目的首选脚手架。它的第一个版本发布于2018年,至今已经经历了Vue 2到Vue 3的完整演进。
Vue CLI基于Webpack构建,提供了一个完整的项目脚手架系统,包含了:
@vue/cli:全局命令行工具,用于创建和管理项目@vue/cli-service:项目级服务,提供开发、构建、检查等功能@vue/cli-plugin-*:插件体系,扩展项目功能
bash
# 全局安装Vue CLI
npm install -g @vue/cli
# 创建Vue3项目
vue create my-vue3-app
# 或使用图形化界面
vue ui
2.2 Vue CLI的核心特性
(1)交互式项目创建
Vue CLI提供了丰富的交互式选项,让开发者可以根据需求定制项目:
bash
Vue CLI v5.0.8
? Please pick a preset:
Default ([Vue 3] babel, eslint)
Default ([Vue 2] babel, eslint)
> Manually select features
? Check the features needed for your project:
◉ Babel
◉ TypeScript
◉ Progressive Web App (PWA) Support
◉ Router
◉ Vuex
◉ CSS Pre-processors
◉ Linter / Formatter
◉ Unit Testing
◉ E2E Testing
(2)图形化管理界面
Vue CLI提供了一套Web图形化管理界面,通过vue ui命令启动:
bash
vue ui
# 浏览器自动打开 http://localhost:8000
在这个界面中,你可以:
- 创建新项目
- 管理项目依赖(安装、更新、卸载)
- 配置项目设置
- 运行任务(serve、build、lint等)
- 查看项目分析和构建报告
(3)插件体系
Vue CLI的插件系统非常成熟,官方和社区提供了大量插件:
bash
# 添加TypeScript支持
vue add typescript
# 添加Vue Router
vue add router
# 添加Vuex(状态管理)
vue add vuex
# 添加单元测试
vue add unit-jest
# 添加Element Plus组件库
vue add element-plus
(4)预设(Preset)功能
Vue CLI允许将项目配置保存为预设,供团队复用:
json
// ~/.vuerc 或项目的 preset.json
{
"useConfigFiles": true,
"plugins": {
"@vue/cli-plugin-babel": {},
"@vue/cli-plugin-router": {
"historyMode": true
},
"@vue/cli-plugin-vuex": {},
"@vue/cli-plugin-eslint": {
"config": "standard",
"lintOn": ["save", "commit"]
}
},
"vueVersion": "3"
}
2.3 Vue CLI的项目结构
使用Vue CLI创建的项目具有以下标准结构:
my-vue3-app/
├── public/ # 静态资源目录
│ ├── favicon.ico # 网站图标
│ └── index.html # HTML模板
├── src/ # 源代码目录
│ ├── assets/ # 资源文件(图片、字体等)
│ ├── components/ # 公共组件
│ ├── views/ # 页面组件
│ ├── router/ # 路由配置
│ │ └── index.js
│ ├── store/ # 状态管理
│ │ └── index.js
│ ├── App.vue # 根组件
│ └── main.js # 入口文件
├── .browserslistrc # 浏览器兼容配置
├── .eslintrc.js # ESLint配置
├── babel.config.js # Babel配置
├── package.json # 项目依赖与脚本
├── vue.config.js # Vue CLI配置(可选)
└── README.md # 项目说明
2.4 Vue CLI的底层:Webpack
Vue CLI的核心构建引擎是Webpack。Webpack是一个强大的模块打包工具,它的工作原理可以概括为:
#mermaid-svg-y9x3E7gjLiUp5baf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-y9x3E7gjLiUp5baf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-y9x3E7gjLiUp5baf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-y9x3E7gjLiUp5baf .error-icon{fill:#552222;}#mermaid-svg-y9x3E7gjLiUp5baf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-y9x3E7gjLiUp5baf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-y9x3E7gjLiUp5baf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-y9x3E7gjLiUp5baf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-y9x3E7gjLiUp5baf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-y9x3E7gjLiUp5baf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-y9x3E7gjLiUp5baf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-y9x3E7gjLiUp5baf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-y9x3E7gjLiUp5baf .marker.cross{stroke:#333333;}#mermaid-svg-y9x3E7gjLiUp5baf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-y9x3E7gjLiUp5baf p{margin:0;}#mermaid-svg-y9x3E7gjLiUp5baf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-y9x3E7gjLiUp5baf .cluster-label text{fill:#333;}#mermaid-svg-y9x3E7gjLiUp5baf .cluster-label span{color:#333;}#mermaid-svg-y9x3E7gjLiUp5baf .cluster-label span p{background-color:transparent;}#mermaid-svg-y9x3E7gjLiUp5baf .label text,#mermaid-svg-y9x3E7gjLiUp5baf span{fill:#333;color:#333;}#mermaid-svg-y9x3E7gjLiUp5baf .node rect,#mermaid-svg-y9x3E7gjLiUp5baf .node circle,#mermaid-svg-y9x3E7gjLiUp5baf .node ellipse,#mermaid-svg-y9x3E7gjLiUp5baf .node polygon,#mermaid-svg-y9x3E7gjLiUp5baf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-y9x3E7gjLiUp5baf .rough-node .label text,#mermaid-svg-y9x3E7gjLiUp5baf .node .label text,#mermaid-svg-y9x3E7gjLiUp5baf .image-shape .label,#mermaid-svg-y9x3E7gjLiUp5baf .icon-shape .label{text-anchor:middle;}#mermaid-svg-y9x3E7gjLiUp5baf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-y9x3E7gjLiUp5baf .rough-node .label,#mermaid-svg-y9x3E7gjLiUp5baf .node .label,#mermaid-svg-y9x3E7gjLiUp5baf .image-shape .label,#mermaid-svg-y9x3E7gjLiUp5baf .icon-shape .label{text-align:center;}#mermaid-svg-y9x3E7gjLiUp5baf .node.clickable{cursor:pointer;}#mermaid-svg-y9x3E7gjLiUp5baf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-y9x3E7gjLiUp5baf .arrowheadPath{fill:#333333;}#mermaid-svg-y9x3E7gjLiUp5baf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-y9x3E7gjLiUp5baf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-y9x3E7gjLiUp5baf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y9x3E7gjLiUp5baf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-y9x3E7gjLiUp5baf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y9x3E7gjLiUp5baf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-y9x3E7gjLiUp5baf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-y9x3E7gjLiUp5baf .cluster text{fill:#333;}#mermaid-svg-y9x3E7gjLiUp5baf .cluster span{color:#333;}#mermaid-svg-y9x3E7gjLiUp5baf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-y9x3E7gjLiUp5baf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-y9x3E7gjLiUp5baf rect.text{fill:none;stroke-width:0;}#mermaid-svg-y9x3E7gjLiUp5baf .icon-shape,#mermaid-svg-y9x3E7gjLiUp5baf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y9x3E7gjLiUp5baf .icon-shape p,#mermaid-svg-y9x3E7gjLiUp5baf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-y9x3E7gjLiUp5baf .icon-shape .label rect,#mermaid-svg-y9x3E7gjLiUp5baf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y9x3E7gjLiUp5baf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-y9x3E7gjLiUp5baf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-y9x3E7gjLiUp5baf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 入口文件
src/main.js
Webpack
.vue 单文件组件
.js / .ts 模块
.css / .scss 样式
图片/字体等资源
Loader处理
vue-loader
解析.vue文件
babel-loader
转译ES6+
css-loader
处理CSS
file-loader
处理资源
Plugin处理
HtmlWebpackPlugin
生成HTML
MiniCssExtractPlugin
提取CSS
TerserPlugin
压缩JS
输出打包文件
dist/ 目录
生产就绪的文件
然而,Webpack的一个核心问题在于:它必须先将整个应用的所有模块打包处理,然后才能启动开发服务器。随着项目规模的增长,这个打包过程会变得越来越慢,严重影响开发体验。
2.5 Vue CLI的优势与局限
优势:
| 优势 | 说明 |
|---|---|
| 成熟稳定 | 经过多年迭代,功能完善,bug较少 |
| 文档丰富 | 中文文档完善,社区讨论活跃 |
| 插件丰富 | 官方和社区插件数量庞大 |
| 企业认可 | 大量企业项目使用,招聘市场上广泛认可 |
| 图形化界面 | vue ui提供直观的项目管理 |
| 配置灵活 | vue.config.js支持深度定制Webpack配置 |
| 兼容性好 | 对老旧浏览器支持更好(通过Babel) |
局限:
| 局限 | 说明 |
|---|---|
| 启动速度慢 | 大型项目冷启动可能需要30秒以上 |
| HMR速度慢 | 项目规模大时,热更新可能需要数秒 |
| 构建速度慢 | 生产构建时间较长,影响CI/CD效率 |
| 配置复杂 | Webpack配置学习曲线陡峭 |
| 底层技术老旧 | 基于Webpack 4/5,部分设计理念已过时 |
| 内存占用高 | 开发服务器内存占用较大 |
三、Vite:新一代前端构建工具
3.1 Vite的诞生背景
Vite(法语"快"的意思,发音/vit/)由Vue.js的作者尤雨溪(Evan You)于2020年创建。它的诞生源于一个核心问题:随着项目规模的增长,基于Webpack的构建工具变得越来越慢,开发体验严重下降。
尤雨溪在Vite的官方文档中这样描述它的设计初衷:
Vite旨在利用浏览器原生支持的ES模块(ESM),为现代Web项目提供更快、更精简的开发体验。
Vite的核心理念是"按需编译 "而非"全量打包",这一理念的转变是它能够实现极致性能的关键。
3.2 Vite的核心原理
Vite的开发服务器工作原理与传统构建工具有本质区别:
文件系统 esbuild预构建 Vite开发服务器 浏览器 文件系统 esbuild预构建 Vite开发服务器 浏览器 #mermaid-svg-Te6WEsG0wyzy7LCG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Te6WEsG0wyzy7LCG .error-icon{fill:#552222;}#mermaid-svg-Te6WEsG0wyzy7LCG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Te6WEsG0wyzy7LCG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Te6WEsG0wyzy7LCG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Te6WEsG0wyzy7LCG .marker.cross{stroke:#333333;}#mermaid-svg-Te6WEsG0wyzy7LCG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Te6WEsG0wyzy7LCG p{margin:0;}#mermaid-svg-Te6WEsG0wyzy7LCG .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Te6WEsG0wyzy7LCG text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-Te6WEsG0wyzy7LCG .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Te6WEsG0wyzy7LCG .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-Te6WEsG0wyzy7LCG .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-Te6WEsG0wyzy7LCG .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-Te6WEsG0wyzy7LCG #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-Te6WEsG0wyzy7LCG .sequenceNumber{fill:white;}#mermaid-svg-Te6WEsG0wyzy7LCG #sequencenumber{fill:#333;}#mermaid-svg-Te6WEsG0wyzy7LCG #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-Te6WEsG0wyzy7LCG .messageText{fill:#333;stroke:none;}#mermaid-svg-Te6WEsG0wyzy7LCG .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Te6WEsG0wyzy7LCG .labelText,#mermaid-svg-Te6WEsG0wyzy7LCG .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-Te6WEsG0wyzy7LCG .loopText,#mermaid-svg-Te6WEsG0wyzy7LCG .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-Te6WEsG0wyzy7LCG .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-Te6WEsG0wyzy7LCG .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-Te6WEsG0wyzy7LCG .noteText,#mermaid-svg-Te6WEsG0wyzy7LCG .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-Te6WEsG0wyzy7LCG .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Te6WEsG0wyzy7LCG .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Te6WEsG0wyzy7LCG .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-Te6WEsG0wyzy7LCG .actorPopupMenu{position:absolute;}#mermaid-svg-Te6WEsG0wyzy7LCG .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-Te6WEsG0wyzy7LCG .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-Te6WEsG0wyzy7LCG .actor-man circle,#mermaid-svg-Te6WEsG0wyzy7LCG line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-Te6WEsG0wyzy7LCG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 启动开发服务器 浏览器请求页面 浏览器解析import语句 只编译浏览器实际请求的模块 未访问的模块不会被编译 使用esbuild预构建依赖 读取node_modules 返回预构建结果(极快) GET /index.html 读取index.html 返回HTML GET /src/main.js 读取main.js 处理import路径 返回处理后的JS GET /src/App.vue 读取App.vue 编译SFC(按需) 返回编译后的JS GET /src/components/Header.vue 读取Header.vue 编译SFC(按需) 返回编译后的JS
Vite开发服务器的核心流程:
第一步:预构建依赖
Vite在启动时使用esbuild(用Go语言编写,比JavaScript快10-100倍)快速预构建node_modules中的依赖。这些依赖通常不会频繁变化,预构建的结果会被缓存。
javascript
// vite.config.js 中的预构建配置
export default {
optimizeDeps: {
// 需要预构建的依赖
include: ['vue', 'vue-router', 'pinia', 'axios'],
// 不需要预构建的依赖
exclude: ['your-local-package']
}
}
第二步:按需编译源码
当浏览器请求某个模块时,Vite才动态编译该模块。未请求的模块根本不会被编译,这意味着:
- 无论项目多大,冷启动速度几乎恒定
- 只有当前页面用到的模块会被编译
- 路由切换时,新页面的模块也是按需编译的
第三步:HMR(热模块替换)
Vite的HMR基于原生ESM实现,不需要像Webpack那样重新打包整个模块图。当修改一个文件时:
- Vite精确找到受影响的模块链
- 只向浏览器推送变化的部分
- 浏览器直接替换对应模块
这意味着HMR速度几乎不受项目规模影响。
3.3 Vite的项目结构
使用Vite创建的Vue3项目结构:
my-vite-app/
├── index.html # HTML入口(在项目根目录)
├── package.json # 项目依赖与脚本
├── vite.config.js # Vite配置文件
├── public/ # 静态资源(不经过构建)
│ └── favicon.ico
├── src/ # 源代码目录
│ ├── assets/ # 需要构建的资源(会被处理)
│ ├── components/ # 公共组件
│ ├── views/ # 页面组件
│ ├── router/ # 路由配置
│ │ └── index.js
│ ├── stores/ # 状态管理(Pinia)
│ │ └── counter.js
│ ├── App.vue # 根组件
│ ├── main.js # 入口文件
│ └── style.css # 全局样式
├── .env # 环境变量
├── .env.development # 开发环境变量
├── .env.production # 生产环境变量
└── .gitignore
与Vue CLI项目结构的一个关键区别:index.html位于项目根目录,而不是public目录下 。这是因为Vite将index.html视为构建入口,而不是简单的静态资源。
3.4 Vite的核心特性
(1)极速冷启动
Vite使用esbuild预构建依赖,开发服务器启动速度通常在200-500ms之间,几乎不受项目规模影响。
bash
# 典型的Vite启动日志
VITE v5.4.0 ready in 312 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
(2)即时热更新
HMR速度通常在50ms以内,修改代码后几乎"瞬间"就能看到效果。这种体验上的提升对开发效率影响巨大------开发者可以保持"心流"状态,不被等待打断。
(3)开箱即用的支持
Vite原生支持以下特性,无需额外配置:
| 特性 | 说明 |
|---|---|
| TypeScript | 原生支持.ts文件,无需额外插件 |
| JSX/TSX | 支持Vue JSX和React JSX |
| CSS预处理器 | 支持.scss、.less、.stylus,安装对应预处理器即可 |
| CSS Modules | 自动支持.module.css等文件 |
| JSON导入 | 可以直接import JSON文件 |
| WebAssembly | 支持导入.wasm文件 |
| 静态资源导入 | 导入图片、字体等资源会返回URL |
| 环境变量 | 支持.env文件,自动注入import.meta.env |
(4)丰富的构建优化
javascript
// vite.config.js - 生产构建优化
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
build: {
// 代码分割策略
rollupOptions: {
output: {
manualChunks: {
// 将Vue相关库打包到一起
'vue-vendor': ['vue', 'vue-router', 'pinia'],
// 将UI库单独打包
'ui-vendor': ['element-plus'],
}
}
},
// chunk大小警告阈值
chunkSizeWarningLimit: 1000,
// 压缩配置
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // 移除console.log
drop_debugger: true, // 移除debugger
}
}
}
})
(5)强大的插件系统
Vite的插件系统基于Rollup插件接口,兼容大部分Rollup插件。同时,Vite也有自己独特的插件钩子,用于处理开发服务器相关的逻辑。
javascript
// 一个简单的Vite插件示例
function myPlugin() {
return {
name: 'my-vite-plugin',
// 在开发服务器启动时执行
configureServer(server) {
server.middlewares.use((req, res, next) => {
console.log(`请求: ${req.url}`)
next()
})
},
// 转换代码
transform(code, id) {
if (id.endsWith('.vue')) {
// 对Vue文件做自定义处理
return code
}
}
}
}
3.5 Vite与传统构建工具的本质区别
#mermaid-svg-7JH7UK7BE5OBm22B{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7JH7UK7BE5OBm22B .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7JH7UK7BE5OBm22B .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7JH7UK7BE5OBm22B .error-icon{fill:#552222;}#mermaid-svg-7JH7UK7BE5OBm22B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7JH7UK7BE5OBm22B .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7JH7UK7BE5OBm22B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7JH7UK7BE5OBm22B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7JH7UK7BE5OBm22B .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7JH7UK7BE5OBm22B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7JH7UK7BE5OBm22B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7JH7UK7BE5OBm22B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7JH7UK7BE5OBm22B .marker.cross{stroke:#333333;}#mermaid-svg-7JH7UK7BE5OBm22B svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7JH7UK7BE5OBm22B p{margin:0;}#mermaid-svg-7JH7UK7BE5OBm22B .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7JH7UK7BE5OBm22B .cluster-label text{fill:#333;}#mermaid-svg-7JH7UK7BE5OBm22B .cluster-label span{color:#333;}#mermaid-svg-7JH7UK7BE5OBm22B .cluster-label span p{background-color:transparent;}#mermaid-svg-7JH7UK7BE5OBm22B .label text,#mermaid-svg-7JH7UK7BE5OBm22B span{fill:#333;color:#333;}#mermaid-svg-7JH7UK7BE5OBm22B .node rect,#mermaid-svg-7JH7UK7BE5OBm22B .node circle,#mermaid-svg-7JH7UK7BE5OBm22B .node ellipse,#mermaid-svg-7JH7UK7BE5OBm22B .node polygon,#mermaid-svg-7JH7UK7BE5OBm22B .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7JH7UK7BE5OBm22B .rough-node .label text,#mermaid-svg-7JH7UK7BE5OBm22B .node .label text,#mermaid-svg-7JH7UK7BE5OBm22B .image-shape .label,#mermaid-svg-7JH7UK7BE5OBm22B .icon-shape .label{text-anchor:middle;}#mermaid-svg-7JH7UK7BE5OBm22B .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7JH7UK7BE5OBm22B .rough-node .label,#mermaid-svg-7JH7UK7BE5OBm22B .node .label,#mermaid-svg-7JH7UK7BE5OBm22B .image-shape .label,#mermaid-svg-7JH7UK7BE5OBm22B .icon-shape .label{text-align:center;}#mermaid-svg-7JH7UK7BE5OBm22B .node.clickable{cursor:pointer;}#mermaid-svg-7JH7UK7BE5OBm22B .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7JH7UK7BE5OBm22B .arrowheadPath{fill:#333333;}#mermaid-svg-7JH7UK7BE5OBm22B .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7JH7UK7BE5OBm22B .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7JH7UK7BE5OBm22B .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7JH7UK7BE5OBm22B .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7JH7UK7BE5OBm22B .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7JH7UK7BE5OBm22B .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7JH7UK7BE5OBm22B .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7JH7UK7BE5OBm22B .cluster text{fill:#333;}#mermaid-svg-7JH7UK7BE5OBm22B .cluster span{color:#333;}#mermaid-svg-7JH7UK7BE5OBm22B div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7JH7UK7BE5OBm22B .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7JH7UK7BE5OBm22B rect.text{fill:none;stroke-width:0;}#mermaid-svg-7JH7UK7BE5OBm22B .icon-shape,#mermaid-svg-7JH7UK7BE5OBm22B .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7JH7UK7BE5OBm22B .icon-shape p,#mermaid-svg-7JH7UK7BE5OBm22B .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7JH7UK7BE5OBm22B .icon-shape .label rect,#mermaid-svg-7JH7UK7BE5OBm22B .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7JH7UK7BE5OBm22B .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7JH7UK7BE5OBm22B .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7JH7UK7BE5OBm22B :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 对比
Vite构建工具
esbuild预构建依赖
启动开发服务器
浏览器请求HTML
浏览器解析ESM imports
Vite按需编译请求的模块
浏览器直接执行模块
只编译实际使用的模块
传统构建工具 - Webpack/Vue CLI
读取所有源码
解析所有模块依赖
打包所有模块
启动开发服务器
浏览器加载完整bundle
核心区别可以总结为:
- 传统方式:先打包全部,再启动服务器(Bundle-based)
- Vite方式:先启动服务器,按需编译(Native ESM-based)
四、全方位对比:Vite vs Vue CLI
4.1 启动速度对比
冷启动速度是开发者每天都会面对的问题。每次打开项目、切换分支、重启服务器时,都需要等待开发服务器启动。
| 项目规模 | Vue CLI (Webpack) | Vite | 速度倍数 |
|---|---|---|---|
| 小型项目(<50组件) | 3-8秒 | 200-500ms | 约10-20倍 |
| 中型项目(50-200组件) | 10-30秒 | 200-600ms | 约20-50倍 |
| 大型项目(>200组件) | 30-120秒 | 300-800ms | 约50-150倍 |
为什么差距这么大?
Vue CLI需要在启动前完成整个依赖图的打包,这个过程包括:
- 读取所有源码文件
- 解析所有import/require依赖关系
- 通过Loader和Plugin处理每个模块
- 生成完整的bundle文件
而Vite只需要:
- 使用esbuild快速预构建node_modules中的依赖(毫秒级)
- 启动开发服务器
- 浏览器按需请求模块时才动态编译
4.2 热更新(HMR)速度对比
热更新速度直接影响开发体验。修改代码后等待更新的时间越长,开发者的"心流"状态越容易被打破。
| 操作类型 | Vue CLI (Webpack) | Vite |
|---|---|---|
| 修改模板(template) | 200-800ms | 10-50ms |
| 修改样式(style) | 100-500ms | 10-30ms |
| 修改逻辑(script) | 500-2000ms | 20-100ms |
| 修改公共组件 | 1000-5000ms | 50-200ms |
| 修改依赖模块 | 5000-15000ms(可能需重启) | 页面自动刷新(秒级) |
Vite HMR的实现原理:
javascript
// Vite的HMR通信流程(简化示意)
// 1. 服务端监听文件变化
const watcher = chokidar.watch('src/**/*')
watcher.on('change', async (file) => {
// 2. 找到受影响的模块
const modules = moduleGraph.getModulesByFile(file)
// 3. 只向客户端推送变化的模块
for (const mod of modules) {
ws.send({
type: 'update',
updates: [{
type: 'js-update',
path: mod.url,
acceptedPath: mod.url,
timestamp: Date.now()
}]
})
}
})
4.3 构建速度对比
生产构建速度在CI/CD流程中尤为重要。构建时间越长,部署效率越低,开发者的等待时间越长。
| 场景 | Vue CLI | Vite | 说明 |
|---|---|---|---|
| 小型项目首次构建 | 5-15秒 | 3-8秒 | Vite使用Rollup,效率更高 |
| 中型项目首次构建 | 15-60秒 | 8-20秒 | 差异随项目规模扩大 |
| 大型项目首次构建 | 60-300秒 | 20-60秒 | 差距显著 |
| 增量构建(缓存) | 3-15秒 | 1-5秒 | 两者都有缓存,但Rollup更快 |
| 构建内存占用 | 500MB-2GB | 300MB-1GB | Vite内存效率更高 |
Vite构建的底层引擎:Rollup
Vite使用Rollup进行生产构建,Rollup的优势在于:
- 生成更小、更高效的bundle
- 天然支持ES模块,Tree Shaking更彻底
- 输出代码更干净,可读性更好
- 插件系统与Vite无缝兼容
4.4 配置方式对比
Vue CLI的配置方式:
javascript
// vue.config.js - Vue CLI配置
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
// 基础路径
publicPath: '/my-app/',
// 输出目录
outputDir: 'dist',
// 静态资源目录
assetsDir: 'static',
// 开发服务器配置
devServer: {
port: 8080,
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},
// Webpack配置(链式调用)
chainWebpack: config => {
config.plugin('html').tap(args => {
args[0].title = '我的应用'
return args
})
config.resolve.alias.set('@', 'src')
},
// 直接修改Webpack配置
configureWebpack: {
plugins: [
// 自定义Webpack插件
]
},
// CSS相关配置
css: {
loaderOptions: {
sass: {
additionalData: `@import "@/styles/variables.scss";`
}
}
}
})
Vite的配置方式:
javascript
// vite.config.js - Vite配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
// 插件
plugins: [vue()],
// 路径别名
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
// 开发服务器配置
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
// CSS配置
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`
}
}
},
// 构建配置
build: {
outDir: 'dist',
assetsDir: 'static',
sourcemap: false,
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router']
}
}
}
},
// 环境变量前缀
envPrefix: 'VITE_'
})
配置复杂度对比:
| 维度 | Vue CLI | Vite |
|---|---|---|
| 基础配置代码量 | 较少(约定大于配置) | 较少(简洁直观) |
| 高级配置难度 | 较高(需要理解Webpack) | 中等(需要理解Rollup) |
| 配置文档质量 | 优秀(中文文档完善) | 优秀(中文文档完善) |
| 配置可读性 | 中等(Webpack链式API较复杂) | 较好(结构清晰) |
| 学习成本 | 高(需要同时学习Vue CLI和Webpack) | 中(主要学习Vite本身) |
4.5 插件生态系统对比
Vue CLI插件生态:
Vue CLI拥有成熟的插件体系,官方和社区提供了大量插件:
| 插件名称 | 功能 | 安装命令 |
|---|---|---|
| @vue/cli-plugin-babel | Babel转译 | 内置 |
| @vue/cli-plugin-typescript | TypeScript支持 | vue add typescript |
| @vue/cli-plugin-router | Vue Router | vue add router |
| @vue/cli-plugin-vuex | Vuex状态管理 | vue add vuex |
| @vue/cli-plugin-eslint | 代码规范 | 内置 |
| @vue/cli-plugin-pwa | PWA支持 | vue add pwa |
| @vue/cli-plugin-unit-jest | Jest单元测试 | vue add unit-jest |
| vue-cli-plugin-element-plus | Element Plus | vue add element-plus |
Vite插件生态:
Vite的插件生态正在快速发展,覆盖了绝大多数开发场景:
| 插件名称 | 功能 | 安装命令 |
|---|---|---|
| @vitejs/plugin-vue | Vue3 SFC支持 | 内置 |
| @vitejs/plugin-vue-jsx | Vue JSX支持 | npm i @vitejs/plugin-vue-jsx |
| vite-plugin-pages | 自动路由 | npm i vite-plugin-pages |
| vite-plugin-components | 自动导入组件 | npm i unplugin-vue-components |
| vite-plugin-auto-import | 自动导入API | npm i unplugin-auto-import |
| vite-plugin-compression | Gzip压缩 | npm i vite-plugin-compression |
| vite-plugin-imagemin | 图片压缩 | npm i vite-plugin-imagemin |
| vite-plugin-pwa | PWA支持 | npm i vite-plugin-pwa |
生态成熟度对比:
| 维度 | Vue CLI | Vite |
|---|---|---|
| 官方插件数量 | 约20+ | 约10+ |
| 社区插件数量 | 1000+(成熟) | 500+(快速增长) |
| 插件质量 | 整体较高 | 整体较高 |
| 插件发现难度 | 容易(文档完善) | 容易(awesome-vite列表) |
| 未来趋势 | 维护模式(不再积极开发新功能) | 活跃开发,生态持续增长 |
4.6 浏览器兼容性对比
| 浏览器 | Vue CLI | Vite |
|---|---|---|
| Chrome | 全面支持 | 全面支持 |
| Firefox | 全面支持 | 全面支持 |
| Safari | 全面支持 | 全面支持 |
| Edge | 全面支持 | 全面支持 |
| IE 11 | 支持(需配置polyfill) | 不支持 |
| 旧版Chrome (<63) | 支持(需配置polyfill) | 不支持 |
| 旧版Safari (<12) | 支持(需配置polyfill) | 不支持 |
重要说明:
Vite的浏览器兼容策略是"只支持现代浏览器 "。它在开发环境中直接使用原生ES模块,这意味着浏览器必须支持<script type="module">。在生产构建时,Vite默认目标也是现代浏览器(ES2015+)。
Vue CLI通过Babel的polyfill机制,可以兼容更老旧的浏览器,包括IE11。但考虑到IE11已经于2022年6月停止支持,对于绝大多数新项目,这不是一个需要担心的因素。
javascript
// vite.config.js - 配置浏览器兼容目标
export default defineConfig({
build: {
target: 'es2015', // 默认值
// 如果需要兼容更旧的浏览器
// target: ['es2015', 'chrome58', 'firefox57', 'safari11']
}
})
4.7 综合对比表
| 对比维度 | Vue CLI | Vite | 胜出 |
|---|---|---|---|
| 启动速度 | 慢(3-120秒) | 极快(200-800ms) | Vite |
| HMR速度 | 慢(100-5000ms) | 极快(10-100ms) | Vite |
| 构建速度 | 慢到中等 | 快到中等 | Vite |
| 配置复杂度 | 中等 | 低到中等 | Vite |
| 学习曲线 | 陡峭(需学Webpack) | 平缓 | Vite |
| 插件生态 | 成熟(1000+插件) | 快速发展(500+) | Vue CLI |
| 文档质量 | 优秀 | 优秀 | 平手 |
| 浏览器兼容性 | 更好(支持IE11) | 仅现代浏览器 | Vue CLI |
| 社区活跃度 | 维护模式 | 非常活跃 | Vite |
| 官方推荐 | 不推荐(新项目) | 强烈推荐 | Vite |
| 企业项目积累 | 大量存量项目 | 新项目首选 | 各有优势 |
| TypeScript支持 | 好(通过插件) | 原生支持 | Vite |
| 多页应用 | 支持 | 支持 | 平手 |
| 库模式构建 | 支持 | 支持 | 平手 |
| 服务端渲染 | 支持 | 支持(通过Nuxt等) | 平手 |
五、如何选择?场景化决策指南
5.1 选择Vite的场景
以下场景强烈建议使用Vite:
(1)新启动的Vue3项目
如果你正在启动一个全新的Vue3项目,Vite是毫无疑问的首选。Vue官方在2023年已将Vite列为默认推荐,Vue CLI已进入维护模式。
bash
# 推荐使用Vite创建Vue3项目
npm create vue@latest
# 或
npm create vite@latest my-app -- --template vue
(2)重视开发体验的团队
如果你的团队重视开发效率,追求"极致的开发体验",Vite的快速启动和即时HMR将显著提升开发效率。团队成员每天可能启动服务器数次,每次节省几十秒,累积起来是巨大的时间节省。
(3)中小型项目
对于中小型项目(组件数量在200个以内),Vite的轻量级和简洁性非常适合。无需复杂的Webpack配置,开箱即用。
(4)需要快速原型开发
Vite的快速启动特性使其非常适合快速原型开发和概念验证(POC)。你可以在几秒钟内启动一个开发环境,快速验证想法。
(5)TypeScript项目
Vite原生支持TypeScript,无需额外配置插件。它使用esbuild编译TypeScript(只做类型擦除,不进行类型检查),速度极快。
5.2 选择Vue CLI的场景
以下场景仍然可以考虑使用Vue CLI:
(1)需要兼容IE11或旧版浏览器
如果你的项目必须支持IE11或其他非常旧的浏览器,Vue CLI配合Babel的polyfill方案是更好的选择。Vite不支持这些旧浏览器。
(2)维护现有的大型Vue CLI项目
如果你正在维护一个已经使用Vue CLI的大型项目,而且项目运行稳定,没有必要立即迁移。迁移本身需要投入时间,需要评估投入产出比。
(3)团队对Webpack有深度依赖
如果你的团队对Webpack非常熟悉,项目中有大量自定义的Webpack配置和插件,短期内在Vue CLI上继续开发可能更高效。
(4)使用了大量Vue CLI专属插件
如果你的项目依赖了大量Vue CLI专属的插件,而这些插件在Vite生态中没有对应的替代品,迁移成本会比较高。
5.3 决策流程图
#mermaid-svg-62TpgdgSneKBIQY2{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-62TpgdgSneKBIQY2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-62TpgdgSneKBIQY2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-62TpgdgSneKBIQY2 .error-icon{fill:#552222;}#mermaid-svg-62TpgdgSneKBIQY2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-62TpgdgSneKBIQY2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-62TpgdgSneKBIQY2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-62TpgdgSneKBIQY2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-62TpgdgSneKBIQY2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-62TpgdgSneKBIQY2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-62TpgdgSneKBIQY2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-62TpgdgSneKBIQY2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-62TpgdgSneKBIQY2 .marker.cross{stroke:#333333;}#mermaid-svg-62TpgdgSneKBIQY2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-62TpgdgSneKBIQY2 p{margin:0;}#mermaid-svg-62TpgdgSneKBIQY2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-62TpgdgSneKBIQY2 .cluster-label text{fill:#333;}#mermaid-svg-62TpgdgSneKBIQY2 .cluster-label span{color:#333;}#mermaid-svg-62TpgdgSneKBIQY2 .cluster-label span p{background-color:transparent;}#mermaid-svg-62TpgdgSneKBIQY2 .label text,#mermaid-svg-62TpgdgSneKBIQY2 span{fill:#333;color:#333;}#mermaid-svg-62TpgdgSneKBIQY2 .node rect,#mermaid-svg-62TpgdgSneKBIQY2 .node circle,#mermaid-svg-62TpgdgSneKBIQY2 .node ellipse,#mermaid-svg-62TpgdgSneKBIQY2 .node polygon,#mermaid-svg-62TpgdgSneKBIQY2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-62TpgdgSneKBIQY2 .rough-node .label text,#mermaid-svg-62TpgdgSneKBIQY2 .node .label text,#mermaid-svg-62TpgdgSneKBIQY2 .image-shape .label,#mermaid-svg-62TpgdgSneKBIQY2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-62TpgdgSneKBIQY2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-62TpgdgSneKBIQY2 .rough-node .label,#mermaid-svg-62TpgdgSneKBIQY2 .node .label,#mermaid-svg-62TpgdgSneKBIQY2 .image-shape .label,#mermaid-svg-62TpgdgSneKBIQY2 .icon-shape .label{text-align:center;}#mermaid-svg-62TpgdgSneKBIQY2 .node.clickable{cursor:pointer;}#mermaid-svg-62TpgdgSneKBIQY2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-62TpgdgSneKBIQY2 .arrowheadPath{fill:#333333;}#mermaid-svg-62TpgdgSneKBIQY2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-62TpgdgSneKBIQY2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-62TpgdgSneKBIQY2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-62TpgdgSneKBIQY2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-62TpgdgSneKBIQY2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-62TpgdgSneKBIQY2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-62TpgdgSneKBIQY2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-62TpgdgSneKBIQY2 .cluster text{fill:#333;}#mermaid-svg-62TpgdgSneKBIQY2 .cluster span{color:#333;}#mermaid-svg-62TpgdgSneKBIQY2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-62TpgdgSneKBIQY2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-62TpgdgSneKBIQY2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-62TpgdgSneKBIQY2 .icon-shape,#mermaid-svg-62TpgdgSneKBIQY2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-62TpgdgSneKBIQY2 .icon-shape p,#mermaid-svg-62TpgdgSneKBIQY2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-62TpgdgSneKBIQY2 .icon-shape .label rect,#mermaid-svg-62TpgdgSneKBIQY2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-62TpgdgSneKBIQY2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-62TpgdgSneKBIQY2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-62TpgdgSneKBIQY2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否,维护老项目
是
否
Vue CLI
Vite
小型项目
中型项目
大型项目
低依赖
高依赖
是
否
开始新项目/选择脚手架
是全新项目吗?
需要兼容IE11吗?
项目当前使用什么?
选择Vue CLI
配置Babel polyfill
选择Vite
Vue官方推荐
项目规模多大?
继续使用Vite
无需迁移
考虑迁移到Vite
迁移成本低,收益明显
团队对Webpack依赖程度?
是否有迫切的性能问题?
迁移到Vite
分阶段进行
暂维持Vue CLI
等待迁移时机
制定迁移计划
评估投入产出
维持Vue CLI
稳定优先
六、从Vue CLI迁移到Vite实战指南
6.1 迁移前的准备工作
在开始迁移之前,建议完成以下准备工作:
(1)评估项目现状
bash
# 检查项目依赖
npm list --depth=0
# 检查Vue CLI插件
cat package.json | grep "@vue/cli-plugin"
# 检查自定义Webpack配置
cat vue.config.js
(2)检查兼容性
- 确认所有团队成员使用的Node.js版本 >= 18
- 确认项目不再需要支持IE11
- 确认所有依赖包都有ESM版本或兼容Vite
(3)创建迁移分支
bash
# 创建迁移分支
git checkout -b migrate-to-vite
# 备份当前配置
cp vue.config.js vue.config.js.bak
cp babel.config.js babel.config.js.bak
6.2 迁移步骤详解
第一步:移除Vue CLI相关依赖
bash
# 移除Vue CLI相关包
npm uninstall @vue/cli-service @vue/cli-plugin-babel @vue/cli-plugin-router @vue/cli-plugin-vuex @vue/cli-plugin-eslint
# 移除Babel相关配置依赖
npm uninstall babel-eslint @vue/cli-plugin-babel
第二步:安装Vite及Vue插件
bash
# 安装Vite和Vue插件
npm install -D vite @vitejs/plugin-vue
# 如果使用了JSX,安装JSX插件
npm install -D @vitejs/plugin-vue-jsx
第三步:创建vite.config.js
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
server: {
port: 5173,
// 如果之前有代理配置,迁移到这里
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
assetsDir: 'static',
rollupOptions: {
output: {
manualChunks: {
vendor: ['vue', 'vue-router', 'pinia']
}
}
}
}
})
第四步:移动index.html到根目录
bash
# Vue CLI的index.html在public目录下
# Vite需要index.html在根目录
cp public/index.html ./index.html
# 修改index.html,移除Vue CLI特有的占位符
修改后的index.html:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>我的应用</title>
</head>
<body>
<div id="app"></div>
<!-- 关键改动:添加type="module",指向src/main.js -->
<script type="module" src="/src/main.js"></script>
</body>
</html>
第五步:修改package.json中的脚本
json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.ts,.tsx --fix"
}
}
第六步:处理环境变量
Vue CLI使用process.env.VUE_APP_*,Vite使用import.meta.env.VITE_*:
bash
# 批量重命名环境变量
# 将 .env 文件中的 VUE_APP_ 替换为 VITE_
# 在代码中全局替换
# process.env.VUE_APP_API_URL 改为 import.meta.env.VITE_API_URL
创建.env文件:
bash
# .env.development
VITE_API_URL=http://localhost:3000/api
VITE_APP_TITLE=开发环境
# .env.production
VITE_API_URL=https://api.example.com
VITE_APP_TITLE=生产环境
在代码中使用:
javascript
// 之前(Vue CLI)
const apiUrl = process.env.VUE_APP_API_URL
// 之后(Vite)
const apiUrl = import.meta.env.VITE_API_URL
第七步:处理require语法
Vite只支持ES模块(import/export),不支持CommonJS(require/module.exports)。需要将代码中的require改为import:
javascript
// 之前(Vue CLI支持)
const logo = require('@/assets/logo.png')
const config = require('./config.json')
// 之后(Vite)
import logo from '@/assets/logo.png'
import config from './config.json'
第八步:移除Babel配置
删除babel.config.js文件。Vite使用esbuild进行代码转换,不需要Babel。
bash
rm babel.config.js
第九步:处理.vue文件中的资源引用
Vite支持通过new URL方式引用资源:
html
<!-- 之前(Vue CLI) -->
<img src="@/assets/logo.png" />
<!-- Vite同样支持,但推荐使用 -->
<script setup>
import logo from '@/assets/logo.png'
</script>
<template>
<img :src="logo" />
</template>
6.3 常见问题与解决方案
问题1:迁移后某些静态资源404
原因:Vue CLI中静态资源放在public目录,引用时使用绝对路径;
Vite中同样资源放在public目录,但根路径处理方式不同。
解决:
1. 确保public目录下的资源使用绝对路径引用(如 /favicon.ico)
2. 不要在src代码中使用 public/ 前缀
问题2:全局引入的CSS/SCSS变量失效
原因:Vue CLI通过css.loaderOptions注入全局变量,Vite的配置方式不同。
解决(vite.config.js):
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`
}
}
}
问题3:require.context 无法使用
原因:Vite不支持Webpack的require.context。
解决:使用Vite的import.meta.glob替代:
// 之前
const modules = require.context('./modules', true, /\.js$/)
// 之后
const modules = import.meta.glob('./modules/**/*.js', { eager: true })
问题4:vue.config.js中的configureWebpack配置需要迁移
解决:需要将Webpack插件转换为Vite/Rollup插件。
大多数常用Webpack插件都有对应的Vite版本或替代方案。
6.4 迁移后的验证
迁移完成后,需要进行全面验证:
bash
# 1. 启动开发服务器
npm run dev
# 2. 检查所有页面是否正常渲染
# 手动浏览所有主要页面
# 3. 检查所有功能是否正常
# 登录、数据请求、表单提交等
# 4. 构建生产版本
npm run build
# 5. 预览生产构建
npm run preview
# 6. 运行代码检查
npm run lint
# 7. 运行测试(如果有)
npm run test
迁移验证清单:
| 验证项 | 检查内容 | 状态 |
|---|---|---|
| 开发服务器 | 能否正常启动,HMR是否工作 | |
| 页面渲染 | 所有页面是否正常显示 | |
| 路由功能 | 页面跳转是否正常 | |
| API请求 | 接口调用是否正常,代理是否生效 | |
| 样式渲染 | CSS/SCSS是否正常加载 | |
| 静态资源 | 图片、字体等是否正常加载 | |
| 环境变量 | 不同环境的变量是否正确 | |
| 生产构建 | 构建是否成功,产物大小是否合理 | |
| 第三方库 | 所有第三方库是否正常工作 | |
| 代码规范 | ESLint/Prettier是否正常工作 |
七、实战建议与最佳实践
7.1 项目初始化最佳实践
(1)使用create-vue创建项目
bash
# 官方推荐的创建方式
npm create vue@latest
# 交互式选择项目配置
✔ Project name: ... my-vue3-app
✔ Add TypeScript? ... Yes
✔ Add JSX Support? ... No
✔ Add Vue Router for Single Page Application development? ... Yes
✔ Add Pinia for state management? ... Yes
✔ Add Vitest for Unit Testing? ... Yes
✔ Add an End-to-End Testing Solution? ... Playwright
✔ Add ESLint for code quality? ... Yes
✔ Add Prettier for code formatting? ... Yes
(2)配置路径别名
javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
'@components': resolve(__dirname, 'src/components'),
'@views': resolve(__dirname, 'src/views'),
'@stores': resolve(__dirname, 'src/stores'),
'@utils': resolve(__dirname, 'src/utils'),
'@assets': resolve(__dirname, 'src/assets'),
'@api': resolve(__dirname, 'src/api'),
}
}
})
(3)配置自动导入(可选但推荐)
bash
npm install -D unplugin-auto-import unplugin-vue-components
javascript
// vite.config.js
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: 'src/auto-imports.d.ts'
}),
Components({
dts: 'src/components.d.ts'
})
]
})
7.2 开发环境配置优化
(1)开发服务器配置
javascript
// vite.config.js
export default defineConfig({
server: {
port: 5173, // 端口号
strictPort: false, // 端口被占用时不报错,自动尝试下一个
open: true, // 自动打开浏览器
host: '0.0.0.0', // 监听所有网络接口(方便移动端调试)
cors: true, // 启用CORS
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
(2)CSS预处理器配置
javascript
// vite.config.js
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
// 全局注入变量和mixins
additionalData: `
@use "@/styles/variables.scss" as *;
@use "@/styles/mixins.scss" as *;
`
},
less: {
// 全局注入Less变量
modifyVars: {
'primary-color': '#42b883'
},
javascriptEnabled: true
}
},
// CSS Modules的行为配置
modules: {
localsConvention: 'camelCaseOnly'
}
}
})
(3)静态资源处理
javascript
// vite.config.js
export default defineConfig({
// 静态资源处理阈值
// 小于此值的资源会被内联为base64
assetsInlineLimit: 4096, // 4KB
})
7.3 生产构建优化
(1)代码分割策略
javascript
// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// 将node_modules中的包按类别分割
if (id.includes('node_modules')) {
// Vue核心生态
if (id.includes('vue') || id.includes('pinia') || id.includes('vue-router')) {
return 'vue-vendor'
}
// UI组件库
if (id.includes('element-plus') || id.includes('ant-design-vue')) {
return 'ui-vendor'
}
// 工具库
if (id.includes('lodash') || id.includes('axios') || id.includes('dayjs')) {
return 'utils-vendor'
}
// 其他第三方库
return 'vendor'
}
}
}
}
}
})
(2)压缩优化
javascript
// vite.config.js
export default defineConfig({
build: {
// 使用terser进行更精细的压缩控制
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // 移除console
drop_debugger: true, // 移除debugger
pure_funcs: ['console.log'] // 移除特定函数调用
},
format: {
comments: false // 移除注释
}
},
// 生成sourcemap(生产环境建议关闭或使用hidden模式)
sourcemap: false,
// chunk大小警告阈值(KB)
chunkSizeWarningLimit: 2000
}
})
(3)构建分析
bash
# 安装构建分析插件
npm install -D rollup-plugin-visualizer
javascript
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
vue(),
// 生成构建分析报告
visualizer({
open: true, // 自动打开报告
gzipSize: true, // 显示gzip大小
brotliSize: true, // 显示brotli大小
filename: 'dist/stats.html' // 报告文件路径
})
]
})
7.4 团队协作建议
(1)统一Node.js版本
在项目根目录创建.nvmrc文件,锁定Node.js版本:
18.20.0
或使用package.json中的engines字段:
json
{
"engines": {
"node": ">=18.0.0"
}
}
(2)统一包管理器
在项目根目录创建.npmrc文件,锁定包管理器:
engine-strict=true
并在package.json中指定:
json
{
"packageManager": "pnpm@9.0.0"
}
(3)Vite配置管理建议
对于团队项目,建议将Vite配置拆分为多个文件:
vite.config.js # 基础配置
vite.config.dev.js # 开发环境配置
vite.config.prod.js # 生产环境配置
javascript
// vite.config.js
import { defineConfig } from 'vite'
import baseConfig from './vite.config.base'
import devConfig from './vite.config.dev'
import prodConfig from './vite.config.prod'
export default defineConfig(({ mode }) => {
if (mode === 'development') {
return { ...baseConfig, ...devConfig }
}
return { ...baseConfig, ...prodConfig }
})
(4)Git提交前检查
使用husky和lint-staged确保代码质量:
bash
npm install -D husky lint-staged
npx husky init
json
// package.json
{
"lint-staged": {
"*.{vue,js,ts,jsx,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{css,scss,less}": [
"prettier --write"
]
}
}
(5)CI/CD构建优化
在CI/CD环境中,可以利用Vite的缓存机制加速构建:
yaml
# .github/workflows/deploy.yml
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Cache build output
uses: actions/cache@v3
with:
path: |
dist
node_modules/.vite
key: ${{ runner.os }}-build-${{ github.sha }}
八、总结
8.1 核心结论
Vite和Vue CLI的对比,本质上不是两个脚手架工具的对决,而是两种构建理念的较量:全量打包(Bundle-based)与按需编译(Native ESM-based)。
Vite通过利用浏览器原生ES模块支持,实现了开发体验的质的飞跃:
- 冷启动速度从数十秒缩短到数百毫秒
- HMR从数秒缩短到数十毫秒
- 配置复杂度大幅降低
Vue CLI作为Vue生态的"老兵",在稳定性、浏览器兼容性、插件生态方面仍有优势,但它的技术路线已经走到了尽头------Vue官方已明确表示Vue CLI进入维护模式,不再开发新功能。
8.2 行动建议
| 你的情况 | 建议 |
|---|---|
| 启动全新Vue3项目 | 毫不犹豫选择Vite |
| 维护中小型Vue CLI项目 | 评估迁移到Vite |
| 维护大型Vue CLI项目 | 制定分阶段迁移计划 |
| 需要兼容IE11 | 暂时使用Vue CLI,同时寻找替代方案 |
| 团队刚接触Vue3 | 直接从Vite开始学习 |
8.3 关键要点回顾
- Vite是Vue3官方推荐的默认脚手架,Vue CLI已进入维护模式
- Vite的核心优势在于开发体验:极速冷启动、即时HMR、简洁配置
- Vite的底层原理是"按需编译",利用浏览器原生ESM,避免了全量打包
- Vue CLI的底层是Webpack,成熟稳定,但构建速度慢,配置复杂
- 对于新项目,Vite是最佳选择;对于老项目,需要评估迁移成本
- 迁移过程并不复杂,大多数中小型项目可以在半天内完成迁移
- Vite的插件生态正在快速追赶,大多数常用场景都有对应的解决方案
- 生产构建方面,Vite基于Rollup,生成的代码更小、更高效
8.4 展望
前端构建工具的演进从未停止。从Grunt到Gulp,从Webpack到Parcel,再到现在的Vite和Turbopack,每一次变革都是为了更好的开发体验。Vite代表了当前前端构建工具的最高水平,但它也不是终点。
未来,随着浏览器能力的不断增强,构建工具可能会进一步简化。也许有一天,我们不再需要构建工具,浏览器可以直接运行所有源码。但在那一天到来之前,Vite无疑是我们最好的选择。
本文是《Vue3从入门到精通》系列专栏的第十四篇文章。 现在你已经全面了解了Vite和Vue CLI的差异、各自的优劣势以及如何在不同场景下做出选择。掌握了脚手架工具后,下一篇文章我们将深入Vue3的模板语法,系统学习Vue3的所有指令和模板相关功能。
下一篇预告:《Vue3模板语法全解:从插值到指令》------全面学习Vue3模板语法的所有用法,包括文本插值、属性绑定、事件处理、条件渲染、列表渲染等核心内容。
系列文章导航:
- 第一篇:从零开始学Vue3:一篇文章带你走进Vue的世界
- 第十三篇:第一个Vue3程序:Hello World从零开始
- 第十四篇:Vue3项目脚手架:Vite vs Vue CLI怎么选?(当前文章)