摘要:本文面向 Vue 2 新手和需要重构老项目的开发者,手把手演示如何用 Vue CLI 从零搭建一个规范的 Vue 2 项目,并进一步把 Webpack 构建迁移到 Vite,体验秒级启动与热更新带来的开发效率提升。全流程已实测通过:每一段代码、每一条命令都在真实项目中跑过并验证了浏览器渲染结果。
前言
虽然 Vue 3 已经发布多时,但在实际开发和维护中,Vue 2 依然占据着巨大的市场份额。对于新手或需要重构老项目的开发者来说,如何从零搭建一个规范的 Vue 2 项目是必备技能。
本文将带你从零开始,使用官方脚手架 Vue CLI 搭建标准 Vue 2 项目,并在最后教你如何将 Webpack 替换为 Vite,体验极速启动的快乐。
⚠️ 关于 Vue 2 的生命周期:Vue 2.7.16 是 Vue 2 的最后一个版本,已于 2023-12-31 停止维护,不再有安全更新。存量项目维护没问题,但如果这是全新项目且需要长期演进,建议直接上 Vue 3。本文针对的是「必须用 Vue 2」的场景。
第一阶段:环境准备与基础搭建
第一步:环境准备
- 安装 Node.js(建议 18 LTS 及以上):下载地址
- 安装 Git:下载地址
Node 自带 npm,无需单独下载。验证安装:
node -v npm -v能正常显示版本号,说明环境准备就绪。
第二步:全局安装 Vue CLI
npm install -g @vue/cli第三步:创建 Vue 2 项目
在目标文件夹下执行:
vue create my-vue2-project进入交互式界面后,关键选择如下:
| 选项 | 选择 | 原因 |
|---|---|---|
| 预设 | Manually select features | 默认是 Vue 3,要手动选功能 |
| 功能 | 勾选 Babel、Router、Vuex、ESLint | 核心插件 |
| Vue 版本 | 2.x | ⚠️ 最关键的一步,务必选 2.x |
| 路由模式 | Y(History 模式) | 单页应用推荐,URL 无# |
| CSS 预处理器 | 按需(Less / Sass / Stylus) | 后续 Vite 也需要对应编译包 |
| Linter 配置 | ESLint + Standard config | 本文后续会升级为 ESLint 9 |
| 校验时机 | Lint on save | 保存时检查 |
| 配置文件位置 | In dedicated config files | 独立配置文件,结构更清晰 |
等待依赖安装完成,项目创建好了。
第四步:启动项目
cd my-vue2-project npm run serve终端会显示访问地址(通常是http://localhost:8080)。
初始项目结构速览:
public/index.html:页面模板(Vue CLI 特有)src/main.js:入口,初始化 Vue 实例vue.config.js:Webpack 配置(迁移时要删)babel.config.js:Babel 配置(迁移时要删)
第二阶段:迁移到 Vite 核心实战
Vue CLI 基于 Webpack,项目变大后启动和热更新会明显变慢。Vite 用原生 ESM,启动是秒级的。
⚠️ 迁移前必读:两个“看不见的坑”
在动手前,先说清楚两个照着错误教程做会掉进去的坑:
💣 坑 A:Dev 白屏,但 Prod 正常
原项目src/router/index.js里有这么一行:
base: process.env.BASE_URL, // ← 这是 Webpack 的写法Vite 里没有process.env这个对象。后果是:
- Dev 模式:直接抛
ReferenceError: process is not defined,页面完全空白。 - Prod 模式:Vite 构建时把
process.env替换成{},于是base静默变成undefined——不报错,但 base 配置丢了,部署到子路径时 404。
最坑的地方在于 Prod 能跑,测试很容易漏过去。必须手动改。
💣 坑 B:搜process.env.VUE_APP_搜不到它
网上很多教程说「全局搜索process.env.VUE_APP_全部替换」。但上面那行是process.env.BASE_URL,不带VUE_APP_前缀,按这个模式搜索会被整个漏掉。
正确的搜索关键词是process.env.(不带前缀)。
第一步:改写 package.json
删除所有 Vue CLI 相关依赖(@vue/cli-plugin-*、vue-template-compiler),以及这些在 Vite 下完全用不到的包:
@babel/core、@babel/eslint-parser—— Vite 用 esbuild 转译。less-loader——Webpack 的 loader,Vite 直接用less,留着纯属多余。@vue/eslint-config-standard——vue-cli 专属,依赖 Webpack 体系。
同时必须把 Vue 版本升到^2.7.16:@vitejs/plugin-vue2@2.3.x的 peer 要求是vue: ^2.7.0-0,而 vue create 生成的是^2.6.14——一旦命中 2.6.x 就会构建失败。
最终package.json参考:
{ "name": "my-vue2-project", "type": "module", "engines": { "node": ">=18.0.0" }, "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview", "lint": "eslint .", "lint:fix": "eslint . --fix" }, "dependencies": { "vue": "^2.7.16", "vue-router": "^3.6.5", "vuex": "^3.6.2" }, "devDependencies": { "@vitejs/plugin-vue2": "^2.3.4", "eslint": "^9.39.5", "eslint-plugin-vue": "^10.11.1", "less": "^4.9.1", "neostandard": "^0.14.1", "vite": "^5.4.21", "vue-eslint-parser": "^10.4.1" } }💡
neostandard是eslint-config-standard的现代继任者,完美支持 ESLint 9/10。
第二步:删除 Vue CLI 残留文件
rm babel.config.js vue.config.js .eslintrc.js⚠️
vue.config.js一定要删。它留着不影响 Vite,但会误导后来的人以为还在用 Webpack。
第三步:移动 index.html 并清理 EJS 语法
Vue CLI 用public/index.html,Vite 要求index.html在项目根目录。
mv public/index.html index.html原文件里有两处 EJS 语法必须改:<%= BASE_URL %>favicon.ico改为/favicon.ico;标题可以直接写死,也可以用 Vite 的环境变量占位符。
Vite 的 HTML 环境变量语法是%变量名%(不含空格、不带=):
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <link rel="icon" href="/favicon.ico" /> <title>%VITE_APP_TITLE%</title> </head> <body> <div id="app"></div> <script type="module" src="/src/main.js"></script> </body> </html>💡 很多人会写成
<%= VITE_APP_TITLE %>(EJS 风格),这样不会生效——Vite 的匹配规则是/%(\S+?)%/g,中间不允许有空格。写错时不报错,只是占位符原样留在页面上。
第四步:创建 vite.config.js
在项目根目录新建vite.config.js,保持与 Vue CLI 一致的@别名和端口习惯,同时把代理和环境变量读取一并配好:
import { fileURLToPath, URL } from 'node:url' import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue2' export default defineConfig(({ mode }) => { // loadEnv 的第三个参数传 '' 表示读取全部变量(含仅构建期使用的) const env = loadEnv(mode, process.cwd(), '') return { plugins: [vue()], resolve: { alias: { // ESM 里没有 __dirname,要用 import.meta.url 换算 '@': fileURLToPath(new URL('./src', import.meta.url)) } }, server: { port: Number(env.DEV_PORT) || 8080, proxy: { '/api': { target: env.API_PROXY_TARGET || 'http://localhost:3000', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') } } }, build: { target: 'es2015', rollupOptions: { output: { manualChunks: { vue: ['vue', 'vue-router', 'vuex'] } } } } } })⚠️关于
__dirname的坑:网上常见的写法是path.resolve(__dirname, 'src')。加上"type": "module"并改用import.meta.url,才能彻底消除 CJS 警告。
第五步:调整源码与环境变量
- src/main.js:保持原有的 Vue 2 实例化写法即可(
new Vue(...))。 - 环境变量替换:
process.env.VUE_APP_XXX改为import.meta.env.VITE_XXX,并把.env文件里的变量前缀改为VITE_。 - 路由 base:
process.env.BASE_URL改为import.meta.env.BASE_URL(Vite 内置提供,无需自己定义)。
第六步:清理并重新安装
删除原来的node_modules和package-lock.json(或yarn.lock),然后重新安装并启动:
npm install npm run dev第三阶段:实战避坑指南(常见报错解决)
在迁移过程中,由于网络环境或依赖版本变动,很容易遇到以下报错,以下是解决方案:
💥 坑 1:npm install 报错 ERESOLVE unable to resolve dependency tree
原因:ESLint 配置包与插件版本不兼容(如@vue/eslint-config-standard要求eslint-plugin-vue@^7.0.0,而项目里装成了 8.x)。
解决:不要盲目用--legacy-peer-deps掩盖问题。正确做法是移除@vue/eslint-config-standard这类 vue-cli 专属包,升级到 ESLint 9 Flat Config +neostandard,从根源上消除冲突。
💥 坑 2:npm install 报错 network read ECONNRESET
原因:国内网络环境连接 npm 官方源不稳定,连接被重置。
解决:切换为淘宝(阿里)镜像源。
npm config set registry https://registry.npmmirror.com配置后重新执行npm install即可。
💥 坑 3:页面白屏或控制台报错 process is not defined
原因:Vite 里没有process.env这个 Node.js 环境变量对象。
解决:全局搜索process.env.,按变量类型分别替换为import.meta.env.VITE_XXX或import.meta.env.BASE_URL。
💥 坑 4:启动时报错找不到 less 或 sass
原因:Vite 内置了预处理器支持,但不会自动安装对应的编译包;同时less-loader是 Webpack 专属,Vite 下不需要。
解决:只装编译包本身(以 less 为例)。
npm install less -D💥 坑 5:jsconfig.json 满屏红色波浪线
原因:VS Code 的类型检查无法解析 Vite 的特殊别名或import.meta环境变量。
解决:不要直接关闭检查,而是补全jsconfig.json的types和paths:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"] }, "types": ["vite/client"] }, "exclude": ["node_modules", "dist"] }总结
通过以上步骤,我们成功从 0 到 1 搭建了标准的 Vue 2 项目,并顺利迁移到了 Vite 构建。遇到报错不要慌,仔细看终端的报错提示,往往就是版本冲突或语法不兼容导致的。如果在迁移过程中遇到其他具体报错,欢迎在评论区留言交流!