天天看點

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

webpack系列文章:

  • 【Webpack 性能優化系列(9) - 多程序打包】極大的提升項目打包建構速度!!!
  • 【Webpack 性能優化系列(8) - PWA】使用漸進式網絡應用程式為我們的項目添加離線體驗
  • 【Webpack 性能優化系列(7) - 懶加載和預加載】
  • 【Webpack 性能優化系列(6) - code splitting 】通過代碼分割來擷取更小的 bundle,優化資源加載
  • 【Webpack 性能優化系列(5) - tree shaking 】去除未引用代碼,減少代碼體積!!!
  • 【Webpack 性能優化系列(4) - 緩存 】詳解如何做bable緩存和檔案資源緩存
  • 【Webpack 性能優化系列(3) - oneOf】
  • 【Webpack 性能優化系列(2) - source-map】
  • 【Webpack 生産環境配置】近兩萬字長文總結學習如何提取css為單獨檔案、css的壓縮和相容性處理,如何壓縮html和js、如何做js文法檢查eslint和js相容性處理babel!!!
  • 【Webpack 開發環境配置】萬字長文總結學習如何打包樣式資源、html資源、圖檔資源和其他資源?devServer是什麼,如何配置?
  • 【Webpack 簡介及五個核心概念】

webpack性能優化

webpack性能優化主要指兩個環境:

  • 開發環境性能優化
  • 生産環境性能優化

除了前面的開發環境和生産環境配置,還有以下性能優化處理:

開發環境性能優化包括:

  • 優化打包建構速度
    • HMR
  • 優化代碼調試
    • source-map

生産環境性能優化包括:

  • 優化打包建構速度
    • oneOf
    • babel緩存
    • 多程序打包
    • externals
    • dll
  • 優化代碼運作的性能
    • 緩存(hash-chunkhash-contenthash)
    • tree shaking
    • code split
    • 懶加載/預加載
    • pwa

HMR 熱子產品替換

為什麼要使用

HMR 熱子產品替換

功能?

我們回看一下前面總結的開發環境配置:

/*
  開發環境配置:能讓代碼運作
    運作項目指令:
      webpack 打包運作項目
      npx webpack-dev-server 啟動webpack-dev-server
*/

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 處理less資源
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 處理css資源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        // 處理圖檔資源
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 關閉es6子產品化
          esModule: false,
          outputPath: 'imgs'
        }
      },
      {
        // 處理html中img資源
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        // 處理其他資源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true
  }
};
           

下面我們看一下這種配置存在什麼問題

運作指令:

npx webpack-dev-server

,啟動webpack-dev-server

然後在

index.js

檔案中列印一段話:

console.log('index.js檔案被加載了~');

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

隻要index.js檔案重新被加載,就會列印上面那段話

現在去修改樣式檔案

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考
#box {
  width: 400px;// 200px修改為400px
  height: 200px;
  background-image: url('../imgs/angular.jpg');
  background-repeat: no-repeat;
  background-size: 100% 100%;
}
           

修改之後,很明顯整體頁面被重新整理,内容被重新列印了一次

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

意思就是:當我們修改css檔案時,明明js檔案沒有變化,但js檔案也被重新加載了一次,是以打包的時候,看似隻修改了css檔案,實際上是把js檔案也重新打包了一次,這是一個問題。

再寫一個子產品:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

在index.js中引入上面那個print子產品,并且在下面調用一下:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

效果:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

發現子產品被加載,并且子產品的print方法被調用執行了

現在我們修改一下print.js檔案,

'hello print'

