Vue 3 发布至今已经成为新项目的主流选择,但真正开始一个项目时,摆在团队面前的第一个问题往往不是怎么写组件,而是工程化技术栈怎么选。构建工具用 Vite 还是继续用 Webpack?脚手架是官方的 create-vue 还是社区的 Nuxt?状态管理从 Vuex 迁移到 Pinia 值不值得?TypeScript 要不要一上来就全量接入?这些决策每一个都会影响项目后续几年的维护成本。本文围绕这些核心问题逐一展开对比,并总结出一套可复用的选型决策流程。

构建工具:Vite 与 Webpack 的核心差异
Vue 3 项目目前默认推荐 Vite,但很多存量项目仍在使用基于 Webpack 的 Vue CLI,两者在底层机制上有本质区别。Webpack 在开发环境下会先把整个项目打包成 bundle 再启动开发服务器,项目越大,冷启动时间越长。而 Vite 利用了浏览器原生支持的 ES Module,开发环境下不打包,只在浏览器请求某个模块时按需编译,因此冷启动速度几乎不受项目体积影响。
热更新(HMR)方面差异同样明显。Webpack 的 HMR 会以模块粒度重新构建并推送更新,随着项目膨胀,热更新耗时也会逐渐增加。Vite 的 HMR 是基于原生 ESM 实现的,精确到单个模块,修改代码后的反馈通常是毫秒级。此外 Vite 内置了对 Vue 单文件组件、TSX、CSS 预处理器的支持,配置量远小于 Webpack。
当然 Vite 也并非完美。生产环境构建 Vite 使用 Rollup,某些依赖 CommonJS 的老库需要通过 @vitejs/plugin-legacy 或预打包处理兼容问题;如果团队有大量自定义 Webpack loader 和插件积累,迁移成本也需要评估。一个简单的判断标准:新项目直接选 Vite,没有悬念;存量项目如果构建速度已经严重影响效率,也建议逐步迁移,社区提供了 vite-plugin-webpack 等过渡方案。
// 典型的 vite.config.js 配置,Vue 3 项目通常只需要这些内容
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
port: 5173,
proxy: {
// 开发环境接口代理,解决跨域问题
'/api': {
target: 'http://127.0.0.1:3000',
changeOrigin: true
}
}
}
})脚手架与状态管理:create-vue、Nuxt 与 Pinia 的取舍
脚手架层面,官方的 create-vue 是最直接的起点,它支持在初始化时勾选 TypeScript、Router、Pinia、ESLint、测试框架等选项,生成的项目结构干净且与官方文档对齐。如果项目是重 SEO 的内容型站点或希望获得服务端渲染能力,Nuxt 3 是更合适的选择,它提供了文件路由、自动导入、服务端 API 等开箱即用的能力,但代价是学习曲线更陡,部署也相对复杂。纯管理后台或内部系统则没有必要引入 SSR,用 create-vue 加 Vue Router 即可。
状态管理方面,Pinia 已经是 Vue 3 的事实标准。相比 Vuex 4,Pinia 移除了 mutation 这一层,直接在 action 中修改状态或执行异步逻辑,代码量明显减少。TypeScript 支持也是 Pinia 的强项,它天然推导 state 类型,不需要手写复杂的类型声明。此外 Pinia 的每个 store 相互独立,天然支持代码分割,配合 Vite 可以实现路由级别的懒加载优化。
// Pinia store 定义示例:无 mutation,语法简洁
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useUserStore = defineStore('user', () => {
const token = ref('')
const userInfo = ref(null)
function setToken(val) {
token.value = val
}
async function fetchUserInfo() {
// 异步逻辑直接写在 action 中
const res = await api.getUserInfo()
userInfo.value = res.data
}
return { token, userInfo, setToken, fetchUserInfo }
})如果项目还在用 Vuex,建议在新模块中直接引入 Pinia,两者可以共存,等时机成熟再逐步替换,避免一次性大迁移带来的风险。
TypeScript、测试与规范工具链的选择
Vue 3 的源码本身就是用 TypeScript 编写的,官方类型支持非常完善。对于生命周期两年以上的项目,强烈建议接入 TypeScript。组件层面使用 <script setup lang="ts"> 组合式 API,配合 defineProps 的泛型语法可以获得完整的类型推导。如果团队 TS 经验不足,也可以先从 JSDOM 注释或局部 .ts 文件做起,渐进式迁移。
测试框架方面,Vitest 是 Vite 生态的天然搭配。它复用 Vite 的配置和转换管道,写单测不需要额外配置 loader,速度也快于 Jest。Vue 官方的 @vue/test-utils 对两者都支持,组件测试代码几乎无差别:
// 使用 Vitest + @vue/test-utils 进行组件测试
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import Counter from './Counter.vue'
describe('Counter.vue', () => {
it('点击按钮后计数加一', async () => {
const wrapper = mount(Counter)
await wrapper.find('button').trigger('click')
expect(wrapper.text()).toContain('1')
})
})代码规范上,ESLint 加 Prettier 仍是主流组合,Vue 3 项目需要使用 eslint-plugin-vue 并启用 flat/configs/vue3 规则集。建议在 package.json 中配置 lint-staged 配合 husky,在提交前自动格式化,避免规范靠口头约定。Git 提交信息可以引入 commitlint 约定式提交规范,方便后期自动生成变更日志。
一套可落地的选型决策流程
具体的技术方案敲定后,更重要的是形成一套可复用的决策方法。建议按以下流程推进:第一步,明确业务形态,判断是内容型站点、管理后台还是移动端 H5,这直接决定是否需要 SSR 和对应的脚手架;第二步,评估团队现状,包括成员对 TypeScript 的熟悉程度、存量代码的规模,避免为了追新而牺牲交付速度;第三步,考察生态成熟度,优先选择官方推荐或社区活跃度高的方案,冷门工具在遇到问题时往往找不到答案。
团队层面还可以建立一份技术选型评审清单,把构建工具、UI 组件库、状态管理、请求封装、测试方案、CI/CD 流水线逐项列出,每项标注候选方案、选择理由和放弃理由。这份文档的价值不在于约束,而在于半年后有人问为什么当时这么选时,能给出清晰的依据。
总结来说,2024 年之后启动的 Vue 3 项目,一套稳妥的默认组合是:Vite 加 create-vue 加 TypeScript 加 Pinia 加 Vitest,需要 SSR 时切换到 Nuxt 3。在这个基线上按团队能力做减法,比从零开始逐项比较要高效得多。技术选型没有绝对的最优解,只有与团队规模、项目周期、维护预期相匹配的相对最优解。