外观
vue.config.js 系统学习文档
适合人群:正在维护 Vue CLI 项目,尤其是 Vue2 老项目、Vue3 + Vue CLI 项目,或者需要理解旧项目工程配置的学习者。
学习目标:理解
vue.config.js是什么、放在哪里、常用配置怎么写、如何配置代理、路径、构建输出、Webpack 扩展、CSS 和环境变量。核对时间:2026-06-18。Vue CLI 已进入维护模式,新项目通常更推荐 Vite,但大量存量项目仍然需要理解
vue.config.js。
目录
- vue.config.js 是什么
- 它和 vite.config.ts 有什么区别
- 最小配置写法
- 常用基础配置
- 开发服务器 devServer 配置
- CSS 相关配置
- configureWebpack 与 chainWebpack
- 路径别名配置
- 多页面 pages 配置
- 环境变量在 vue.config.js 中的使用
- 常见生产环境配置
- 常见实战场景
- 初学者常见坑
- 推荐学习顺序
- 学习资源
1. vue.config.js 是什么
vue.config.js 是 Vue CLI 项目的全局配置文件。
它通常放在项目根目录:
text
my-vue-cli-app/
├── public/
├── src/
├── package.json
├── babel.config.js
└── vue.config.jsVue CLI 内部基于 Webpack。vue.config.js 的作用是让你不用直接维护完整 Webpack 配置,也能修改常见工程化行为。
它可以配置:
- 部署基础路径。
- 构建输出目录。
- 静态资源目录。
- 开发服务器端口和代理。
- CSS loader 选项。
- Webpack 别名。
- Webpack 插件。
- 多页面应用。
- source map。
- 第三方插件选项。
1.1 它在哪些项目中常见
常见于:
- Vue2 + Vue CLI 项目。
- Vue3 + Vue CLI 项目。
- 早期企业后台项目。
- 基于 Vue CLI 改造的自研脚手架。
不常见于:
- Vite 项目。
- Nuxt 项目。
- 自行搭建的纯 Webpack 项目。
1.2 vue.config.js 是怎么被加载的(内部机制)
理解加载机制,能避免很多「改了不生效」的困惑。
vue-cli-service启动时,会读取项目根目录的vue.config.js(通过 Node 的require加载,所以默认是 CommonJS 写法)。- 这个文件里的「顶层字段」(
publicPath、outputDir、devServer、css等)会被 Vue CLI 翻译成对应的底层 Webpack 配置,而不是直接拿给你一个 Webpack 配置文件。 configureWebpack里的内容会通过 webpack-merge 合并进最终 Webpack 配置;chainWebpack则用 webpack-chain 链式 API 精细修改已有的 rule/plugin。- 整个配置在
serve/build启动时一次性加载,修改vue.config.js后必须重启命令才会生效(不像.vue文件有热更新)。
想确认你的配置最终变成了什么 Webpack 配置,随时可以:
bash
vue-cli-service inspect⚠️ Vue CLI 已进入维护模式,官方不再开发新特性,只修关键 bug。新项目优先考虑 Vite;但对存量 Vue CLI 项目,理解这套机制仍然必要。
2. 它和 vite.config.ts 有什么区别
vue.config.js 属于 Vue CLI。
vite.config.ts 属于 Vite。
两者不要混用。
| 项目类型 | 配置文件 | 底层构建工具 | 常见命令 |
|---|---|---|---|
| Vue2 + Vue CLI | vue.config.js | Webpack | vue-cli-service serve |
| Vue3 + Vue CLI | vue.config.js | Webpack | vue-cli-service serve |
| Vue3 + Vite | vite.config.ts | Vite + Rollup | vite |
| Vue2 + Vite | vite.config.ts | Vite + Rollup | vite |
判断方式:
看 package.json。
Vue CLI 项目通常有:
json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
}
}Vite 项目通常有:
json
{
"scripts": {
"dev": "vite",
"build": "vite build"
}
}3. 最小配置写法
vue.config.js:
js
module.exports = {
publicPath: '/',
}Vue CLI 默认使用 CommonJS 写法,因为这个文件运行在 Node.js 环境。
也可以导出函数或根据环境变量动态返回配置,但初学阶段先掌握对象写法。
3.1 常见完整示例
js
const path = require('node:path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/admin/' : '/',
outputDir: 'dist',
assetsDir: 'static',
productionSourceMap: false,
devServer: {
host: '0.0.0.0',
port: 8080,
open: true,
proxy: {
'/api': {
target: process.env.VUE_APP_PROXY_TARGET,
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
},
configureWebpack: {
resolve: {
alias: {
'@': resolve('src'),
},
},
},
css: {
loaderOptions: {
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`,
},
},
},
}4. 常用基础配置
4.1 publicPath
部署基础路径。
js
module.exports = {
publicPath: '/',
}如果项目部署到域名根路径:
text
https://example.com/使用:
js
publicPath: '/'如果项目部署到子路径:
text
https://example.com/admin/使用:
js
publicPath: '/admin/'它会影响构建后 JS、CSS、图片等资源的引用路径。
4.2 outputDir
构建输出目录。
js
module.exports = {
outputDir: 'dist',
}默认是 dist。
4.3 assetsDir
放置构建后静态资源的目录。
js
module.exports = {
assetsDir: 'static',
}构建后可能类似:
text
dist/
├── index.html
└── static/
├── js/
├── css/
└── img/4.4 indexPath
指定生成的 index.html 路径。
js
module.exports = {
indexPath: 'index.html',
}通常不需要改。多页面或后端模板集成时可能会用到。
4.5 filenameHashing
是否在生成的静态资源文件名中包含 hash。
js
module.exports = {
filenameHashing: true,
}生产环境推荐保持开启,利于浏览器缓存。
4.6 productionSourceMap
生产构建是否生成 source map。
js
module.exports = {
productionSourceMap: false,
}常见选择:
- 内部测试环境可以打开。
- 线上生产环境通常关闭,或上传到错误监控平台但不公开。
4.7 lintOnSave
保存时是否触发 lint。
js
module.exports = {
lintOnSave: 'default',
}也可以:
js
lintOnSave: false不建议长期关闭 lint。更好的做法是修正规则或代码。
4.8 transpileDependencies
指定需要被 Babel 转译的依赖。
js
module.exports = {
transpileDependencies: ['some-esm-package'],
}常见场景:
- 某些第三方包发布了较新的语法。
- 老浏览器无法直接运行。
- 需要让 Babel 处理该依赖。
4.9 parallel
是否用 thread-loader 开启 Babel/TS 的多线程转译,默认在 CPU 核心数 > 1 时开启。
js
module.exports = {
parallel: require('node:os').cpus().length > 1,
}适用场景:
- 项目较大、转译耗时明显时保持开启。
- CI 或低配虚拟机里,多线程反而可能拖慢构建,可以显式关掉:
parallel: false。
4.10 runtimeCompiler
是否需要把 Vue 的「运行时 + 模板编译器」完整打包进来,默认 false。
js
module.exports = {
runtimeCompiler: true,
}两种构建形态:
- runtime-only(默认,体积更小):
.vue文件在构建阶段就被编译成 render 函数,运行时不需要编译器。 - runtime + compiler(
runtimeCompiler: true):允许在组件里直接写template: '<div>...</div>'字符串,但会增大包体积。
💡 除非你确实要在运行时动态编译模板(比如从接口返回模板字符串),否则保持默认
false即可,别为了「兼容」盲目开启。
5. 开发服务器 devServer 配置
devServer 底层对应 webpack-dev-server。
5.1 端口、host、自动打开
js
module.exports = {
devServer: {
host: '0.0.0.0',
port: 8080,
open: true,
},
}含义:
host: '0.0.0.0':允许局域网访问。port: 8080:固定端口。open: true:启动后自动打开浏览器。
5.2 配置代理
开发环境常用代理解决跨域。
js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: {
'^/api': '',
},
},
},
},
}业务代码:
js
axios.get('/api/users')实际流程:
text
浏览器 -> Vue CLI dev server -> 后端 http://localhost:3000/users5.3 使用环境变量配置代理地址
.env.development:
env
VUE_APP_PROXY_TARGET=http://localhost:3000vue.config.js:
js
module.exports = {
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_PROXY_TARGET,
changeOrigin: true,
},
},
},
}注意:修改 .env 或 vue.config.js 后,需要重启开发服务器。
5.4 history 路由刷新
Vue Router 使用 history 模式时,本地刷新子路由可能需要 fallback。
Vue CLI 通常已经做了相应处理。如果你定制 devServer 后出现刷新 404,可以检查 webpack-dev-server 的 history fallback 相关配置。
生产环境也要在 Nginx 或服务器上配置:
nginx
location / {
try_files $uri $uri/ /index.html;
}5.5 devServer 其他常用选项
devServer 直接透传 webpack-dev-server 的配置,以下是除端口、代理外的高频项:
js
module.exports = {
devServer: {
https: true, // 本地 HTTPS
allowedHosts: ['localhost', '.example.com'], // 白名单,防 DNS rebinding 攻击
headers: { // 自定义响应头
'X-Custom-Header': 'hello',
},
client: {
overlay: { errors: true, warnings: false }, // 编译错误覆盖层
},
historyApiFallback: true, // history 路由回退(默认已开)
},
}https:需要本地调试 HTTPS 相关能力(如 PWA、跨域 cookie)时开启。allowedHosts:默认只允许本机访问;用局域网 IP 或自定义域名访问时报Invalid Host header,就是这里要放行。client.overlay:编译报错时全屏遮罩提示,团队里有人嫌烦可以只关 warnings。historyApiFallback:Vue Router history 模式下刷新子路由 404 的回退,Vue CLI 默认已经处理,一般不用改。
6. CSS 相关配置
6.1 css.extract
是否提取 CSS 到独立文件。
js
module.exports = {
css: {
extract: process.env.NODE_ENV === 'production',
},
}生产环境通常提取,开发环境通常注入 style 便于热更新。
6.2 css.sourceMap
是否为 CSS 生成 source map。
js
module.exports = {
css: {
sourceMap: false,
},
}调试样式时可以打开,但会增加构建成本。
6.3 css.loaderOptions
给 CSS 相关 loader 传选项。
Sass 全局变量:
js
module.exports = {
css: {
loaderOptions: {
scss: {
additionalData: `@use "@/styles/variables.scss" as *;`,
},
},
},
}Less 全局变量:
js
module.exports = {
css: {
loaderOptions: {
less: {
lessOptions: {
modifyVars: {
'primary-color': '#42b883',
},
javascriptEnabled: true,
},
},
},
},
}6.4 不要滥用全局注入
适合全局注入:
- Sass 变量。
- mixin。
- function。
不适合全局注入:
- 大量真实 CSS。
- reset 样式。
- 组件样式。
真实 CSS 应该通过入口文件引入:
js
import '@/styles/index.scss'7. configureWebpack 与 chainWebpack
Vue CLI 给了两种扩展 Webpack 的方式。
7.1 configureWebpack
适合简单合并配置。
对象写法:
js
module.exports = {
configureWebpack: {
resolve: {
alias: {
'@': require('node:path').resolve(__dirname, 'src'),
},
},
},
}函数写法:
js
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config.devtool = false
}
},
}7.2 chainWebpack
适合精细修改内部 Webpack 配置。
它使用 webpack-chain API。
js
module.exports = {
chainWebpack: config => {
config.resolve.alias.set('@', require('node:path').resolve(__dirname, 'src'))
},
}7.3 什么时候用哪个
优先级建议:
- 简单新增配置:用
configureWebpack。 - 需要修改已有 loader/plugin:用
chainWebpack。 - 能用 Vue CLI 顶层配置解决,就不要改底层 Webpack。
7.4 查看最终 Webpack 配置
可以使用:
bash
vue-cli-service inspect输出到文件:
bash
vue-cli-service inspect > webpack.config.output.js在改 chainWebpack 前,建议先看最终配置里对应 rule/plugin 的名字。
7.5 configureWebpack 的合并语义(内部机制)
configureWebpack 的「对象」和「函数」两种写法,合并行为不一样:
- 对象写法:通过 webpack-merge 把对象合并进 Vue CLI 生成好的配置,你写的同名字段会覆盖默认值。
- 函数写法:接收 Vue CLI 已经生成好的
config,你在函数里直接改(或返回一个新对象让 Vue CLI 再 merge)。
js
module.exports = {
configureWebpack: config => {
// 此时 config 已经是完整的 Webpack 配置
if (process.env.NODE_ENV === 'production') {
config.devtool = false
}
return config // 返回 undefined 表示「不改」;返回对象则 merge
},
}为什么需要两种:
- 对象适合「无条件新增/覆盖」。
- 函数适合「按环境、按条件」改配置,因为你能拿到最终 config 和
process.env.NODE_ENV。
⚠️ 注意 merge 的粒度:普通对象字段是「覆盖」,但数组(如
plugins)按索引合并,删减数组项容易踩坑。要精确增删 plugin/loader,用chainWebpack的.delete()/.use()更可靠。
8. 路径别名配置
常见别名:
js
const path = require('node:path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
configureWebpack: {
resolve: {
alias: {
'@': resolve('src'),
'@components': resolve('src/components'),
'@utils': resolve('src/utils'),
},
},
},
}使用:
js
import UserCard from '@components/UserCard.vue'
import { formatDate } from '@utils/date'8.1 TypeScript 项目要同步 tsconfig
tsconfig.json:
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"]
}
}
}否则项目可能能运行,但编辑器和类型检查报错。
9. 多页面 pages 配置
Vue CLI 默认是单页面应用。如果要做多页面,可以使用 pages。
js
module.exports = {
pages: {
index: {
entry: 'src/pages/index/main.js',
template: 'public/index.html',
filename: 'index.html',
title: '首页',
},
admin: {
entry: 'src/pages/admin/main.js',
template: 'public/admin.html',
filename: 'admin.html',
title: '后台',
},
},
}目录结构:
text
src/
└── pages/
├── index/
│ └── main.js
└── admin/
└── main.js多页面适合:
- 后台和前台完全分离。
- 多个独立入口。
- 老系统逐步迁移。
不适合:
- 普通 Vue Router 单页面项目。
10. 环境变量在 vue.config.js 中的使用
Vue CLI 会加载 .env 文件。
在客户端代码中,只有这些变量会被嵌入:
NODE_ENV。BASE_URL。- 以
VUE_APP_开头的变量。
在 vue.config.js 中,可以读取:
js
process.env.NODE_ENV
process.env.VUE_APP_API_BASE_URL
process.env.VUE_APP_PROXY_TARGET示例:
js
module.exports = {
publicPath: process.env.VUE_APP_PUBLIC_PATH || '/',
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_PROXY_TARGET,
changeOrigin: true,
},
},
},
}10.1 不要在前端 env 中放秘密
下面这种变量不能放进前端 .env:
env
VUE_APP_DB_PASSWORD=123456
VUE_APP_SECRET_KEY=abcdef原因:
- 前端构建产物会被用户下载。
- 以
VUE_APP_开头的变量会被嵌入客户端代码。 - 用户可以从源码或构建产物中找到它们。
真正的密钥应该放在服务端。
11. 常见生产环境配置
11.1 部署到子路径
js
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/admin/' : '/',
}如果 Vue Router 使用 history:
js
const router = new VueRouter({
mode: 'history',
base: '/admin/',
routes,
})11.2 关闭生产 source map
js
module.exports = {
productionSourceMap: false,
}11.3 配置 splitChunks
js
module.exports = {
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'all',
},
},
},
}不要上来就写复杂拆包规则。先用 bundle analyzer 看结果,再决定是否定制。
11.4 Bundle Analyzer
安装:
bash
npm install webpack-bundle-analyzer -D配置:
js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
configureWebpack: config => {
if (process.env.ANALYZE) {
config.plugins.push(new BundleAnalyzerPlugin())
}
},
}运行:
bash
ANALYZE=true npm run buildWindows PowerShell:
powershell
$env:ANALYZE='true'; npm run build12. 常见实战场景
12.1 开发环境代理多个后端服务
js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
},
'/upload': {
target: 'http://localhost:4000',
changeOrigin: true,
},
},
},
}12.2 给项目加版本号
js
const webpack = require('webpack')
const pkg = require('./package.json')
module.exports = {
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
__APP_VERSION__: JSON.stringify(pkg.version),
}),
],
},
}业务代码:
js
console.log(__APP_VERSION__)12.3 移除 prefetch
有些项目会移除默认 prefetch,避免浏览器提前加载过多异步 chunk。
js
module.exports = {
chainWebpack: config => {
config.plugins.delete('prefetch')
},
}是否移除要看项目实际加载表现,不要盲目。
12.4 SVG 图标特殊处理
很多项目会把 src/icons 下的 SVG 当成 symbol sprite,把其他 SVG 当普通图片。
示例思路:
js
const path = require('node:path')
function resolve(dir) {
return path.join(__dirname, dir)
}
module.exports = {
chainWebpack: config => {
config.module.rule('svg').exclude.add(resolve('src/icons'))
config.module
.rule('icons')
.test(/\.svg$/)
.include.add(resolve('src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]',
})
},
}需要安装:
bash
npm install svg-sprite-loader -D13. 初学者常见坑
13.1 在 Vite 项目里写 vue.config.js
Vite 不读取 vue.config.js。
Vite 项目应该写:
text
vite.config.ts13.2 修改 vue.config.js 后不重启服务
配置文件变化通常需要重启:
bash
npm run serve13.3 publicPath 和路由 base 不一致
部署到 /admin/ 时,至少要检查:
publicPath。- Vue Router base。
- Nginx fallback。
13.4 只配置 Webpack alias,不配 tsconfig
TypeScript 项目要两边都配:
vue.config.js给 Webpack。tsconfig.json给 TypeScript 和编辑器。
13.5 把秘密写进 VUE_APP_
VUE_APP_ 变量会进入客户端构建产物。不要放密码、token、私钥。
13.6 滥用 chainWebpack
chainWebpack 能力很强,但也更难维护。
优先顺序:
- Vue CLI 顶层配置。
configureWebpack。chainWebpack。
14. 推荐学习顺序
第一阶段:认识配置文件
目标:
- 知道
vue.config.js放在哪里。 - 知道它只属于 Vue CLI。
- 会配置
publicPath、outputDir。
第二阶段:开发环境
目标:
- 会配置端口。
- 会配置代理。
- 会用
.env.development管理代理地址。
第三阶段:资源与样式
目标:
- 会配置 Sass 全局变量。
- 会理解 CSS 是否提取。
- 会处理静态资源目录。
第四阶段:Webpack 扩展
目标:
- 会用
configureWebpack加别名。 - 会用
chainWebpack修改已有规则。 - 会用
vue-cli-service inspect查看最终配置。
第五阶段:生产部署
目标:
- 会配置子路径部署。
- 会关闭生产 source map。
- 会分析构建体积。
- 会处理 history 路由刷新。
15. 学习资源
- Vue CLI 配置参考:https://cli.vuejs.org/config/
- Vue CLI 模式和环境变量:https://cli.vuejs.org/guide/mode-and-env.html
- Webpack 官方文档:https://webpack.js.org/
- webpack-chain 文档:https://github.com/neutrinojs/webpack-chain
建议:学习 vue.config.js 时,不要只背配置项。你应该每次改完后运行:
bash
vue-cli-service inspect看最终 Webpack 配置发生了什么变化。这样才能真正理解 Vue CLI 帮你封装了什么。