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

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


肥油咔咔掉.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. 最后

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336