0%

vue | 如何缩小打包出来的体积

如果默认 vue 的方式的话,会把所有的 js 打包到一个 js 文件中。

vendor.js

但是,有的时候,这会导致我们的文件非常大,所以,我们就要优化体积。


参考资料



项目简介


  • element-ui
  • “vue”: “2.9.6”
  • “webpack”: “^3.6.0”,

优化过程


下面我会一步步的进行优化。

原始版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
                static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]         
static/fonts/element-icons.732389d.ttf 56 kB [emitted]
static/img/chengzi.0b884eb.jpeg 73.3 kB [emitted]
static/img/dalao1.1bdb522.jpeg 77.6 kB [emitted]
static/img/xiniu.fc3b704.jpeg 25.6 kB [emitted]
static/js/vendor.351b59b55ebe8d775289.js 2.58 MB 0 [emitted] [big] vendor
static/js/app.45c12b206ba8016a482e.js 142 kB 1 [emitted] app
static/js/manifest.2ae2e69a05c33dfc65f8.js 857 bytes 2 [emitted] manifest
static/css/app.e29f6e9666cf20f47a0d76993cc9aa89.css 240 kB 1 [emitted] app
static/css/app.e29f6e9666cf20f47a0d76993cc9aa89.css.map 346 kB [emitted]
static/js/vendor.351b59b55ebe8d775289.js.map 9.96 MB 0 [emitted] vendor
static/js/app.45c12b206ba8016a482e.js.map 549 kB 1 [emitted] app
static/js/manifest.2ae2e69a05c33dfc65f8.js.map 4.97 kB 2 [emitted] manifest
index.html 506 bytes [emitted]

可以发现 static/js/vendor.351b59b55ebe8d775289.js 达到 2.58 MB 可谓是非常大了。

懒加载

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
static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]         
static/fonts/element-icons.732389d.ttf 56 kB [emitted]
static/img/chengzi.0b884eb.jpeg 73.3 kB [emitted]
static/img/dalao1.1bdb522.jpeg 77.6 kB [emitted]
static/img/xiniu.fc3b704.jpeg 25.6 kB [emitted]
static/js/0.d099045696e8849273aa.js 76.6 kB 0 [emitted] vendor-async
static/js/1.e4beefe17d8580fcfa69.js 1.78 MB 1 [emitted] [big]
static/js/2.d2c76f91c9091d7ff287.js 5.05 kB 2 [emitted]
static/js/3.f581823a92ab15dbec91.js 5.4 kB 3 [emitted]
static/js/4.d46626a76946d0ae494d.js 4.57 kB 4 [emitted]
static/js/5.5f31a58676ec7bb6c9eb.js 2.56 kB 5 [emitted]
static/js/6.cc43339b92ec4c114c20.js 3.5 kB 6 [emitted]
static/js/7.3b917184b766b2cf2504.js 1.48 kB 7 [emitted]
static/js/8.4ca1b2e73d2f7bf5486b.js 3.14 kB 8 [emitted]
static/js/9.a3fbe9ade8437c8d5f34.js 2.33 kB 9 [emitted]
static/js/vendor.8324a6c99767382240e6.js 845 kB 10 [emitted] [big] vendor
static/js/app.aa3889e05deaedd5ccaf.js 1.66 kB 11 [emitted] app
static/js/manifest.772ea74e659fc9c3efc8.js 1.69 kB 12 [emitted] manifest
static/css/app.001e48863657bb70bf8aeb2ff2d70148.css 240 kB 11 [emitted] app
static/css/app.001e48863657bb70bf8aeb2ff2d70148.css.map 346 kB [emitted]
static/js/0.d099045696e8849273aa.js.map 707 kB 0 [emitted] vendor-async
static/js/1.e4beefe17d8580fcfa69.js.map 6.38 MB 1 [emitted]
static/js/2.d2c76f91c9091d7ff287.js.map 12.5 kB 2 [emitted]
static/js/3.f581823a92ab15dbec91.js.map 17.1 kB 3 [emitted]
static/js/4.d46626a76946d0ae494d.js.map 15.5 kB 4 [emitted]
static/js/5.5f31a58676ec7bb6c9eb.js.map 11.3 kB 5 [emitted]
static/js/6.cc43339b92ec4c114c20.js.map 13.2 kB 6 [emitted]
static/js/7.3b917184b766b2cf2504.js.map 7.79 kB 7 [emitted]
static/js/8.4ca1b2e73d2f7bf5486b.js.map 11.5 kB 8 [emitted]
static/js/9.a3fbe9ade8437c8d5f34.js.map 11 kB 9 [emitted]
static/js/vendor.8324a6c99767382240e6.js.map 3.32 MB 10 [emitted] vendor
static/js/app.aa3889e05deaedd5ccaf.js.map 6.48 kB 11 [emitted] app
static/js/manifest.772ea74e659fc9c3efc8.js.map 8.18 kB 12 [emitted] manifest
index.html 506 bytes [emitted]

