藉助 webpack 對項目進行分析優化

原文鏈接:http://callmedadaxin.github.io/2018/04/13/analyse-project-with-webpack/#more

進入公司之後,接手的便是前人留下來的一個大項目。慶幸的是整個項目擁有完善的產品功能文檔,但是由於項目過於龐大,老舊。包含了打包過慢,冗餘文件過多等諸多問題。想要快速的解決這些問題,想要完全把功能重構一遍的話,成本太高了。一個一個文件來過,時間成本也比較大。因此在此篇文章中,我們介紹一下我是如何配合webpack一步步進行分析,將項目進行優化的。
同時我針對思路封裝了一個webpack-unused-files,用於查找項目中的冗餘文件,歡迎試用並star

問題

首先,我們先大致看下我們都有什麼問題,然後一步步進行解決

  • 項目頻繁進行修改,冗餘文件過多
  • 部分第三方依賴濫用,想去除但是不知道在哪個文件中。或沒用,但是遺留在package.json裏,
  • 項目龐大,打包的結果過大,時間過長

刪除冗餘文件

由於項目的頻繁改動,有很多文件已經不被使用並且沒有被刪除。由於項目的不斷擴大,只會影響我們定位功能和問題的速度,因此對冗餘文件進行清理,是很重要的。但是我們單憑肉眼很難識別哪個文件是否被依賴的,因此還要通過webpack來解決。

獲取項目依賴的所有文件

我們來看一下webpack的輸出文件格式:

{
  ...
  chunks: [{
    name: 'chunk-name',
    modules: [
      // 每個chunk中所有的依賴文件
    ]
  }]
  ...
}

所以說,根據這個stats.json,我們可以拿到在整個項目中拿到的所有項目文件:

/**
 * 查詢依賴的模塊
 */
function findSrcModules () {
  return new Promise((resolve, reject) => {
    fs.readFile(statPath, (err, data) => {
      if (err) return
      const json = JSON.parse(data)
      const assetsList = json.chunks
      let ret = []
      // 拿到所有chunk的所有依賴文件
      assetsList.forEach(chunk => {
        const modules = chunk.modules.map(item => item.name)
        ret = ret.concat(modules)
      })
      // 去除node_modules中的文件
      ret = ret.filter(item => item.indexOf('node_modules') < 0)
      resolve(ret)
    })
  })
}

通過這一步,我們可以拿到項目中,所有打包依賴的文件。

獲取項目中所有的文件

通過glob,我們可以獲取所有的文件:

function getAllFilesInSrc () {
  const pattern = './src/**'
  return new Promise((resolve, reject) => {
    glob(pattern, {
      nodir: true
    }, (err, files) => {
      const ret = files.map(item => {
        return item.replace('./src', '.')
      })
      resolve(ret)
    })
  })
}

將兩個文件數組進行對比,然後進行刪除等操作:

將兩個數組進行對比,沒有出現在依賴中的文件,就是冗餘文件。我們可以一鍵刪除

findSrcModules().then(ret => {
  getAllFilesInSrc().then(allFiles => {
    const unUsed = allFiles.filter(item => {
      return ret.indexOf(item) < 0
    })
    const join = p => path.join('./src', p)
    unUsed.forEach(file => {
      shelljs.rm(join(file))
    })
  })
})

分析第三方依賴

根據上述冗餘文件的思路,我們同樣可以對第三方依賴進行處理,大致思路如下

  1. 獲取所有包含node_modules的依賴
  2. 將文件名進行截取、去重。獲取到所有的依賴
  3. 與package.json進行對比,拿到沒有使用的依賴
  4. 將對比結果進行分析,將不想使用的依賴保存下來
  5. 再次查找stat.json,查找該依賴的reson字段,獲取再哪裏引用了該依賴,進行輸出
  6. 將依賴進行手動替換、刪除等操作

可以說,拿到了所有依賴及依賴關係,我們可以很靈活的對其進行處理,拿到我們想要的結果。

該功能後續也會更新到webpack-unused-files中去。

優化打包大小

讓人震驚的是,整個項目由於種種原因,打包後的大小有近20M的大小!雖然並不是TO C項目,並且針對頁面進行了代碼拆分和懶加載,但是作爲一個“合格的前端”,這種現象是一定要修改的(沒錯!)。該如何下手呢?一個個的翻代碼,看看我們都引用了什麼大依賴,看哪些項目過大未免太複雜了。我們看看webpack給我嗎提供了什麼方案:

展示打包結果

我們知道,在webpack打包結束後,會自動在控制檯顯示打包結果。同時,他也提供了輸出依賴及大小的功能,我們執行以下參數, 便可將所有的依賴進行展示,並且看到他們的大小了。

webpack --display-modules --sort-modules-by size

結果類似這樣:

我們可以很快的定位到排名前幾的 js 文件或者第三方依賴,決定該如何對其進行處置。

可視化分析依賴

webpack提供了一個功能,將打包的所有依賴文件以及關係,以 json 格式進行輸出:

webpack --profile --json > stats.json

這是我們整篇文章的一個基礎,很多人基於此封裝了不少可視化分析的工具,可以直觀的看到各個
文件、chunk 之間的依賴關係以及大小等,快速定位到大文件、大模塊

webpack analyse

 

webpack chart

 

優化方案

通過以上兩種方法,我們可以很好的對內容文件和依賴進行定位和分析,針對打包大小的優化方案網上已經有很多了,在此不再進行贅述,提供幾個思路及參考:

優化打包時間

針對打包時間的優化的文章其實也很多了,我們在此僅提供一些思路。我們主要提一點,通過構建會發現,項目中引用了大量的svg圖標以及國旗圖標,每次在靜態資源處理中,打包時間就會變的特別慢。

我們在項目中使用的 svg-sprite-loader,自動將各個 svg 圖標進行 svg-spirte。但是我們知道,這些圖標一旦引用,我們很少進行修改。尤其是像國旗圖標這種,但是每次構建我們都需要進行重複打包。因此,我們可以提前把這些圖標進行 svg-sprite。推薦一個網站,將各種svg圖標提前進行 sprite 並自動進行引用:

iconmoon

日常打包時間優化點

  • externals 避免打包大的第三方依賴
  • dll-plugin 預打包第三方依賴
  • happypack 多進程處理,緩存
  • 緩存與增量構建
    • babel-loader?cacheDirectory
    • webpack cache:true
  • 減少構建搜索或編譯路徑 alias resolve
  • 具象打包的範圍 include exclude

總結

通過對 webpack 輸出依賴關係的 json 的分析,我們可以直觀的拿到以下數據:

  • 所有依賴文件及其大小
  • 每個依賴文件是被哪些文件引用的
  • 項目依賴的第三方依賴

通過這些數據,我們可以很方便的對現有項目進行優化。

生命不息,倒騰不止。讓我們對所有的噁心代碼說再見!

作者:王衛新

關注微信公衆號【51reboot運維開發】可免費獲取視頻學習資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章