开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第30天,点击查看活动详情
最近在写项目的时候,突然发现打包出了点小问题,在看vue-cli文档排查问题的过程中,便有了这篇文档,主要介绍vue.config.js的常见配置内容。
vue.config.js文件
vue.config.js 是一个可选的配置文件,如果项目的 (和 package.json 同级的) 根目录中存在这个文件,那么它会被 @vue/cli-service 自动加载。
vue.config.js其实主要目的就是导出一个对象,这个对象里面有很多配置。
// vue.config.js
module.exports = {
}
以我项目中代码为例,vue.config.js中的内容如下:
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
const path = require('path');
const resolve = dir => path.join(__dirname, dir);
const isProduction = process.env.NODE_ENV === 'production';
const isDevelopment = process.env.NODE_ENV === 'development';
module.exports = {
// 基于部署应用包时的基本URL
publicPath: '/',
productionSourceMap: false,
configureWebpack: config => {
// elementplus按需引入
const plugins = [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
})
];
config.plugins.push(...plugins);
// 为生产环境修改配置...
if (process.env.NODE_ENV === 'production') {
config.mode = 'production';
// 打包文件大小配置
config.performance = {
maxEntrypointSize: 10000000,
maxAssetSize: 30000000
}
}
},
chainWebpack: config => {
// 添加别名
config.resolve.alias
.set('@', resolve('src'))
.set('@apis', resolve('src/apis'))
.set('@assets', resolve('src/assets'))
.set('@scss', resolve('src/assets/scss'))
.set('@components', resolve('src/components'))
.set('@mixins', resolve('src/mixins'))
.set('@plugins', resolve('src/plugins'))
.set('@router', resolve('src/router'))
.set('@store', resolve('src/store'))
.set('@utils', resolve('src/utils'))
.set('@config', resolve('src/config'))
.set('@views', resolve('src/views'));
// code splitting
config.optimization.splitChunks({
cacheGroups: {
// 第三方组件
vendors: {
// 指定chunks名称
name: `chunk-vendors`,
// 符合组的要求就给构建
test: /[\\/]node_modules[\\/]/,
// 优先级:数字越大优先级越高,因为默认值为0,所以自定义的一般是负数形式,决定cacheGroups中相同条件下每个组执行的优先顺序。
priority: -10,
// 仅限于最初依赖的第三方
chunks: 'initial'
},
// 公共组件
common: {
name: `chunk-common`,
minChunks: 2,
priority: -20,
chunks: 'initial',
//这个的作用是当前的chunk如果包含了从main里面分离出来的模块,则重用这个模块,这样的问题是会影响chunk的名称。
reuseExistingChunk: true
},
// // 将elementplus单独拆分出来
element: {
name: `element-plus`,
test: /element-plus/,
priority: 20,
chunks: 'all'
},
// 将vue相关的单独拆分出来
vue: {
name: `vue`,
test: /vue/,
priority: 20,
chunks: 'initial'
}
}
});
// 资源配置:在生产环境和开发环境配上title
if (isProduction || isDevelopment) {
config.plugin('html')
.tap(args => {
args[0].title = 'test';
return args;
});
}
// 打包分析
if (isProduction) {
if (process.env.npm_config_report) {
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
.end();
config.plugins.delete('prefetch');
}
}
},
css: {
// 是否使用css分离插件 ExtractTextPlugin
// 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。
extract: true,
// 开启 CSS source maps?
sourceMap: false,
loaderOptions: {
scss: {
// 向全局sass样式传入共享的全局变量, $src可以配置图片cdn前缀
// 详情: https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
prependData: `
@import '@scss/variables.scss';
@import '@scss/mixins.scss';
@import '@scss/function.scss';
$src: '${process.env.VUE_APP_BASE_API}';`
}
}
},
devServer: {
// 让浏览器 overlay 同时显示警告和错误
overlay: {
warnings: true,
errors: true
},
// open: false, // 是否打开浏览器
host: '',
port: '8180', // 代理端口
// https: false,
hotOnly: true, // 热更新
proxy: {
'/ins': {
target: 'http://pre-fundbackend.jinfuzi.cn/',
},
'/alc': {
target: 'http://10.3.20.64:8090/'
// target: 'http://192.168.172.113:8090/'
},
'/sys': {
target: 'http://192.168.20.120:27730'
}
}
},
// 构建时开启多进程处理 babel 编译
parallel: require('os').cpus().length > 1,
// https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
pwa: {},
// 第三方插件配置
pluginOptions: {}
}
vue.config.js配置项
publicPath
这个属性是用来配置部署应用包时的基本URL,属性值是字符串类型,默认是'/'。如果是部署在www.my-app.com上,那么访问路径就是https://www.my-app…', 那么访问路径就是www.my-app.com/my-app/。
一般我们不修改, 保持默认的'/'
publicPath: '/',
outputDir
当运行 vue-cli-service build 时生成的生产环境构建文件的目录(也就是说执行 npm run build时生成的目录名)。属性值也是字符串类型,默认值是'dist'。
一般我们也不修改,保持默认的dist
outputDir: 'dist'
assetsDir
放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。也就是说在dist中单独再分出一个静态资源的目录。属性值也是字符串类型,默认值是''。 不过需要注意的是如果我们配置打包时设置filename 或 chunkFilename 时,assetsDir 会被忽略。
一般我们也不修改,保持默认的’‘
assetsDir: ''
indexPath
指定生成的 index.html 的输出路径 (相对于 outputDir)。也可以是一个绝对路径。属性值是字符串,默认是'index.html'。
一般我们也不修改,保持默认的'index.html'
indexPath: 'index.html'
filenameHashing
是否对生成的静态资源在它们的文件名中包含 hash 值。属性值是布尔型。默认是true,也就是文件名带有hash值。
一般我们也不修改,保持默认的true
filenameHashing: true
pages
在 multi-page 模式下构建应用。每个“page”应该有一个对应的 JavaScript 入口文件。因此可以使用这个属性来配置,属性值是个对象。
一般我们的项目都是单页面应用,因此不需要配置这个,如果是多页面应用,需要配置,参考如下:
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'
}
lintOnSave
是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码。这个值会在 @vue/cli-plugin-eslint 被安装之后生效。属性值类型是boolean | 'warning' | 'default' | 'error',默认是'default'.
- true或‘warning’: eslint-loader 会将 lint 错误输出为编译警告。默认情况下,警告仅仅会被输出到命令行,且不会使得编译失败。
- 'default': 强制 eslint-loader 将 lint 错误输出为编译错误,同时也意味着 lint 错误将会导致编译失败。
- 'error': eslint-loader 把 lint 警告也输出为编译错误,这意味着 lint 警告将会导致编译失败。
如果你想要浏览器overlay 同时显示警告和错误,配置如下:
devServer: {
overlay: {
warnings: true,
errors: true
}
}
runtimeCompiler
是否使用包含运行时编译器的 Vue 构建版本。属性值是布尔类型。默认是false。如果设置了true,你就相当于有了完整版vue,可以在new Vue中使用template选项。 默认情况下我们是不能使用template的,通过渲染函数h()来完成。
productionSourceMap
生产环境下是否生成source map。source map意味着我们可以查看源码,帮助我们debugger查看问题,这也意味着如果使用的话会增加编译时间。默认为true。
一般情况下,我们会设置成false, 来加速生产环境的编译。
productionSourceMap: false
configureWebpack
configureWebpack是用来配置webpack的,属性值可以是对象或者函数。
- 对象:会通过 webpack-merge 合并到最终的配置中。
- 函数:会接收被解析的配置作为参数。该函数既可以修改配置并不返回任何东西,也可以返回一个被克隆或合并过的配置版本。
// 对象形式
configureWebpack: {
plugins: [
new MyAwesomeWebpackPlugin()
]
}
// 函数形式
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// 为生产环境修改配置...
} else {
// 为开发环境修改配置...
}
}
configureWebpack应用
问题描述: 项目打包的时候,有两个提示,说文件打包太大,如图所示
解决方式 在configureWebpack中配置打包文件大小
configureWebpack: config => {
// 为生产环境修改配置...
if (process.env.NODE_ENV === 'production') {
config.mode = 'production';
// 打包文件大小配置
config.performance = {
maxEntrypointSize: 10000000,
maxAssetSize: 30000000
}
}
}
这时候,我之前在configureWebpack中配置过elementplus的按需引入插件是按照对象的形式配置的,如下:
configureWebpack: {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
]
}
如何将对象形式和函数形式合并呢 对象里面是没法加函数的,但是函数里面可以有对象呀,因此主体还是函数默认,只是需要在参数上将对象内容push进去。
configureWebpack: config => {
// elementplus按需引入
const plugins = [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
})
];
config.plugins.push(...plugins);
// 为生产环境修改配置...
if (process.env.NODE_ENV === 'production') {
config.mode = 'production';
// 打包文件大小配置
config.performance = {
maxEntrypointSize: 10000000,
maxAssetSize: 30000000
}
}
}
具体其他操作参考webpack
chainWebpack
是一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。一般这里面可以定义具名的loader规则和具名插件。
1. 添加loader
chainWebpack: config => {
// GraphQL Loader
config.module
.rule('graphql')
.test(/\.graphql$/)
.use('graphql-tag/loader')
.loader('graphql-tag/loader')
.end()
// 你还可以再添加一个 loader
.use('other-loader')
.loader('other-loader')
.end()
}
2. 替换一个规则里的loader
chainWebpack: config => {
const svgRule = config.module.rule('svg')
// 清除已有的所有 loader。
// 如果你不这样做,接下来的 loader 会附加在该规则现有的 loader 之后。
svgRule.uses.clear()
// 添加要替换的 loader
svgRule
.use('vue-svg-loader')
.loader('vue-svg-loader')
}
3. 修改loader选项
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.tap(options => {
// 修改它的选项...
return options
})
}
4. 修改插件选项
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
return [/* 传递给 html-webpack-plugin's 构造函数的新参数 */]
})
}
具体其他操作参考webpack
css.requireModuleExtension
默认情况下,只有 *.module.[ext] 结尾的文件才会被视作 CSS Modules 模块。设置为 false 后你就可以去掉文件名中的 .module 并将所有的 *.(css|scss|sass|less|styl(us)?) 文件视为 CSS Modules 模块。默认值是true.
css.extract
是否将组件中的css提取出来,放到一个单独的css文件中,而不是以js的形式注入到inline代码中。属性值是布尔和对象类型,默认情况下生产环境是true, 开发环境是false。
一般情况下我们设置为true
css: {
extract: true
}
css.sourceMap
和productionSourceMap差不多,只是这个是针对css代码的。属性值是布尔型的。默认是false.
为了提高构建性能,我们一般不设置或者设置为false.
css: {
sourceMap: false
}
css.loaderOptions
这个属性是用来给loder配置选项的。属性值是对象。 loder主要是以下几种:
- css-loader
- postcss-loader
- sass-loader
- less-loader
- stylus-loader
// 全局使用预处理器定义的变量
css: {
loaderOptions: {
scss: {
// 向全局sass样式传入共享的全局变量, $src可以配置图片cdn前缀
// 详情: https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders
prependData: `
@import '@scss/variables.scss';
@import '@scss/mixins.scss';
@import '@scss/function.scss';
$src: '${process.env.VUE_APP_BASE_API}';`
}
}
}
pluginOptions
用来给第三方插件传递选项,属性值是对象。
pluginOptions: {
foo: {
// 插件可以作为 `options.pluginOptions.foo` 访问这些选项。
}
}
devServer
这个是用来配置开发服务器的一些选项,比如host, port, https等,具体可以参考webpack-dev-server 的选项。
devServer.proxy
这个是用来配置代理的,前面我们已经介绍过,具体可以参考我的另一篇文章。