可以发现原来的 js 文件被拆分成每个页面的 js

但是,还是有几个页面很大。

element-ui 简化

根据这个页面,进行改进。

首先修改

npm install babel-plugin-component -D

然后修改 .babelrc

原来的文件内容为

1
2
3
4
5
6
7
8
9
10
11
12
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}

修改后为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime",
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}

然后按需引入即可。

我的 main.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
41
42
43
44
import Vue from 'vue'
import 'element-ui/lib/theme-chalk/index.css';
import App from './App'
import router from './router'
import {
Button,
Row,
Col,
Input,
Table,
TableColumn,
Card,
Pagination,
Menu,
MenuItem,
Select,
Option,
Tag,
Popover
} from 'element-ui';

Vue.config.productionTip = false
Vue.use(Button);
Vue.use(Row);
Vue.use(Col);
Vue.use(Input);
Vue.use(Table);
Vue.use(TableColumn);
Vue.use(Card);
Vue.use(Pagination);
Vue.use(Menu);
Vue.use(MenuItem);
Vue.use(Select);
Vue.use(Option);
Vue.use(Tag);
Vue.use(Popover);

/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: {App},
template: '<App/>'
})

最后优化的结果如下

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
static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]         
static/fonts/element-icons.732389d.ttf 56 kB [emitted]
static/img/chengzi.0b884eb.jpeg 73.3 kB [emitted]
static/img/dalao1.1bdb522.jpeg 77.6 kB [emitted]
static/img/xiniu.fc3b704.jpeg 25.6 kB [emitted]
static/js/0.f4f679b0d302e84bb368.js 81.9 kB 0 [emitted] vendor-async
static/js/1.119973c2777589481b4c.js 1.79 MB 1 [emitted] [big]
static/js/2.d2c76f91c9091d7ff287.js 5.05 kB 2 [emitted]
static/js/3.f581823a92ab15dbec91.js 5.4 kB 3 [emitted]
static/js/4.d46626a76946d0ae494d.js 4.57 kB 4 [emitted]
static/js/5.5f31a58676ec7bb6c9eb.js 2.56 kB 5 [emitted]
static/js/6.cc43339b92ec4c114c20.js 3.5 kB 6 [emitted]
static/js/7.3b917184b766b2cf2504.js 1.48 kB 7 [emitted]
static/js/8.4ca1b2e73d2f7bf5486b.js 3.14 kB 8 [emitted]
static/js/9.a3fbe9ade8437c8d5f34.js 2.33 kB 9 [emitted]
static/js/vendor.2f4ba11b35a369dfc4bd.js 354 kB 10 [emitted] [big] vendor
static/js/app.e29a122d83a5d6121945.js 2.68 kB 11 [emitted] app
static/js/manifest.6874871355993d949630.js 1.69 kB 12 [emitted] manifest
static/css/app.1aa24e61f8edefb4fb70c89353745412.css 243 kB 11 [emitted] app
static/css/app.1aa24e61f8edefb4fb70c89353745412.css.map 505 kB [emitted]
static/js/0.f4f679b0d302e84bb368.js.map 732 kB 0 [emitted] vendor-async
static/js/1.119973c2777589481b4c.js.map 6.4 MB 1 [emitted]
static/js/2.d2c76f91c9091d7ff287.js.map 12.5 kB 2 [emitted]
static/js/3.f581823a92ab15dbec91.js.map 17.1 kB 3 [emitted]
static/js/4.d46626a76946d0ae494d.js.map 15.5 kB 4 [emitted]
static/js/5.5f31a58676ec7bb6c9eb.js.map 11.3 kB 5 [emitted]
static/js/6.cc43339b92ec4c114c20.js.map 13.2 kB 6 [emitted]
static/js/7.3b917184b766b2cf2504.js.map 7.79 kB 7 [emitted]
static/js/8.4ca1b2e73d2f7bf5486b.js.map 11.5 kB 8 [emitted]
static/js/9.a3fbe9ade8437c8d5f34.js.map 11 kB 9 [emitted]
static/js/vendor.2f4ba11b35a369dfc4bd.js.map 1.55 MB 10 [emitted] vendor
static/js/app.e29a122d83a5d6121945.js.map 7.01 kB 11 [emitted] app
static/js/manifest.6874871355993d949630.js.map 8.18 kB 12 [emitted] manifest
index.html 506 bytes [emitted]

