【node】webpack-vue-cli常用配置

修改方式

Vue CLI 可通过两种方式修改 webpack 配置。分别为:configureWebpack 和 chainWebpack。

需要注意的是:configureWebpack 会直接覆盖同名配置(有可能会覆盖 vue cli 默认配置 或 chainWebpack 配置);而 chainWebpack 则是通过修改默认配置来实现。所以一般推荐优先使用 chainWebpack 来修改配置。

configureWebpack

可提供一个 configureWebpack 对象,也可以是一个方法。

  • 对象:该对象将被 webpack-merge 合并到最终的 webpack 配置中,可以直接修改或覆盖 Webpack 的配置。
  • 方法:可基于环境修改配置。函数会在环境变量被设置之后回调,形参会收到已经解析好的配置。在函数内,你可以直接修改解析好的配置,或者返回一个将会被合并的对象。
1
2
3
4
5
6
// vue.config.js 提供对象
module.exports = {
configureWebpack: {
// 修改Webpack的配置
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
// vue.config.js 提供方法
module.exports = {
configureWebpack: (config) => {
if (process.env.NODE_ENV === "production") {
// 为生产环境修改配置...
} else {
// 为开发环境修改配置...
}
return {
// 修改Webpack的配置
};
},
};

chainWebpack 推荐

Vue CLI 内部的 webpack 配置是通过 webpack-chain 维护的。webpack-chain 是一个可以链式配置 webpack 的库。所以可以使用 webpack-chain API 链式修改配置

创建 vue.config.js

1
2
3
4
5
6
7
8
9
10
// vue.config.js
module.exports = {
chainWebpack: (config) => {
if (process.env.NODE_ENV === "production") {
// 为生产环境修改配置...
} else {
// 为开发环境修改配置...
}
},
};

常用的配置

scss 自动导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// vue.config.js
module.exports = {
css: {
loaderOptions: {
sass: {
sassOptions: { outputStyle: "expanded" },
additionalData(content, loaderContext) {
const { resourcePath, rootContext } = loaderContext;
const relativePath = relative(rootContext, resourcePath);
if (relativePath.replace(/\\/g, "/") !== "src/assets/styles/variables.scss") return '@import "~@/assets/styles/variables.scss";' + content;
return content;
},
},
},
},
};

别名

1
2
3
4
5
6
7
8
9
10
11
// vue.config.js
module.exports = {
configureWebpack: {
resolve: {
alias: {
"@": path.resolve(__dirname, "src/"),
// ...
},
},
},
};

打包去掉 console

https://webpack.js.org/configuration/optimization/#optimizationminimizer
https://github.com/terser/terser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// vue.config.js
module.exports = {
chainWebpack: (config) => {
if (process.env.NODE_ENV === "production") {
config.optimization.minimizer("terser").tap((args) => {
// 移除 debugger
args[0].terserOptions.compress.drop_debugger = true;
// 移除全部 console.*
args[0].terserOptions.compress.drop_console = true;
// 移除指定 console.*
// args[0].terserOptions.compress.pure_funcs = ["console.log"];
return args;
});
}
},
};

SVG 自动引入

地址:https://www.npmjs.com/package/svg-sprite-loader

1
npm i -D svg-sprite-loader
1
2
3
4
5
6
7
8
9
10
11
12
13
// vue.config.js
module.exports = {
chainWebpack: (config) => {
const svgRule = config.module.rule("svg");
// 清除SVG已有的 loader 规则
svgRule.uses.clear();
// 新增 SVG Loader 规则
svgRule
.test(/\.svg$/)
.use("svg-sprite-loader")
.loader("svg-sprite-loader");
},
};

gzip 压缩

地址:https://www.npmjs.com/package/compression-webpack-plugin

1
npm i -D compression-webpack-plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// vue.config.js;
const CompressionWebpackPlugin = require("compression-webpack-plugin");

module.exports = {
chainWebpack: (config) => {
if (process.env.NODE_ENV === "production") {
config.plugin("compression").use(CompressionWebpackPlugin, [
{
filename: "[path][base].gz[query]",
algorithm: "gzip",
test: new RegExp("\\.(" + ["html", "js", "css", "svg"].join("|") + ")$"),
threshold: 8192, // 单位字节 大于这个字节时才压缩
minRatio: 0.8, // 压缩比率
},
]);
}
},
};

分块优化

地址: https://webpack.js.org/configuration/optimization/#optimizationsplitchunks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// vue.config.js
module.exports = {
chainWebpack: (config) => {
if (process.env.NODE_ENV === "production") {
config.optimization.splitChunks({
automaticNameDelimiter: "-",
minSize: 20000, // 生成块的最小尺寸,默认 20000 小于 20000 字节的模块不拆分
maxSize: 0, // 生成块的最大尺寸,默认0 表示不限制 超过该值的模块会被拆分成更小的块
minChunks: 1, // 最少chunk,默认1
chunks: "all", // async: 仅拆分异步代码 initial: 仅拆分同步代码 all: 拆分全部代码
cacheGroups: {
vue: {
name: "vue",
test: /[\\/]node_modules[\\/](vue(.*)|core-js)[\\/]/,
chunks: "initial",
priority: 20, // 两个缓存组的 test 规则冲突时,优先匹配优先级高的缓存组
},
elementUI: {
name: "element-ui",
test: /[\\/]node_modules[\\/]element-ui(.*)[\\/]/,
priority: 30,
},
echarts: {
name: "echarts",
test: /[\\/]node_modules[\\/](echarts|zrender|tslib)[\\/]/,
priority: 50,
},
extra: {
name: "roc-extra",
test: resolve("src/extra"),
priority: 40,
},
},
});
}
},
};

打包排除 js 库使用 CDN 引入

比如排除 echarts 包

1
2
3
4
5
6
7
8
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.externals({
echarts: "echarts", // 配置 ECharts 为外部依赖,指定全局变量
});
},
};

排除后在 index.html 中引入 CDN 。在项目中使用全局的变量 echarts 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title>Vue App</title>
</head>

<body>
<noscript>
<strong>We're sorry but vue app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- cdn 引入 -->
<script src="//unpkg.com/echarts@4.9.0/dist/echarts.js"></script>
</body>
</html>

打包模块可视化分析

地址:https://www.npmjs.com/package/webpack-bundle-analyzer

1
npm i -D webpack-bundle-analyzer
1
2
3
4
5
6
// vue.config.js
module.exports = {
chainWebpack: (config) => {
config.plugin("webpack-bundle-analyzer").use(require("webpack-bundle-analyzer").BundleAnalyzerPlugin);
},
};