记一次Vue2 多页面项目优化及所遇到的那些坑

1,598 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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插件对项目打包分析。

打包分析

打包结果如图:

npmv2

打包后,总大小为1.44Mb,其中有三个包比较大:

文件大小
dist/static/js/chunk-5c62e814.3287d6e5.js497.43 KiB
dist/static/js/chunk-f40acd22.4f2337b1.js481.75 KiB
dist/static/js/chunk-vendors.5650d808.js439.50 KiB

具体分析并优化

那么我们通过分析下这三个包下具体的内容,来找出相对应的优化方式:

一、 dist/static/js/chunk-5c62e814.3287d6e5.js

通过图中,我们可以看到有momentlodash.js文件占用比较大。

优化momentlodash

  1. 优化前moment打包后的文件大小为:267.41Kb,其中我们看到locale文件占用了很大一部分,大约是203.61Kb。而locale为国际化相关文件,我们项目中并没用到国际化,所以可以直接干掉。

    解决方法: 通过webpack4中的webpack-ignore来将momentlocale包过滤掉

    const webpack = require('webpack')
    
    module.exports = {
      chainWebpack: config => {
      	config.plugin('webpack-ignore').use(webpack.IgnorePlugin, [
          {
            resourceRegExp: /^\.\/locale$/,
            contextRegExp: /moment$/
          }
        ])
      }
    }
    
    

​ ok,我们再打一下包看下:

成功了,我们看到locale文件已经没有了,我们已经将打包体积减少了是203.61Kb。我们继续:

  1. 优化前lodash打包后的文件大小为:71.48Kb,在项目中我就引入了一两个方法,怎么会这么大呢,我们找下解决办法。

    解决方法: 引入lodash-webpack-pluginbabel-plugin-lodash插件,然后在vue.config.jsbabel.config.js或(.babelrc)文件中进行配置:

    Step1: npm install lodash-webpack-plugin babel-plugin-lodash --save-dev

    Step2: 配置vue.config.jsbabel.config.js

    Vue.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,我们再打包看一下:

image-20220424163349778

​ 哈哈哈,减少到了7Kb,想比之前的71.48Kb,我们减少了64.48Kb

二、dist/static/js/chunk-vendors.5650d808.js

image-20220424163349778

通过图中,我们可以看到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

image-20220424163349778

通过图片,我们看出此包的文件大小为481.75Kb/views/insuranceNotice文件中包含着大量的条款(即文字)。

利用optimization.splitChunks分包

我们进行了如下尝试:

  1. 路由懒加载。此包非首页内容,我们采用了路由懒加载的方式加载符首页非首页内容:
{
  path: '/insuranceNotice',
  name: 'InsuranceNotice',
  component: () => import('../views/insuranceNotice/index')
}
  1. 默认@vue/cli脚手架会将chunk-f40acd22.4f2337b1.js文件通过prefetch的方式预加载下载,以备之后使用。

  2. 我们决定通过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,我们打包再看一下:

    image-20220424163349778

​ 现在的包的大小为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.68Kbimage-20220424163349778

改动:

image-20220424163349778 通过上图我找了半天才找了,太小了,现在`crypto-js`包的大小只有`7.93Kb`,哈哈哈。

通过这次改动,一共用为此项目减少了大约30Kb的大小。

感谢小明同学_死磕前端的建议,希望大家也能多多沟通~

最后

您的每一个点赞及评论都是对我坚持写作最大的支持! 另外希望各位朋友和我交流讨论,如有不对的地方,更希望批评指正!

我是程序员_随心,希望能够通过自己的学习输出给你带来帮助。