0%

webpack优化踩坑记

项目背景

  • vue 2.6
  • vue-class-component 7.2
  • vuex 3.4
  • vuex-class 3.4
  • vue-router 3.2
  • element-ui 2.14
  • vue-property-decorator 8.4
  • vue-cli 4
  • webpack 4

今天抽空做一下 webpack 的打包优化,然后网上看看各种方式,一种是多进程打包 HappyPack ,项目使用 TypeScript 尝试了下,由于 vue-cli 配置有限,尝试几次失败后,选择简单的动态库的形式。


按照教程慢慢来

先写个 dll 的配置

webpack.dll.config.js

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
38
39
40
// 标准的配置,没有什么异常
/* eslint-disable */
const path = require('path')
const { execSync } = require('child_process')
const webpack = require('webpack')

const dllPath = path.join(__dirname, 'dll')

execSync(`rm -rf ${dllPath}`)

module.exports = {
mode: 'production',
entry: {
// vue全家桶加上
vue: [
'vue',
'vue-property-decorator',
'vue-class-component',
'vue-router',
'vuex',
'vuex-class',
],
axios: ['axios'],
// element 加上
element: ['element-ui'],
},
output: {
// 打包后文件输出的位置
path: path.join(__dirname, 'dll'),
filename: '[name].dll.js',
// 打包出的是一个库,暴漏到全局,名叫vendors
library: '[name]',
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, 'dll/[name].manifest.json'),
}),
],
}

然后 添加 npm scripts: "dll": "webpack --config ./webpack.dll.config.js"`

再修改 vue.config.js

这里需要安装一些依赖

npm i -d webpack-cli add-asset-html-webpack-plugin

随带添加了个 代码包分析插件 webpack-bundle-analyzer, 打包速度分析插件 speed-measure-webpack-plugin

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// vue.config.js 部分内容
const TerserPlugin = require("terser-webpack-plugin");
const webpack = require('webpack');
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

const smp = new SpeedMeasurePlugin();
const workers = os.cpus().length;

function getPlugins() {
if (__DEV__) {
return [];
}
const plugins = [
// 代码包分析插件
new BundleAnalyzerPlugin()
];
const files = fs.readdirSync(path.resolve(__dirname, 'dll'));
files.forEach(file => {
if (/.*.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, 'dll', file), // 将打包后的dll文件注入html中
outputPath: 'static/dll',
publicPath: publicPath + 'static/dll',
}));
}
else if (/.*.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dll', file),
})); // 分析json文件,里面有的模块就不会引用node_modules里的文件,因为dll.js中已存在
}
});
return plugins;
}

module.exports = {
// ...
configureWebpack: config => {
config.devtool = "module-source-map";
return smp.wrap({
mode: __DEV__ ? 'development' : 'production',
// 保持类名不被压缩
optimization: {
usedExports: true,
concatenateModules: false,
minimizer: [
new TerserPlugin({
parallel: workers,
terserOptions: {
ecma: undefined,
warnings: false,
keep_fnames: true,
parse: {},
compress: {
drop_console: process.env.VUE_APP_MODE === 'production',
drop_debugger: process.env.VUE_APP_MODE === 'production',
pure_funcs: ['console.log'], // 移除console
},
},
sourceMap: true,
})
]
},
// 添加插件
plugins: getPlugins()
});
},
// ...
}

然后打包发布

image-20210422214626693

pa 哦豁,报错了,然后看到是在 vue.**.dll.js 报的错。


改下配置,将 vue 全家桶拆分

1
2
3
4
5
6
7
8
9
10
entry: {
// vue全家桶加上
vue: ['vue', 'vue-router', 'vuex'],
vuePropertyDecorator: ['vue-property-decorator'],
vueClassComponent: ['vue-class-component'],
vueClass: ['vuex-class'],
axios: ['axios'],
// element 加上
element: ['element-ui'],
}
image-20210422221210130

还是有问题,不过这次定位到了在 vue-property-decorator 里面,

修改配置,去掉 vue-property-decorator

1
2
3
4
5
6
7
8
9
10
// 修改配置,去掉vue-property-decorator
entry: {
// vue全家桶加上
vue: ['vue', 'vue-router', 'vuex'],
vueClassComponent: ['vue-class-component'],
vueClass: ['vuex-class'],
axios: ['axios'],
// element 加上
element: ['element-ui'],
}
image-20210422221914099

shit 再去掉 vue-class-component

1
2
3
4
5
6
7
8
9
// 修改配置,再去掉vue-class-component
entry: {
// vue全家桶加上
vue: ['vue', 'vue-router', 'vuex'],
vueClass: ['vuex-class'],
axios: ['axios'],
// element 加上
element: ['element-ui'],
}
image-20210422222154612

fuck 再去

1
2
3
4
5
6
7
8
// 修改配置,再去掉vue-class-component
entry: {
// vue全家桶加上
vue: ['vue', 'vue-router', 'vuex'],
axios: ['axios'],
// element 加上
element: ['element-ui'],
}

nice 一切(看越来)正常

image-20210422222659890

OMG, vue 怎么还在

vue 明明是已经抽取 dll 了,为什么打包的时候还有。。。

等我排查排查

此处省略 1W+字 😩😩😩

最后的配置

1
2
3
4
5
6
entry: {
// element-ui 依赖 vue/dist/vue.runtime.esm
vue: ['vue/dist/vue.esm', 'vue-router', 'vuex/dist/vuex.esm'],
axios: ['axios'],
element: ['element-ui'],
}

image-20210422225221286

perfect


你以为这就结束了?no no no

看一下打包的 dll

element.dll.js

image-20210422230903664

瞎搞,你element怎么打vue也打包了

再看看vue.dll.jd

image-20210422231054380

正常的,我自己打包自己没毛病吧

1
2
继续修改配置,
vue: ['vue/dist/vue.esm', 'vue-router', 'vuex/dist/vuex.esm', 'element-ui'],

element-uivue一起打包,但是还是会打包多个,这里就不贴图了

继续翻翻翻翻 全局搜索的时候发现了这个

image-20210422235525740

然后再看看 vue.config.js

1
runtimeCompiler: true

原来在这,改成false 就行了

OK 一切正常,这次是真 OK 了

附上最后的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 切记vue.config.js 配置
runtimeCompiler: true

// entry 配置
entry: {
vendors: [
'vue',
'vue-property-decorator',
'vue-class-component',
'vue-router',
'vuex',
'vuex-class',
'element-ui',
'vuedraggable',
'dayjs',
'core-js',
'axios'
],
}

总结

一切的一切全来源于runtimeCompiler: true

成果

这是优化前的编译时间

12

这是优化后的编译时间

10-29-57-sNGSP2sNGSP2

卧槽卧槽卧槽。。提速 95%...