webpack dev server自動(dòng)刷新問題:自動(dòng)刷新導(dǎo)致頁面狀態(tài)丟失
每次修改完代碼,webpack監(jiān)視到變化,自動(dòng)打包,并通過瀏覽器自動(dòng)刷新,一旦頁面整體刷新,頁面中的任何操作狀態(tài)都會(huì)丟失
HMR(Hot Module Replacement模塊熱替換)
”熱拔插“ 計(jì)算機(jī)正在運(yùn)行,插上去的設(shè)備可以立即工作,“熱"指在運(yùn)行過程中的即時(shí)變化
webpack模塊熱替換,實(shí)時(shí)的替換掉應(yīng)用中某個(gè)模塊,整體運(yùn)行狀態(tài)不會(huì)因此改變 例如上面的問題,使用HMR 就可以實(shí)現(xiàn)將修改的模塊實(shí)時(shí)替換到應(yīng)用中,不整體刷新
HMR是Webpack中最強(qiáng)大的功能之一,極大程度提高了開發(fā)者的工作效率
開啟HMR
兩種方式
運(yùn)行命令webpack-dev-server --hot 開啟
-
將devServer對(duì)象的hot屬性設(shè)置未true,然后需導(dǎo)入插件HotModuleReplacementPlugin
const webpack = require('webpack') module.exports = { ... plugins: [ ... new webpack.HotModuleReplacementPlugin() ] }
css文件熱更新正常 js文件熱更新頁面自動(dòng)刷新,狀態(tài)丟失
HMR疑問
HMR并不像webpack其他特性一樣開箱即用,需要額外操作(手動(dòng)通過代碼處理 當(dāng)模塊更新過后 如何把更新后模塊替換到頁面中)
-
為什么樣式文件熱更新?
樣式文件經(jīng)過loader處理,在style-loader中已經(jīng)自動(dòng)處理了樣式文件的熱更新 不需要額外手動(dòng)處理
-
為什么腳本需要自己手動(dòng)處理?
樣式文件更新后,只需把更新后的CSS及時(shí)替換到頁面中,覆蓋之前樣式,實(shí)現(xiàn)更新
而JavaScript模塊沒有規(guī)律,可能導(dǎo)出對(duì)象、字符串或函數(shù),webpack面對(duì)毫無規(guī)律的JS模塊,不知道怎么處理更新后的模塊,也就無法直接實(shí)現(xiàn)一個(gè)可以通用所有情況的模塊替換方案
-
為什么vue-cli、create-react-app腳手架javaScript代碼會(huì)熱更新?
框架中每個(gè)文件都有規(guī)律,例如react要求每個(gè)模塊導(dǎo)出必須是一個(gè)函數(shù)或類,這樣就有了通用的替換方法
HMR APIs
HotModuleReplacementPlugin提供一套處理HMR的API,使用這些API將更新后的模塊替換到正在運(yùn)行的頁面源代碼
// HMR 手動(dòng)處理模塊熱更新
// 不用擔(dān)心這些代碼在生產(chǎn)環(huán)境冗余的問題,因?yàn)橥ㄟ^ webpack 打包后,
// 這些代碼全部會(huì)被移除,這些只是開發(fā)階段用到
if (module.hot) {
// HMR失敗后自動(dòng)回退到自動(dòng)刷新 頁面自動(dòng)刷新 控制臺(tái)的錯(cuò)誤信息會(huì)被清除
let hotEditor = editor
// 第一個(gè)參數(shù)接收的就是所監(jiān)視的依賴模塊路徑 第二個(gè)參數(shù)就是依賴模塊更新后的處理函數(shù)
// editor.js更新被手動(dòng)處理后 就不會(huì)觸發(fā)自動(dòng)刷新
module.hot.accept('./editor.js', () => {
// 當(dāng) editor.js 更新,自動(dòng)執(zhí)行此函數(shù)
// 臨時(shí)記錄編輯器內(nèi)容
const value = hotEditor.innerHTML
// 移除更新前的元素
document.body.removeChild(hotEditor)
// 創(chuàng)建新的編輯器
// 此時(shí) createEditor 已經(jīng)是更新過后的函數(shù)了
hotEditor = createEditor()
// 還原編輯器內(nèi)容
hotEditor.innerHTML = value
// 追加到頁面
document.body.appendChild(hotEditor)
})
module.hot.accept('./better.png', () => {
// 當(dāng) better.png 更新后執(zhí)行
// 重寫設(shè)置 src 會(huì)觸發(fā)圖片元素重新加載,從而局部更新圖片
img.src = background
})
// style-loader 內(nèi)部自動(dòng)處理更新樣式,所以不需要手動(dòng)處理樣式模塊
}
注意
-
處理HMR的代碼報(bào)錯(cuò)會(huì)導(dǎo)致自動(dòng)刷新
devServer: { // hot: true熱替換失敗就會(huì)自動(dòng)回退使用自動(dòng)刷新 hotOnly: true hotOnly 的情況下并不會(huì)使用自動(dòng)刷新 } | -
使用HMR提供的API,但啟動(dòng)webpsck-dev-serve時(shí)未開啟HMR
// HMR 手動(dòng)處理模塊熱更新 // 不用擔(dān)心這些代碼在生產(chǎn)環(huán)境冗余的問題,因?yàn)橥ㄟ^ webpack 打包后, // 這些代碼全部會(huì)被移除,這些只是開發(fā)階段用到 if (module.hot) { ... }