前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版

Vue CLI 3 项目构建基础 vue.config.js 配置详解

首页2019-06-02 00:12:32Front-End
VueVue CLIWebpack前端工程化

用 Vue CLI 3 建完项目,很多人第一反应是懵的:build 目录呢?webpack.base.conf.js 呢?CLI 2 时代那一堆能随便改的配置文件全没了,根目录干净得只剩一个 package.json。想改个图片打包阈值、加个二级目录、配个代理,无从下手。这篇就顺着这条线走一遍,先把项目跑起来,再讲清 CLI 3 把 webpack 藏到哪去了,然后把 vue.config.js 里每一项配置对应改的是 webpack 的哪个字段讲明白,最后附上默认插件清单和现在该怎么选型。

在本篇文章中,我们将从浅入深,和大家一起学习以下知识:

  • 安装 Vue CLI 3 并创建项目,看懂生成的目录结构
  • CLI 3 到底把 webpack 配置藏在了哪里,为什么要这么做
  • vue.config.js 六个常用配置项各自改的是 webpack 的什么
  • chainWebpack 和 configureWebpack 的区别,什么时候用哪个
  • 用 vue inspect 反查最终生效的完整配置
  • CLI 3 默认给你装了哪些 webpack 插件,各自干什么
  • Vue CLI 进入维护状态之后,新项目该怎么办

# 一、先把环境和脚手架装好

先确认本地 Node 环境。CLI 3 官方要求的 Node 版本是 8.9 及以上,太老的版本装不上:

# 查看 node 版本
node -v

# 查看 npm 版本
npm -v
@前端进阶之旅: 代码已经复制到剪贴板

然后全局装脚手架:

# 安装 Vue CLI 3.x
npm i -g @vue/cli
@前端进阶之旅: 代码已经复制到剪贴板

这里有个新旧包名的坑。CLI 2 的包名是 vue-cli,CLI 3 换成了带 scope 的 @vue/cli,两者是两个独立的 npm 包。如果你机器上以前装过 vue-cli,vue -V 打出来还是 2.x,先把老的卸干净再装新的,不然命令会打架。

装完之后,在你想要放项目的目录下执行创建命令:

# my-project 是你的项目名称
vue create my-project
@前端进阶之旅: 代码已经复制到剪贴板

它会先问你选预设还是手动选特性,手动模式下可以勾 Router、Vuex、CSS 预处理器、ESLint、单元测试这些。这一步选完之后配置会记在本地,下次建项目可以直接复用预设,不用再点一遍。

# 二、目录结构和可视化界面

创建完成后的目录长这样:

├── node_modules     # 项目依赖包目录
├── public
│   ├── favicon.ico  # ico图标
│   └── index.html   # 首页模板
├── src 
│   ├── assets       # 样式图片目录
│   ├── components   # 组件目录
│   ├── views        # 页面目录
│   ├── App.vue      # 父组件
│   ├── main.js      # 入口文件
│   ├── router.js    # 路由配置文件
│   └── store.js     # vuex状态管理文件
├── .gitignore       # git忽略文件
├── .postcssrc.js    # postcss配置文件
├── babel.config.js  # babel配置文件
├── package.json     # 包管理文件
└── yarn.lock        # yarn依赖信息文件
@前端进阶之旅: 代码已经复制到剪贴板

几个点值得留意。public 目录里的东西是原样拷贝到构建产物里的,不走 webpack 处理,所以那些必须保持固定文件名的资源(第三方 SDK、静态 JSON)放这儿最省事。index.html 是模板,里面可以用 htmlWebpackPlugin.options 的变量。

components 和 views 的分工是 CLI 给的一个约定:views 放路由级别的页面,components 放可复用的组件。这条约定挺重要,它其实对应的是容器组件和展示组件的划分,我在 Vue组件化实践详解 里把组件之间怎么通信讲得比较细,配合着看会更清楚为什么要这么分。

还有一点,router.js 和 store.js 是 CLI 3 早期版本生成的单文件形式。后来的版本改成了 router/index.js 和 store/index.js 目录形式,方便把路由拆成多个模块。你手上的版本生成哪种以实际为准,两种都能跑。

除了命令行,CLI 3 还提供了一个图形化界面,在项目目录下运行:

vue ui
@前端进阶之旅: 代码已经复制到剪贴板

它会起一个本地服务,浏览器里能看到依赖列表、可用的 task、插件管理。日常我用得不多,但有两个场景挺顺手:一是给非前端同学演示怎么跑构建,二是下面要讲的查看 webpack 完整配置。

# 三、CLI 3 为什么看不到 webpack 配置

用过 CLI 2 的人都知道,它生成的项目里有一整套 webpack 配置文件摊在 build 目录下,想改什么直接进去改。CLI 3 里这些文件一个都没有,那它是抛弃 webpack 了吗?

当然不是。CLI 3 用的还是 webpack,只是把配置封装进了 @vue/cli-service 这个包里,对外只暴露一个 vue.config.js 作为修改入口。

这个改动当年争议不小,我一开始也觉得别扭,配置摸不着心里没底。用久了才体会到好处:项目里那份 webpack 配置一旦落地成文件,就跟项目绑死了,升级 webpack、升级 loader 全靠人肉改,几十个项目就是几十份需要各自维护的配置。封装进依赖之后,升级 CLI 版本就等于升级了整套构建配置,成本从 N 降到 1。

