Hot Module Replacement熱更新(webpack學習篇9)

模塊熱替換(HMR - Hot Module Replacement)作用:是指在應用程序運行過程中替換、添加或刪除模塊,而無需重新加載整個頁面。主要是通過以下幾種方式,來顯著加快開發速度:

  • 保留在完全重新加載頁面時丟失的應用程序狀態。
  • 只更新變更內容,以節省寶貴的開發時間。
  • 調整樣式更加快速 - 幾乎相當於在瀏覽器調試器中更改樣式。

熱更新配置:(在devServer對象裏配置)

webpack.config.js

// 在這裏做打包配置
const path = require('path'); // 引入node的path模塊(loader模塊)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 引入熱更新插件,爲webpack中自帶的插件
const webpack = require('webpack');

// Common.js語法
module.exports = {
  mode: 'development', // 默認模式爲production,可不寫,不寫時打包運行命令行會有警告
  devtool: 'cheap-module-eval-source-map',
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    open: true,
    port: 8080,
    hot: true, // 讓webpack-dev-server開啓熱更新的功能
    hotOnly: true // 即便是hot配置(HMR)沒有生效,也不讓瀏覽器進行刷新,失效時不做其他處理
  }, 
  module: {
    rules: [{
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader'
      ]
    }]
  },
  plugins: [
  	new HtmlWebpackPlugin({
      template: './src/index.html'
    }), 
    new CleanWebpackPlugin(),
    new webpack.HotModuleReplacementPlugin() // 實例化熱更新插件
  ],
  output: {
    filename: 'dist.js', // 打包之後的輸出文件
    path: path.resolve(__dirname, 'dist') 
  }
}

// 配置完之後,一定要重新執行打包,不然配置項不會生效
// 樣式文件變化,頁面只修改展示樣式,不會進行頁面的刷新操作,也不會更改之前js操作的內容。

配置項的作用:

  • hot: true ===> 讓webpack-dev-server開啓熱更新的功能
  • hotOnly: true ===> 即便是hot配置(HMR)沒有生效,也不讓瀏覽器進行刷新 (失效時不做其他處理)
  • HotModuleReplacementPlugin爲webpack自帶的熱更新插件,所以要直接引入webpack,在plugins配置項中進行實例化。

熱更新的應用:

在css方面應用:

目錄結構:

|--demo
	|--node_modules
	|--src
		|--index.js
		|--style.css
		|--index.html
	|--package.json
	|--package-lock.json
	|--webpack.config.js

src/style.css

div:nth-of-type(odd) {
  background: #2086d7;
}

src/index.js

import './style.css';
var btn = document.createElement('button');
btn.innerHTML = '新增';
document.body.appendChild(btn);
btn.onclick = function() {
  var div = document.createElement('div');
  div.innerHTML = 'item'; 
  document.body.appendChild(div);
}

執行打包:

npm  run  start

頁面展示效果如圖:(點擊新增按鈕,新增item項之後的效果)

此時,再去修改style.css裏的樣式:(把偶數行的背景色改爲粉色)

div:nth-of-type(odd) {
  background: pink;
}

頁面展示效果爲:(沒有刷新瀏覽器,只更改了樣式)

如果不開啓熱更新,修改樣式之後,由於瀏覽器刷新,頁面會恢復到初始狀態,頁面上只保留一個"新增"按鈕,再去點擊的時候,纔會有不同顏色的item顯示在頁面中。

在js方面的應用:

目錄結構:

|--demo
	|--node_modules
	|--src
		|--counter.js
		|--number.js
		|--index.js
		|--index.html
	|--package-lock.json
	|--package.json
	|--webpack.config.js

counter.js

function counter() {
  var div = document.createElement('div');
  div.setAttribute('id', 'counter');
  div.innerHTML = 1;
  div.onclick = function() {
    div.innerHTML = parseInt(div.innerHTML, 10) + 1
  }
  document.body.appendChild(div);
}

export default counter;

number.js

function number() {
  var div = document.createElement('div');
  div.setAttribute('id', 'number');
  div.innerHTML = 1000; 
  document.body.appendChild(div);
}
export default number;

index.js

import counter from './counter';
import number from './number';
counter();
number();

// 這裏需要判斷下是否開啓了熱更新,如果開啓了,就只讓number函數再執行一次,否則不會熱更新
if(module.hot) {
  module.hot.accept('./number', () => {
    document.body.removeChild(document.getElementById('number'));
    number();
  })
}

本質上要實現HMR,都要寫類似以上(判斷是否開啓熱更新,單獨執行某代碼塊)的代碼,否則不會熱更新。但在很多時候,我們開發過程中,並沒有去寫這樣的代碼,是因爲在相應的loader中,已經幫我們實現了熱更新的代碼。如:

  • css-loader中同樣也配置了熱更新,也不需要自己額外添加代碼
  • 我們使用的vue框架裏,vue-loader裏也已經配置了熱更新,所以不需要額外添加代碼

index.js中引入兩個模塊,如果不開啓熱更新,那麼當一個模塊裏的數據變化了,就會導致頁面刷新,使另一個模塊內的數據也恢復到初始值,如果我們想一個模塊裏的js代碼的變化,不影響另一個模塊代碼變更過的數據,每改一個js模塊裏的代碼,只會更新當前模塊的數據,不會影響其他js模塊的數據。以上需求可藉助HMR來實現,

執行打包:

npm  run  start

頁面展示效果:(第一行數字帶有點擊事件,初始值爲1,每點擊一次數值會加1)

當點擊數字值增加爲7時,去修改number.js模塊裏的代碼,把1000修改爲3000,此時頁面不刷新,counter.js模塊裏的數字7也沒有變化,只更改了當前模塊修改的數據。如下圖:

這就是熱更新的巧妙之處。? (如果不開啓熱更新,修改number.js裏的代碼後,由於頁面會刷新,counter.js裏的數字也會變成初始值1)

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