你的前端项目启动速度和打包产物都该优化了吧?

2022-08-01  本文已影响0人  超人s

前端项目启动慢?项目打包体积大?跟着陈教练一起,项目的肥油咔咔掉。


肥油咔咔掉.GIF

1. 背景

项目经过几年的迭代,项目的启动速度随着项目的迭代,肉眼可见的变慢,打包的产物也是一天比一天大。启动项目的时间、打包的时间是越来越久了。如同一个胖子,速度跟不上,体重蹭蹭涨。

接下来就跟着陈教练来两套健身操,减减脂,去去油。

2. 项目启动提速

第一套健身操 —— 提速操

所有的优化,都是需要针对问题进行优化,少数的优化是通用优化。

首先要知道,项目启动的慢,是因为什么慢。

开始前,先看一波目前我手上这个巨大项目的启动时间: before.png

将近190s,3分10秒+,陈教练已经跟着刘畊宏教练跳了一首《本草纲目》了!

2.1. speed-measure-webpack-plugin

直接上工具 speed-measure-webpack-plugin, 跟着配置完后,运行项目既可看到如下的分析报告:

SpeedMeasurePlugin.png
从分析报告可以看出,项目诸多 loader 占用了大半的时间,而 loader 一般又是基本不会变的,于是乎第一个针对本项目的优化方案就出来了,那就是给这些 loader 加上缓存,方法也很简单,就是使用 cache-loader 进行缓存。
npm install --save-dev cache-loader

在 webpack 配置文件内对需要缓存的 loader 进行缓存


const cacheLoader = {   // 新增代码
  loader: 'cache-loader'   // 新增代码
}   // 新增代码
module.exports = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: [
          cacheLoader, // 新增代码
          {
            loader: 'vue-loader',
            options: vueLoaderConfig
          }
        ]
      },
      {
        test: /\.js$/,
        use: [
          cacheLoader, // 新增代码
          {
            loader: 'babel-loader',
          }
        ],
        include: [
          resolve('src'),
        ]
      },
      ... ...
      ... ...
    ]
  }
}

或者也可以像下面,我写的这样,在配置文件内劫持 webpack 的配置,调用 dynamicWebpackConfig 方法,批量缓存

/**
 * 
 * @param {*} rules 
 * @returns rules
 * @description 按需缓存需要缓存的loader
 */
function rules (rules) {
  const shouldCache = ['vue-loader', 'eslint-loader', 'babel-loader']
  const cacheLoader = {
    loader: 'cache-loader'
  }
  rules = rules.map(rule => {
    if (
      rule.use && 
      rule.use[0] && 
      shouldCache.includes(rule.use[0].loader)
    ) {
      rule.use.unshift(
        cacheLoader
      )
    }
    return rule
  })
  return rules
}

/**
 * 
 * @param {*} devWebpackConfig 
 * @returns devWebpackConfig
 * @description 完整的webpack配置
 */

function dynamicWebpackConfig (devWebpackConfig) {
  devWebpackConfig.module.rules = rules(devWebpackConfig.module.rules)
  return devWebpackConfig
}

module.exports = dynamicWebpackConfig
做完这一步,需要正常启动一次项目,此时会建立 loader 的缓存。缓存内容在可以在 node_modules/.cache 下看到。再次启动项目,看看启动时间: after.png

提速了近80秒!此时不知道你是否还记得,在上面我说的这样一句话:

“所有的优化,都是需要针对问题进行优化,少数的优化是通用优化。”

针对问题的优化,已经举了一个例子说明了,那么有没有通用优化的?

通用优化,他来了

2.2. hard-source-webpack-plugin

hard-source-webpack-plugin 中间缓存,不管三七二一,只要 webpack 配置不变,通通缓存,这种这种提速方法过于简单暴力,有其他个性化的需求可以看文档进行配置
hard-source-webpack-plugin

要注意: ip变化,端口变化也是 webpack 配置的变化