代价是灵活性。你想做的事如果超出了 vue.config.js 暴露的范围,就得靠 chainWebpack 去改内部结构,得先知道 CLI 给每条规则、每个插件起的名字是什么。这也是为什么 vue inspect 这个命令后面会反复出现。

# 四、vue.config.js 逐项拆解

vue.config.js 放在项目根目录,导出一个对象。下面这几项是最常改的。

# 1. baseUrl 与现在的 publicPath

如果你想把项目部署在一个二级目录下,比如 http://localhost:8080/vue/,需要配置这一项:

// vue.config.js
module.exports = {
    ...
    
    baseUrl: 'vue',
    
    ...
}
@前端进阶之旅: 代码已经复制到剪贴板

它改的是 webpack 配置里 output.publicPath,重启服务之后首页 URL 就带上二级目录了。

这里要补两个更正。第一,baseUrl 这个名字从 Vue CLI 3.3 起就废弃了,改名叫 publicPath,新版本里写 baseUrl 会给你一条警告,功能还在但别再用。第二,值本身建议写成 '/vue/' 这种前后都带斜杠的形式,只写 'vue' 在部分资源路径拼接时容易出问题。所以现在的写法是:

// vue.config.js
module.exports = {
    publicPath: process.env.NODE_ENV === 'production' ? '/vue/' : '/'
}
@前端进阶之旅: 代码已经复制到剪贴板

按环境区分是因为本地开发一般在根路径下跑,生产才有二级目录。如果部署到 CDN,这里直接填完整的 CDN 域名也行。

# 2. outputDir

想把构建产物输出到别的文件夹(默认是 dist):

// vue.config.js
module.exports = {
    ...
    
    outputDir: 'output',
    
    ...
}
@前端进阶之旅: 代码已经复制到剪贴板

跑 yarn build 之后项目根目录会出现 output 文件夹。它改的是 webpack output.path。

顺带说个相关的:assetsDir 控制的是产物内部静态资源的子目录名(默认是空,资源直接散在根下)。如果后端同学要求 js、css、图片必须归到 static 下,配 assetsDir: 'static' 就行,不用去动 webpack。

# 3. productionSourceMap

这一项控制生产构建要不要生成 source map:

// vue.config.js
module.exports = {
    ...
    
    productionSourceMap: true,
    
    ...
}
@前端进阶之旅: 代码已经复制到剪贴板

它对应 webpack 里 devtool 的值。开启后线上报错能还原到源码行号,定位问题快很多。

但这条现在得加个前提。生产环境直接把 .map 文件传上服务器,等于把源码原封不动交出去了,任何人打开 DevTools 都能看到你的业务逻辑。现在通行的做法是关掉 productionSourceMap,改成在构建流程里单独生成 map 文件、上传给 Sentry 这类错误监控平台,然后从部署产物里删掉。既保留了还原能力,又不把源码挂到公网上。

顺手一提,productionSourceMap: false 还能明显缩短构建时间,大项目上能省掉不少。

# 4. chainWebpack

chainWebpack 允许我们用链式操作细致地修改 webpack 内部配置,底层集成的是 webpack-chain 这个库。比如要把图片的 base64 内联阈值改大:

// 用于做相应的合并处理
const merge = require('webpack-merge');

module.exports = {
    ...
    
    // config 参数为已经解析好的 webpack 配置
    chainWebpack: config => {
        config.module
            .rule('images')
            .use('url-loader')
            .tap(options =>
                merge(options, {
                  limit: 5120,
                })
            )
    }
    
    ...
}
@前端进阶之旅: 代码已经复制到剪贴板

rule('images') 和 use('url-loader') 里的字符串不是随便写的,是 CLI 给这条规则和这个 loader 起的名字,得先用 vue inspect 查出来才能对得上。tap 拿到的是这个 loader 当前的 options,返回值就是新的 options,这里用 webpack-merge 做合并而不是直接覆盖,是为了保住 CLI 原本设的其他字段。

改完之后,webpack 里对应的这段配置变成:

{
    ...
    
    module: {
        rules: [
            {   
                /* config.module.rule('images') */
                test: /\.(png|jpe?g|gif|webp)(\?.*)?$/,
                use: [
                    /* config.module.rule('images').use('url-loader') */
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 5120,
                            name: 'img/[name].[hash:8].[ext]'
                        }
                    }
                ]
            }
        ]
    }
    
    ...
}
@前端进阶之旅: 代码已经复制到剪贴板

注意 limit: 5120 的单位是字节,也就是 5KB,不是 5MB。这个数字调大要慎重,内联进 JS 的 base64 会变大三分之一左右,而且没法被浏览器单独缓存,阈值设太大反而拖慢首屏。我的经验是 4KB 到 10KB 之间,专门给图标类小图用。

# 5. configureWebpack

除了链式修改,还可以用 configureWebpack 改配置。两者的区别在于 chainWebpack 是精细的链式操作,configureWebpack 更倾向于整体替换和合并:

fe
  • 一、先把环境和脚手架装好
  • 二、目录结构和可视化界面
  • 三、CLI 3 为什么看不到 webpack 配置
  • 四、vue.config.js 逐项拆解
    • 1. baseUrl 与现在的 publicPath
    • 2. outputDir
    • 3. productionSourceMap
    • 4. chainWebpack
    • 5. configureWebpack
    • 6. devServer
  • 五、默认装了哪些 webpack 插件
  • 六、Vue CLI 之后,现在该用什么
  • 总结
  • 参考

← Vue单页应用的基本配置 路由 Vuex 与接口层分层Nginx极简教程,反向代理负载均衡与跨域常用配置 →