发现部分文件变小。

去除 source-map

因为,我们一般不需要生成地图,所以,在 config/index.js 中,把

productionSourceMap: true,

改为

productionSourceMap: false,

最后优化为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]         
static/fonts/element-icons.732389d.ttf 56 kB [emitted]
static/img/chengzi.0b884eb.jpeg 73.3 kB [emitted]
static/img/dalao1.1bdb522.jpeg 77.6 kB [emitted]
static/img/xiniu.fc3b704.jpeg 25.6 kB [emitted]
static/js/0.54ecb11a9999accf04d7.js 81.9 kB 0 [emitted] vendor-async
static/js/1.f4b50c67f1e6cb5f82a7.js 1.79 MB 1 [emitted] [big]
static/js/2.9fc348dcaba50a221c3a.js 5 kB 2 [emitted]
static/js/3.5faf67fc7b7f24777d18.js 5.35 kB 3 [emitted]
static/js/4.c147020b09bebbd78ec8.js 4.52 kB 4 [emitted]
static/js/5.5bb3f77048e84a90ae9b.js 2.51 kB 5 [emitted]
static/js/6.18ea8354da80be8106b0.js 3.46 kB 6 [emitted]
static/js/7.507773ffe71e1fe19ca0.js 1.43 kB 7 [emitted]
static/js/8.aa96da2680e2692dd508.js 3.09 kB 8 [emitted]
static/js/9.4a12675dc50db8bee0e4.js 2.27 kB 9 [emitted]
static/js/vendor.2f4ba11b35a369dfc4bd.js 354 kB 10 [emitted] [big] vendor
static/js/app.e29a122d83a5d6121945.js 2.63 kB 11 [emitted] app
static/js/manifest.da0839befa4af5e11752.js 1.63 kB 12 [emitted] manifest
static/css/app.1aa24e61f8edefb4fb70c89353745412.css 243 kB 11 [emitted] app
index.html 506 bytes [emitted]

可以看出少了很多文件。

开启压缩

压缩开启,可以在 nginx 中开启,也可以 webpack 自行压缩。

如果使用 webpack 压缩好了, nginx 就没必要开压缩了,事先压缩好,有助于 nginx 不需要做多余的运算。

但是,如果你直接使用

npm install --save-dev compression-webpack-plugin

这样压缩会出错,初步怀疑是版本问题。

  • “vue”: “2.9.6”
  • “webpack”: “^3.6.0”,

经过我的测试,应该

npm install --save-dev compression-webpack-plugin@1.1.12

然后在 config/index.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
'use strict'
const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')

module.exports = {
dev: {
...
},

build: {
...
productionGzip: true,
productionGzipExtensions: ['js', 'css'],
...
},
...
configureWebpack: (config) => {
return {
plugins: [new CompressionPlugin({
test: /\.js$|\.html$|\.css/, //匹配文件名
threshold: 10240, //对超过10k的数据进行压缩
deleteOriginalAssets: true //是否删除原文件,这个貌似没起作用
})]
}
}
}

也可以下面这样写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
'use strict'
const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')

module.exports = {
dev: {
...
},

build: {
...
productionGzip: true,
productionGzipExtensions: ['js', 'css'],
...
},
...
plugins: [new CompressionPlugin({
test: /\.js$|\.html$|\.css/, //匹配文件名
threshold: 10240, //对超过10k的数据进行压缩
deleteOriginalAssets: true //是否删除原文件
})],
}

