Vue Cli自定义配置
由于 Vue Cli 是默认集成 Webpack 的,为了减少烦琐的配置,默认情况下 Webpack 的相关配置项是不会暴露给开发者的,除了前面提到的采用 inspect
命令查看外。但是我们可以通过 vue.config.js
来修改和覆盖 Vue Cli 的默认 Webpack 配置。注意,由于本书不涉及 Webpack 的详细讲解,所以本章的大部分 Webpack 配置项需要读者事先学习 Webpack 的详细知识后才能理解,可以预先在互联网上了解 Webpack。
默认情况下,vue.config.js
文件并不存在,我们需要在项目的根目录(和 package.json
同级)下创建它,并且返回一个 JSON 格式对象,代码如下:
// vue.config.js
module.exports = {
...
}
由于是覆盖默认的 Webpack 配置,Vue Cli 提供了两种方案,一种是基于 configureWebpack
项来直接覆盖同名配置,另一种是采用 chainWebpack
项来直接修改默认配置。
configureWebpack配置
configureWebpack
选项提供了一个对象,该对象将会被 webpack-merge
合并入最终的 Webpack
配置,代码如下:
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
new MyAwesomeWebpackPlugin()
]
}
}
如果用户需要基于环境有条件地配置,或者想要直接修改配置,可以将 configureWebpack
配成一个函数方法(该函数方法会在环境变量被设置之后执行)。该函数方法的第一个参数会收到已经解析好的配置。在函数方法内,用户可以直接修改配置,或者返回一个将会被合并的对象,代码如下:
// vue.config.js
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置
} else {
// 为开发环境修改配置
}
}
}
采用 configureWebpack
的方式会直接覆盖同名的配置,如果只想修改某个配置的某一个子项,例如 loader
或 plugin
的选项,则很可能会覆盖掉不想要覆盖的默认配置,除非把这些默认配置再写一遍。
chainWebpack
这个配置项提供了颗粒度更细的配置修改。
chainWebpack配置
chainWebpack
选项是一个函数,会接收一个基于 webpack-chain
的实例,该配置项提供了一个 Webpack
原始配置的上层抽象,使其可以定义具名的 loader
规则和具名插件,并有机会在后期进入这些规则并对它们的选项进行修改。
chainWebpack
可以进行更细粒度的修改,修改 loader
的代码如下:
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
// 修改它的选项
return options
})
}
}
替换一个规则中的 loader
,代码如下:
// vue.config.js
module.exports = {
chainWebpack: config => {
const svgRule = config.module.rule('svg')
// 清除已有的所有loader
// 如果你不这样做,接下来的 loader 会附加在该规则现有的loader之后
svgRule.uses.clear()
// 添加要替换的loader
svgRule
.use('vue-svg-loader')
.loader('vue-svg-loader')
}
}
修改插件选项,代码如下:
// vue.config.js
module.exports = {
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
return [/* 传递给 html-webpack-plugin's 构造函数的新参数 */]
})
}
}
比起直接修改 configureWebpack
配置,chainWebpack
的表达能力更强,也更为安全。比如用户想要将 index.html 默认的路径从 /Users/username/proj/public/index.html 改为 /Users/username/proj/app/templates/index.html。通过参考 html-webpack-plugin,可以看到一个可以传入的选项列表。我们可以在下列配置中传入一个新的模板路径来改变它,代码如下:
// vue.config.js
module.exports = {
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
args[0].template = '/Users/username/proj/app/templates/index.html'
return args
})
}
}
无论采用 configureWebpack
还是 chainWebpack
,当我们对配置进行修改后,都可以通过命令:
npx vue-cli-service inspect > output.js
查看最终生成的配置文件是否是我们所需要的,该命令会在 vue.config.js
同级生成一个 output.js
文件,其内容就是完整的配置内容。
其它配置
除了前面介绍的两种配置方式外,vue.config.js
还有一些比较基础的配置项,我们举几个比较常用的例子。
page
默认情况下,项目为单页应用,即只有一个 index.html 页面作为出口,我们也可以通过 page
选项来设置多个页面,每个 page
应该有一个对应的 JavaScript 入口文件,其值应该是一个对象,对象的 key
是入口的名字,value
是一个指定了 entry
、template
、filename
、title
和 chunks
的对象(除了 entry
之外都是可选的),或者是一个指定了 entry
的字符串,代码如下:
module.exports = {
pages: {
index: {
// page 的入口
entry: 'src/index/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
// 当使用只有入口的字符串格式时,
// 模板会被推导为 `public/subpage.html`
// 并且如果找不到的话,就回退到 `public/index.html`。
// 输出文件名会被推导为 `subpage.html`。
subpage: 'src/subpage/main.js'
}
}
publicPath
部署应用包时的基本路径。用法和 Webpack 本身的 output.publicPath
一致,但是 Vue Cli 在其他地方也需要用到这个值,所以要始终使用 publicPath
,而不要直接修改 Webpack 的 output.publicPath
,代码如下:
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/production-sub-path/'
: '/'
}
css.extract
在大多数的 Vue 项目中,每个组件都有自己的样式代码,即放在单文件组件 <style> 里面的内容,当 css.extract
属性设置成 true
时,每个组件的样式代码被提取并合并到一个 CSS 文件中,在项目启动后会被加载。当 css.extract
被设置成 false
时,则不会被合并,而是采用 <style> 标签的形式添加在 HTML 页面中。默认情况下,开发模式为 false
,生产模式为 true
。
devServer
Vue Cli 会提供静态资源服务 devServer
,其基于 webpack-dev-server
,即在执行 npm run serve
后,本地会开启一个默认 8080 端口的静态资源服务,这个服务相关的配置就可以通过 devServer
设置,例如 host
、port
和 https
可以被重新设置。
如果用户的前端应用和后端 API 服务器没有运行在同一个主机上,则需要在开发环境下将 API 请求代理到 API 服务器,通过添加 proxy
项来配置一些代理功能,代码如下:
module.exports = {
devServer: {
proxy: {
'/api': { // 匹配的路径
target: '<url>', // 转换的目标路径
ws: true, // 是否代理 websocket
changeOrigin: true // 配合跨域设置
},
'^/foo': {
target: '<other_url>'
}
}
}
}
其中 proxy
的 key
值表示需要匹配的路径,支持正则,只有命中这个规则的请求才会被代理。changeOrigin
设置成 false
表示请求头中的 host
仍然是浏览器发送过来的 host
,如果设置成 true
,则表示请求头中的 host
会设置成 target
。如果需要跨域,则可以设置成 true
。devServer
基于 http-proxy-middleware
的更多选项配置,可以参考 http-proxy-middleware
的官方网站。
这里暂时只列举这些使用比较多的配置,更多的配置可以参考 vue.config.js
的配置文档地址。