你的前端項目啟動速度和打包產(chǎn)物都該優(yōu)化了吧?

前端項目啟動慢瘩将?項目打包體積大吟税?跟著陳教練一起凹耙,項目的肥油咔咔掉。


肥油咔咔掉.GIF

1. 背景

項目經(jīng)過幾年的迭代肠仪,項目的啟動速度隨著項目的迭代肖抱,肉眼可見的變慢,打包的產(chǎn)物也是一天比一天大藤韵。啟動項目的時間虐沥、打包的時間是越來越久了。如同一個胖子泽艘,速度跟不上欲险,體重蹭蹭漲。

接下來就跟著陳教練來兩套健身操匹涮,減減脂天试,去去油。

2. 項目啟動提速

第一套健身操 —— 提速操

所有的優(yōu)化然低,都是需要針對問題進行優(yōu)化喜每,少數(shù)的優(yōu)化是通用優(yōu)化。

首先要知道雳攘,項目啟動的慢带兜,是因為什么慢。

開始前吨灭,先看一波目前我手上這個巨大項目的啟動時間:
before.png

將近190s刚照,3分10秒+,陳教練已經(jīng)跟著劉畊宏教練跳了一首《本草綱目》了喧兄!

2.1. speed-measure-webpack-plugin

直接上工具 speed-measure-webpack-plugin无畔, 跟著配置完后,運行項目既可看到如下的分析報告:

SpeedMeasurePlugin.png

從分析報告可以看出吠冤,項目諸多 loader 占用了大半的時間浑彰,而 loader 一般又是基本不會變的,于是乎第一個針對本項目的優(yōu)化方案就出來了拯辙,那就是給這些 loader 加上緩存,方法也很簡單涯保,就是使用 cache-loader 進行緩存。

npm install --save-dev cache-loader

在 webpack 配置文件內(nèi)對需要緩存的 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'),
        ]
      },
      ... ...
      ... ...
    ]
  }
}

或者也可以像下面遭赂,我寫的這樣,在配置文件內(nèi)劫持 webpack 的配置横辆,調(diào)用 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 的緩存困肩。緩存內(nèi)容在可以在 node_modules/.cache 下看到划纽。再次啟動項目,看看啟動時間:
after.png

提速了近80秒锌畸!此時不知道你是否還記得勇劣,在上面我說的這樣一句話:

“所有的優(yōu)化,都是需要針對問題進行優(yōu)化潭枣,少數(shù)的優(yōu)化是通用優(yōu)化比默。”

針對問題的優(yōu)化盆犁,已經(jīng)舉了一個例子說明了命咐,那么有沒有通用優(yōu)化的?

通用優(yōu)化谐岁,他來了

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天,現(xiàn)改7天刪除
        sizeThreshold: 500 * 1024 * 1024 // 默認50迷捧,現(xiàn)修改為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天庆锦,現(xiàn)改7天刪除
        sizeThreshold: 500 * 1024 * 1024 // 默認50捅位,現(xiàn)修改為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

由于該優(yōu)化方案還是緩存搂抒,所以還是需要正常啟動一次項目后艇搀,建立緩存。緩存內(nèi)容在可以在 node_modules/.cache 下看到求晶。再次啟動焰雕,查看啟動時間:
afteragine.png

第一套健身操昨完矩屁,項目的啟動速度已經(jīng)從 180s 提速至 30s辟宗。

累了的同學(xué)可以先休息一會兒

3. 項目打包優(yōu)化

休息結(jié)束泊脐,跟上第二套健身操 ——— 打包體積優(yōu)化操

經(jīng)過第一套的健身操之后容客,打包速度上约郁,也會沾了緩存的光,打包速度也會有提升调煎。但是士袄,我們打包的體積還是那么大,怎么辦娄柳?

開始前赤拒,還是需要看一看诱鞠,我們打完包后的產(chǎn)物體積:
image.png

還是那句話航夺,“所有的優(yōu)化,都是需要針對問題進行優(yōu)化始衅,少數(shù)的優(yōu)化是通用優(yōu)化汛闸∫章睿”

那么,如何找到問題呢别伏?

3.1 webpack-bundle-analyzer

這時候就需要用到一個很常見的工具,webpack 打包分析插件 webpack-bundle-analyzer,簡單配置完后轴脐,重新運行打包命令抡砂,可以在本地的8888端口看到如下效果:

image.png

每個顏色的快,就是打包產(chǎn)物內(nèi)的代碼塊注益,圖中占面積越大的文件,其文件的大小越大厦瓢,部署到服務(wù)器之后啤月,在瀏覽器中加載的時間越長。我們可以根據(jù)這個圖浙垫,去優(yōu)化

通過這個分析圖夹姥,我們可以知道:

  • 了解 bundle 包中的真正內(nèi)容
  • 找出哪些模塊尺寸最大
  • 查找誤引入的模塊
  • 優(yōu)化項目

具體優(yōu)化就看各位同學(xué)的眼力和優(yōu)化方向了辙售。這邊我舉一個例子:
譬如倘要,我發(fā)現(xiàn)在 app、outer-form 兩個個模塊內(nèi)志鹃,有一塊公共的代碼曹铃,分別打入這兩個個模塊


image.png

此時可以在 webpack 配置優(yōu)化打包如下:

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

打包后體積略有減小陕见,因為這個地方屬于略有優(yōu)化。


image.png

動動眼睛動動手灰粮,其實還可以發(fā)現(xiàn)更多的優(yōu)化點忍坷,再比如:


image.png

OK,點到為止柑肴!

4. 最后

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末晰骑,一起剝皮案震驚了整個濱河市硕舆,隨后出現(xiàn)的幾起案子岗宣,更是在濱河造成了極大的恐慌淋样,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刊咳,死亡現(xiàn)場離奇詭異娱挨,居然都是意外死亡跷坝,警方通過查閱死者的電腦和手機碉碉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門贴届,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人占键,你說我怎么就攤上這事畔乙⌒ピ瑁” “怎么了氮帐?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵上沐,是天一觀的道長参咙。 經(jīng)常有香客問我硫眯,道長两入,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任择葡,我火速辦了婚禮剃氧,結(jié)果婚禮上朋鞍,老公的妹妹穿的比我還像新娘。我一直安慰自己滥酥,他們只是感情好疏哗,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布返奉。 她就那樣靜靜地躺著,像睡著了一般雷逆。 火紅的嫁衣襯著肌膚如雪污尉。 梳的紋絲不亂的頭發(fā)上被碗,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天某宪,我揣著相機與錄音,去河邊找鬼锐朴。 笑死兴喂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的焚志。 我是一名探鬼主播衣迷,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酱酬!你這毒婦竟也來了壶谒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤膳沽,失蹤者是張志新(化名)和其女友劉穎汗菜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挑社,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡滔灶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年斗这,在試婚紗的時候發(fā)現(xiàn)自己被綠了赁咙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情步鉴,我是刑警寧澤随闪,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布当宴,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虏劲,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一念秧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧砾层,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽庐扫。三九已至碘勉,卻和暖如春倍宾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背怔锌。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遗锣。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓墓阀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親帕膜。 傳聞我的和親對象是個殘疾皇子垮刹,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355