效能優化小冊 - 分類構建:利用好 webpack hash

破曉L發表於2020-05-18

藉助 wepack 的 hash 命名法,不僅可以提高我們專案的構建效率,在生產環境中,合理設定 hash 型別有助於我們對資源進行有效的快取。

webpack hash 種類

當無情面試官問 webpack 有幾種 hash 型別?
  1. hash - 工程級

    如果出口檔案設定的型別是 hash 則每次修改任何檔案,所有檔名的 hash 都會跟著改變。(不能有效利用快取)

  2. chunkhash - 模組級

    根據不同的入口檔案進行依賴檔案解析、構建對應的 chunk,生成對應的 hash 值。

  3. contenthash - 檔案內容級

    由檔案內容產生的 hash 值,內容不同產生的 contenthash 值也不一樣。

如何設定 hash 達到專案優化的目的?

js 檔案分類構建,設定 chunkhash

首先使用 CommonsChunkPlugin 外掛提取第三方庫和公眾模組,進行單獨打包構建:

plugins: [
  new webpack.optimize.CommonsChunkPlugin({ 
    name: 'vendor',
    minChunks (module) {
      return (
        module.resource &&
        /\.js$/.test(module.resource) &&
        module.resource.indexOf(
          path.join(__dirname, '../node_modules')
        ) === 0
      )
    }
  }),
]

接著我們在 outputfilenamechunkFilename 兩個欄位設定 chunkhash ,生成對應 hash 值:

output: {
  path: path.resolve(__dirname, './dist'),
  publicPath: '/dist/',
  filename: 'js/[name].[chunkhash].js', 
  chunkFilename: 'js/[id].[chunkhash].js' // chunkFilename 是處理非同步模組的
},

通過設定 chunkhash 最後打包出來的 js 檔案會生產三種 chunkhash

  1. 正常引入的 js 檔案對應的 hash
  2. 非同步載入的 js 檔案(如果在專案中存在的話)對應的 hash
  3. 提取的三方庫和公共模組對應的 hash

image.png

那麼只要對應的 js 檔案程式碼不改動,就可以保證其 chunkhash 值不會受影響,從而達到瀏覽器的持久快取。

抽離 css,設定 contenthash

首先,使用 ExtractTextPlugin 外掛將所有的入口 chunk 中引用的 *.css,抽離到獨立的 css 資料夾中。

抽離之後的樣式將不再內嵌到 JS bundle 中,而是會放到一個單獨的 CSS 檔案當中,如果樣式檔案大小較大,這會做更快提前載入,因為 CSS bundle 會跟 JS bundle 並行載入。
plugins: [
  new ExtractTextPlugin({
    filename: 'css/[name].css',
    allChunks: true
  }),
]

之後對 css 檔案進行 contenthash 命名:

plugins: [
  new ExtractTextPlugin({
    filename: 'css/[name].[contenthash].css',
    allChunks: true
  }),
]

針對 css 檔案會生產對應的 contenthash 值,只要 css 檔案內容沒有修改,那麼 contenthash 值就一直保持不變,以有效的利用瀏覽器快取。

image.png

css 檔案可以設定成 chunkhash 嗎?

答案是不要這麼做,因為 chunkhash 是模組級,我們是將樣式作為模組 importjs 檔案中,所以它們的 chunkhash 是一致的。

js 和所引入的 css 共用同一個 chunkhash,只要 js 改變,與其關聯的 css 檔案對應的 chunkhash 值也會改變,但可能其內容並沒有改變,所以達不到快取的效果。

image.png

這是 「效能優化小冊」 系列第二篇小記,歡迎關注。

相關文章