Webpack 模塊熱替換(hot module replacement)

2023-05-15 17:26 更新

模塊熱替換(HMR - hot module replacement)功能會(huì)在應(yīng)用程序運(yùn)行過程中,替換、添加或刪除 模塊,而無需重新加載整個(gè)頁面。主要是通過以下幾種方式,來顯著加快開發(fā)速度:

  • 保留在完全重新加載頁面期間丟失的應(yīng)用程序狀態(tài)。
  • 只更新變更內(nèi)容,以節(jié)省寶貴的開發(fā)時(shí)間。
  • 在源代碼中 CSS/JS 產(chǎn)生修改時(shí),會(huì)立刻在瀏覽器中進(jìn)行更新,這幾乎相當(dāng)于在瀏覽器 devtools 直接更改樣式。

這一切是如何運(yùn)行的?

讓我們從一些不同的角度觀察,以了解 HMR 的工作原理……

在應(yīng)用程序中

通過以下步驟,可以做到在應(yīng)用程序中置換(swap in and out)模塊:

  1. 應(yīng)用程序要求 HMR runtime 檢查更新。
  2. HMR runtime 異步地下載更新,然后通知應(yīng)用程序。
  3. 應(yīng)用程序要求 HMR runtime 應(yīng)用更新。
  4. HMR runtime 同步地應(yīng)用更新。

你可以設(shè)置 HMR,以使此進(jìn)程自動(dòng)觸發(fā)更新,或者你可以選擇要求在用戶交互時(shí)進(jìn)行更新。

在 compiler 中

除了普通資源,compiler 需要發(fā)出 "update",將之前的版本更新到新的版本。"update" 由兩部分組成:

  1. 更新后的 manifest (JSON)
  2. 一個(gè)或多個(gè) updated chunk (JavaScript)

manifest 包括新的 compilation hash 和所有的 updated chunk 列表。每個(gè) chunk 都包含著全部更新模塊的最新代碼(或一個(gè) flag 用于表明此模塊需要被移除)。

compiler 會(huì)確保在這些構(gòu)建之間的模塊 ID 和 chunk ID 保持一致。通常將這些 ID 存儲(chǔ)在內(nèi)存中(例如,使用 webpack-dev-server 時(shí)),但是也可能會(huì)將它們存儲(chǔ)在一個(gè) JSON 文件中。

在模塊中

HMR 是可選功能,只會(huì)影響包含 HMR 代碼的模塊。舉個(gè)例子,通過 ?style-loader? 為 style 追加補(bǔ)丁。為了運(yùn)行追加補(bǔ)丁,?style-loader? 實(shí)現(xiàn)了 HMR 接口;當(dāng)它通過 HMR 接收到更新,它會(huì)使用新的樣式替換舊的樣式。

類似的,當(dāng)在一個(gè)模塊中實(shí)現(xiàn)了 HMR 接口,你可以描述出當(dāng)模塊被更新后發(fā)生了什么。然而在多數(shù)情況下,不需要在每個(gè)模塊中強(qiáng)行寫入 HMR 代碼。如果一個(gè)模塊沒有 HMR 處理函數(shù),更新就會(huì)冒泡(bubble up)。這意味著某個(gè)單獨(dú)處理函數(shù)能夠更新整個(gè)模塊樹。如果在模塊樹的一個(gè)單獨(dú)模塊被更新,那么整組依賴模塊都會(huì)被重新加載。

在 runtime 中

對于模塊系統(tǒng)運(yùn)行時(shí)(module system runtime),會(huì)發(fā)出額外代碼,來跟蹤模塊 ?parents? 和 ?children? 關(guān)系。在管理方面,runtime 支持兩個(gè)方法 ?check? 和 ?apply?。

?check? 方法,發(fā)送一個(gè) HTTP 請求來更新 manifest。如果請求失敗,說明沒有可用更新。如果請求成功,會(huì)將 updated chunk 列表與當(dāng)前的 loaded chunk 列表進(jìn)行比較。每個(gè) loaded chunk 都會(huì)下載相應(yīng)的 updated chunk。當(dāng)所有更新 chunk 完成下載,runtime 就會(huì)切換到 ?ready? 狀態(tài)。

?apply? 方法,將所有 updated module 標(biāo)記為無效。對于每個(gè)無效 module,都需要在模塊中有一個(gè) update handler,或者在此模塊的父級模塊中有 update handler。否則,會(huì)進(jìn)行無效標(biāo)記冒泡,并且父級也會(huì)被標(biāo)記為無效。繼續(xù)每個(gè)冒泡,直到到達(dá)應(yīng)用程序入口起點(diǎn),或者到達(dá)帶有 update handler 的 module(以最先到達(dá)為準(zhǔn),冒泡停止)。如果它從入口起點(diǎn)開始冒泡,則此過程失敗。

之后,所有無效 module 都會(huì)被(通過 dispose handler)處理和解除加載。然后更新當(dāng)前 hash,并且調(diào)用所有 ?accept? handler。runtime 切換回 ?idle? 狀態(tài),一切照常繼續(xù)。

起步

在開發(fā)環(huán)境,可以將 HMR 作為 LiveReload 的替代。webpack-dev-server 支持 ?hot? 模式,在試圖重新加載整個(gè)頁面之前,?hot? 模式會(huì)嘗試使用 HMR 來更新。更多細(xì)節(jié)請查看 模塊熱替換 指南。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號