使用方法也很简单:

  const hardSourceWebpackPlugin = require('hard-source-webpack-plugin')
  ... ...
  ... ...

  plugins: [
    new hardSourceWebpackPlugin({
      cachePrune: {
        maxAge: 7 * 24 * 60 * 60 * 1000, // 默认2天,现改7天删除
        sizeThreshold: 500 * 1024 * 1024 // 默认50,现修改为500,目前项目启动后占用400MB的空间
      }
    }), //
  ... ...
  ]

同样,这些额外的配置,也可以跟我上面劫持修改 webpack 配置一样,写在一起,方便维护:

/**
 * 
 * @param {*} plugins 
 * @returns plugins
 * @description 按需push插件
 */
function plugins (plugins) {

  const hardSourceWebpackPlugin = require('hard-source-webpack-plugin')

  plugins.push(
    new hardSourceWebpackPlugin({
      cachePrune: {
        maxAge: 7 * 24 * 60 * 60 * 1000, // 默认2天,现改7天删除
        sizeThreshold: 500 * 1024 * 1024 // 默认50,现修改为500,目前项目启动后占用400MB的空间
      }
    }), //
  )

  return plugins
}

/**
 * 
 * @param {*} rules 
 * @returns rules
 * @description 按需缓存需要缓存的loader
 */
function rules (rules) {
  const shouldCache = ['vue-loader', 'eslint-loader', 'babel-loader']
  const cacheLoader = {
    loader: 'cache-loader'
  }
  rules = rules.map(rule => {
    if (
      rule.use && 
      rule.use[0] && 
      shouldCache.includes(rule.use[0].loader)
    ) {
      rule.use.unshift(
        cacheLoader
      )
    }
    return rule
  })
  return rules
}

/**
 * 
 * @param {*} devWebpackConfig 
 * @returns devWebpackConfig
 * @description 完整的webpack配置
 */

function dynamicWebpackConfig (devWebpackConfig) {
    devWebpackConfig.plugins = plugins(devWebpackConfig.plugins)
    devWebpackConfig.module.rules = rules(devWebpackConfig.module.rules)

    return devWebpackConfig
}

module.exports = dynamicWebpackConfig
由于该优化方案还是缓存,所以还是需要正常启动一次项目后,建立缓存。缓存内容在可以在 node_modules/.cache 下看到。再次启动,查看启动时间: afteragine.png

第一套健身操昨完,项目的启动速度已经从 180s 提速至 30s。

累了的同学可以先休息一会儿

3. 项目打包优化

休息结束,跟上第二套健身操 ——— 打包体积优化操

经过第一套的健身操之后,打包速度上,也会沾了缓存的光,打包速度也会有提升。但是,我们打包的体积还是那么大,怎么办?

开始前,还是需要看一看,我们打完包后的产物体积: image.png

还是那句话,“所有的优化,都是需要针对问题进行优化,少数的优化是通用优化。”

那么,如何找到问题呢?

3.1 webpack-bundle-analyzer

这时候就需要用到一个很常见的工具,webpack 打包分析插件 webpack-bundle-analyzer,简单配置完后,重新运行打包命令,可以在本地的8888端口看到如下效果:

image.png

每个颜色的快,就是打包产物内的代码块,图中占面积越大的文件,其文件的大小越大,部署到服务器之后,在浏览器中加载的时间越长。我们可以根据这个图,去优化

通过这个分析图,我们可以知道:

  • 了解 bundle 包中的真正内容
  • 找出哪些模块尺寸最大
  • 查找误引入的模块
  • 优化项目

具体优化就看各位同学的眼力和优化方向了。这边我举一个例子:
譬如,我发现在 app、outer-form 两个个模块内,有一块公共的代码,分别打入这两个个模块


image.png

此时可以在 webpack 配置优化打包如下:

    new webpack.optimize.CommonsChunkPlugin({
        name: 'common',
        chunks: ['app', 'outer-form'] // 抽取commons chunk
    }),

打包后体积略有减小,因为这个地方属于略有优化。


image.png

动动眼睛动动手,其实还可以发现更多的优化点,再比如:


image.png

OK,点到为止!

4. 最后

希望大家身上的肥油也咔咔掉

上一篇下一篇

猜你喜欢

热点阅读