如果默认 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);
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, 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, 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') .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin) .end(); config.plugins.delete('prefetch'); } } }, }
|
然后
npm run build --report
自动打开 127.0.0.1:8888
网页,可以查看打包后各个依赖包占用的资源大小,我们可以针对各个依赖包的相关大小作出体积的优化,如果开源库过大可以考虑按需引入,不要全部引入,如果是自己公司封装的私有组件库、类库,可以排查哪部分占用文件过大,打包进行优化处理。
除了上面之外,还有
- 如果有的第三方库用不到,一定要去掉,不然也会加载到文件中
- 拆分三方包
- 分包加载
请参考