关于这个插件还有很多用法,请参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static/fonts/element-icons.535877f.woff    28.2 kB          [emitted]         
static/fonts/element-icons.732389d.ttf 56 kB [emitted]
static/img/chengzi.0b884eb.jpeg 73.3 kB [emitted]
static/img/dalao1.1bdb522.jpeg 77.6 kB [emitted]
static/img/xiniu.fc3b704.jpeg 25.6 kB [emitted]
static/js/0.54ecb11a9999accf04d7.js 81.9 kB 0 [emitted] vendor-async
static/js/1.f4b50c67f1e6cb5f82a7.js 1.79 MB 1 [emitted] [big]
static/js/2.9fc348dcaba50a221c3a.js 5 kB 2 [emitted]
static/js/3.5faf67fc7b7f24777d18.js 5.35 kB 3 [emitted]
static/js/4.c147020b09bebbd78ec8.js 4.52 kB 4 [emitted]
static/js/5.5bb3f77048e84a90ae9b.js 2.51 kB 5 [emitted]
static/js/6.18ea8354da80be8106b0.js 3.46 kB 6 [emitted]
static/js/7.507773ffe71e1fe19ca0.js 1.43 kB 7 [emitted]
static/js/8.aa96da2680e2692dd508.js 3.09 kB 8 [emitted]
static/js/9.4a12675dc50db8bee0e4.js 2.27 kB 9 [emitted]
static/js/vendor.2f4ba11b35a369dfc4bd.js 354 kB 10 [emitted] [big] vendor
static/js/app.e29a122d83a5d6121945.js 2.63 kB 11 [emitted] app
static/js/manifest.da0839befa4af5e11752.js 1.63 kB 12 [emitted] manifest
static/css/app.1aa24e61f8edefb4fb70c89353745412.css 243 kB 11 [emitted] app
index.html 506 bytes [emitted]
static/js/0.54ecb11a9999accf04d7.js.gz 28.7 kB [emitted]
static/css/app.1aa24e61f8edefb4fb70c89353745412.css.gz 36.7 kB [emitted]
static/js/vendor.2f4ba11b35a369dfc4bd.js.gz 100 kB [emitted]
static/js/1.f4b50c67f1e6cb5f82a7.js.gz 522 kB [emitted] [big]

可以看到,大于我们设定的值, js 就会被压缩为 gz ,但是,原文件依然存在,可以在 nginx 中来配置,js 返回的是源文件还是压缩之后的。

nginx 这样配置

1
2
3
4
5
server {
gzip on;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;
gzip_static on;
}

gzip_static 设置为 on 之后,这样在访问资源的时候,如果存在 资源路径.gz 的文件,则会直接返回该文件,其优先级高于动态的 gzip

那么,浏览器一方是如何对待压缩文件的呢。

首先浏览器在发送请求的时候,会通过请求头Accept-Encoding告知服务器,本浏览器支持哪些编码格式的资源。打开浏览器的network,查看当前网页的某个请求的请求头:

Accept-Encoding的值表示浏览器支持gzip生成的编码格式或者deflate压缩算法生成的编码格式,这就告诉服务器,如果可以把该请求的资源用这两个方法压缩一下给我也是可以的。Accept-Encoding可能还会有compress压缩、identity不压缩的默认格式。

如果服务器对资源进行压缩编码了,它就会通过响应头Content-Encoding告知当前请求用了什么编码格式,当然如果服务器没干这事,则不会返回这个响应头,比如某个请求用gzip压缩了返回的内容:

现在我们可以发现压缩后最大的文件是 522KB

另外,这个压缩,也针对于字体,图片等。

图形化分析 webpack-bundle-analyzer

npm install webpack-bundle-analyzer

config/index.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
'use strict'
const path = require('path')
const CompressionPlugin = require('compression-webpack-plugin')

module.exports = {
dev: {
...
},

build: {
...
},
module: {
...
},
plugins: [
...],
chainWebpack: config => {
/* 添加分析工具 */
if (process.env.NODE_ENV === 'production') {
if (process.env.npm_config_report) {
config
.plugin('webpack-bundle-analyzer')
// eslint-disable-next-line global-require
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
.end();
config.plugins.delete('prefetch');
}
}
},
}

然后

npm run build --report 

自动打开 127.0.0.1:8888 网页,可以查看打包后各个依赖包占用的资源大小,我们可以针对各个依赖包的相关大小作出体积的优化,如果开源库过大可以考虑按需引入,不要全部引入,如果是自己公司封装的私有组件库、类库,可以排查哪部分占用文件过大,打包进行优化处理。

除了上面之外,还有

  • 如果有的第三方库用不到,一定要去掉,不然也会加载到文件中
  • 拆分三方包
  • 分包加载

请参考

请我喝杯咖啡吧~