改為`‘hello webpack’

console.log('print.js被加載了~');

function print() {
  const content = 'hello webpack';
  console.log(content);
}

export default print;
           

儲存檢視效果,可以發現整個頁面被重新重新整理了,所有代碼重新執行:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

這個意思就代表:假設以後我們有100個js子產品,100個樣式子產品,如果隻修改其中某一個子產品,這整200個子產品就需要重新打包,這個速度可以想想是非常慢的,更不要說以後的子產品會越來越多,那打包情況隻會越來越慢。

是以我們想實作這樣的功能:如果隻有一個子產品發生變化,那麼隻需要修改這一個子產品代碼就足夠了,其他子產品理應是不變的

做這個功能要使用webpack的

HMR 熱子產品替換

HMR:

hot module replacement

熱子產品替換 / 子產品熱替換

作用:一個子產品發生變化,隻會重新打包這一個子產品(而不是打包所有子產品),極大提升建構速度

HMR功能的使用非常簡單,隻需要在devServer裡配置

hot:true

即可:

devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true,
    // 開啟HMR功能
    // 當修改了webpack配置,新配置要想生效,必須重新webpack服務
    hot: true
  }
           

修改配置後,運作指令:

npx webpack-dev-server

,重新啟動webpack-dev-server

開啟HMR功能跟之前更新有什麼差別?

首先列印結果這裡已經顯示HMR功能已經開啟:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

下面修改樣式檔案,儲存,可以發現隻更新一個樣式檔案,js檔案并不會重新加載:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

可以發現:樣式檔案可以使用HMR功能,之是以能使用是因為style-loader内部實作了~

這也是為什麼我們在開發環境要使用

style-loader

,生産環境要用

MiniCssExtractPlugin.loader

提取成單獨檔案,因為開發環境借助

style-loader

能讓性能更好,打包速度更快,但是上線的時候考慮性能優化,是以不能用

前面樣式檔案可以使用HMR功能,js檔案行不行呢?

修改

print.js

檔案,儲存,發現整個頁面被重新重新整理了一遍,這一點可以知道js檔案預設不能使用HMR功能

html檔案可以使用HMR功能嗎?

在html檔案中修改一段代碼:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

儲存後發現當開啟HMR功能後,html檔案改動後并沒有任何變化:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

html檔案: 預設不能使用HMR功能,同時會導緻問題:html檔案不能熱更新了~

通過修改

entey

入口,改成一個數組,把html檔案引入就可以解決上面的問題了:

修改配置後,打包運作項目

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

測試發現html檔案也是沒有HMR功能的,一旦html檔案發生變化,整體頁面就會重新重新整理

那麼html檔案需要HMR功能嗎?

html不像js檔案,一個項目裡會有很多個js子產品,而運作的html隻會有一個,一旦發生變化,就一定要變化,它隻需要變化一個檔案,既然一定要變化,那就沒辦法優化,是以html檔案不用做HMR功能

前面講到了js預設不能使用HMR功能,這并不代表js就不需要HMR功能,如何對js檔案使用HMR功能?

用法:

if (module.hot) {
  // 一旦 module.hot 為true,說明開啟了HMR功能。 --> 讓HMR功能代碼生效
  module.hot.accept('./print.js', function() {
    // 方法會監聽 print.js 檔案的變化,一旦發生變化,其他子產品不會重新打包建構。
    // 會執行後面的回調函數
    print();
  });
}
           
【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

修改

print.js

,檢視效果

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

可以發現,

print.js

會重新更新,但

index.js

不會變,即

index.js

不會重新加載,樣式和結構也不會重新加載,這就是js檔案的HMR功能的使用

注意:HMR功能對js的處理,隻能處理非入口js檔案的其他檔案。

為什麼呢?

因為入口檔案會将其他檔案全部引入,一旦入口檔案變化,其他檔案重新引入,就會重新加載,這是沒辦法阻止的,是以入口檔案是做不了HMR功能的,隻能對入口檔案引入的一些依賴或者其他檔案做HMR功能。

比如修改入口檔案下面的列印代碼:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

儲存,可以發現所有東西都要重新打包建構:

【Webpack 性能優化系列(1) - HMR 熱子產品替換】webpack性能優化HMR 熱子產品替換參考

參考

  • https://www.bilibili.com/video/BV1e7411j7T5?p=17&spm_id_from=pageDriver