一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
大家好,我是程序员_随心,希望能够通过自己的学习输出给你带来帮助。
前言
首先交代一下项目的基本情况:
项目是采用@vue/cli创建的一个多页面应用,package.json部分内容如下:
{
"scripts": {
"serve": "vue-cli-service serve"
}
"dependencies": {
"axios": "^0.19.2",
"core-js": "^3.6.4",
"lib-flexible": "^0.3.2",
"pinyin-pro": "^3.3.1",
"regenerator-runtime": "^0.13.5",
"shelljs": "^0.8.5",
"vant": "^2.10.2",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuex": "^3.4.0",
"weixin-js-sdk": "^1.6.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"crypto-js": "^4.0.0",
"docx": "^5.3.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"file-saver": "^2.0.2",
"js-md5": "^0.7.3",
"lodash": "^4.17.20",
"lodash-webpack-plugin": "^0.11.6",
"moment": "^2.29.0",
"node-sass": "^4.14.1",
"pdfjs-dist": "2.1.266",
"postcss-pxtorem": "^5.1.1",
"sass-loader": "^8.0.2",
"script-ext-html-webpack-plugin": "^2.1.4",
"vconsole": "^3.3.4",
"vue-template-compiler": "^2.6.11",
"webpack-bundle-analyzer": "^3.8.0"
}
}
主要的技术是通过webpack-bundle-analyzer插件对项目打包分析。
打包分析
打包结果如图:
打包后,总大小为1.44Mb,其中有三个包比较大:
| 文件 | 大小 |
|---|---|
| dist/static/js/chunk-5c62e814.3287d6e5.js | 497.43 KiB |
| dist/static/js/chunk-f40acd22.4f2337b1.js | 481.75 KiB |
| dist/static/js/chunk-vendors.5650d808.js | 439.50 KiB |
具体分析并优化
那么我们通过分析下这三个包下具体的内容,来找出相对应的优化方式:
一、 dist/static/js/chunk-5c62e814.3287d6e5.js
通过图中,我们可以看到有moment和lodash.js文件占用比较大。
优化moment和lodash
-
优化前
moment打包后的文件大小为:267.41Kb,其中我们看到locale文件占用了很大一部分,大约是203.61Kb。而locale为国际化相关文件,我们项目中并没用到国际化,所以可以直接干掉。解决方法: 通过
webpack4中的webpack-ignore来将moment的locale包过滤掉const webpack = require('webpack') module.exports = { chainWebpack: config => { config.plugin('webpack-ignore').use(webpack.IgnorePlugin, [ { resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ } ]) } }
ok,我们再打一下包看下:
成功了,我们看到locale文件已经没有了,我们已经将打包体积减少了是203.61Kb。我们继续:
-
优化前
lodash打包后的文件大小为:71.48Kb,在项目中我就引入了一两个方法,怎么会这么大呢,我们找下解决办法。解决方法: 引入
lodash-webpack-plugin和babel-plugin-lodash插件,然后在vue.config.js及babel.config.js或(.babelrc)文件中进行配置: Step1:
npm install lodash-webpack-plugin babel-plugin-lodash --save-dev Step2: 配置
vue.config.js及babel.config.jsVue.config.js:
const LodashWebpackPlugin = require('lodash-webpack-plugin') module.exports = { chainWebpack: config => { config.plugin('lodash-webpack-pluigin').use(new LodashWebpackPlugin()) } }babel.config.js:
module.exports = { plugins: ['lodash'] }
Ok,我们再打包看一下:
哈哈哈,减少到了7Kb,想比之前的71.48Kb,我们减少了64.48Kb。
二、dist/static/js/chunk-vendors.5650d808.js
通过图中,我们可以看到vconsole.min.js文件占用比较大,大小约为147.06Kb。
优化vconsole
由于生产环境中,我们不需要vconsole,并且我记得项目中也做了这样生产环境不进行new Vconsole(),但这里为什么却还是将vconsole打包进来了呢?我们来看下代码:
import VConsole from 'vconsole'
if (process.env.VUE_APP_ENV !== 'production') {
new VConsole()
}
我们乍一看来,好像没啥毛病啊。但是其实import帮我们已经引入了(ES6模块是编译时执行的,讲究的是静态化)。
解决方法: 我们通过require操作符来解决这个问题,因为require是运行时执行的。
if (process.env.VUE_APP_ENV !== 'production') {
const VConsole = require('vconsole')
new VConsole()
}
ok,我们打包的文件又减少了147.06Kb。
三、dist/static/js/chunk-f40acd22.4f2337b1.js
通过图片,我们看出此包的文件大小为481.75Kb,/views/insuranceNotice文件中包含着大量的条款(即文字)。
利用optimization.splitChunks分包
我们进行了如下尝试:
- 路由懒加载。此包非首页内容,我们采用了路由懒加载的方式加载符首页非首页内容:
{
path: '/insuranceNotice',
name: 'InsuranceNotice',
component: () => import('../views/insuranceNotice/index')
}
-
默认
@vue/cli脚手架会将chunk-f40acd22.4f2337b1.js文件通过prefetch的方式预加载下载,以备之后使用。 -
我们决定通过
webpack中的optimization.splitChunks来进行分包处理。我们来更改
vue.config.js文件:const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV) module.exports = { pages: [ index: { // chunks: ['chunk-vendors','chunk-common', 'chunk-login-vendors', 'index'], // 这里打包后的页面显示空白 chunks: 'all' // 这里必须设置为all,https://github.com/vuejs/vue-cli/issues/3454#issuecomment-821034908 } ] chainWebpack: config => { config.when(IS_PROD, config => { config.optimization.splitChunks({ chunks: 'all', minSize: 100 * 1024, maxSize: 150 * 1024, cacheGroups: { commons: { name: 'chunk-commons', test: resolve('src/components'), minChunks: 3, // 被至少用三次以上打包分离 priority: 5, // 优先级 reuseExistingChunk: true // 表示是否使用已有的 chunk,如果为 true 则表示如果当前的 chunk 包含的模块已经被抽取出去了,那么将不会重新生成新的。 }, node_vendors: { name: 'chunk-libs', chunks: 'initial', // 只打包初始时依赖的第三方 test: /[\\/]node_modules[\\/]/, priority: 10 }, vantUI: { name: 'chunk-vantUI', // 单独将 vantUI 拆包 priority: 20, // 数字大权重到,满足多个 cacheGroups 的条件时候分到权重高的 test: /[\\/]node_modules[\\/]_?vant(.*)/ } } }) }) } }ok,我们打包再看一下:
现在的包的大小为1M。ok,至此我们一共减少了(1.44 - 1) * 1024 = 450.56Kb的大小。耶~
2020-04-25 更新
评论区小明同学_死磕前端提出
crypto-js里有md5的方法,为啥还要引入js-md5, crypto-js里没用到的是否可以剥离
对啊,为啥我还要用呢?没有必要,果断听取建议,去掉js-md5。
需要注意的点:
crypto.MD5(val)函数返回的是一个对象,要将其转换为字符串需要调用toString()函数,即crypto.MD5(val).toString()。具体可见下方代码:
import md5 from 'js-md5'
import crypto from 'crypto-js'
console.log(md5('123')) // 202cb962ac59075b964b07152d234b70
console.log(crypto.MD5('123)) // 202cb962ac59075b964b07152d234b70
去掉js-md5包后大概减少了10.31Kb。
然后,我们把crypro-js改为按需引入,而不是引入全量包。
我们看下改动之前,大小为28.68Kb:
改动:
通过这次改动,一共用为此项目减少了大约30Kb的大小。
感谢小明同学_死磕前端的建议,希望大家也能多多沟通~
最后
您的每一个点赞及评论都是对我坚持写作最大的支持! 另外希望各位朋友和我交流讨论,如有不对的地方,更希望批评指正!
我是程序员_随心,希望能够通过自己的学习输出给你带来帮助。