CC 4.0 授權

本節內容衍生自以下連結的內容,並受 CC BY 4.0 授權約束。

如果未特別聲明,以下內容可視為在原始內容基礎上進行修改和刪除的結果。

熱模組替換

通常,使用者會檢查介面是否可存取,然後開始使用它。 例如,以下是如何 accept 更新模組的方法

if (module.hot) {
  module.hot.accept('./library.js', function () {
    // Do something with the updated library module...
  });
}

// or
if (import.meta.webpackHot) {
  import.meta.webpackHot.accept('./library.js', function () {
    // Do something with the updated library module…
  });
}

支援以下方法...

模組 API

accept

接受給定 dependencies 的更新,並觸發一個 callback 來對這些更新做出反應,此外,您可以附加一個可選的錯誤處理程式

module.hot.accept(
  dependencies, // Either a string or an array of strings
  callback, // Function to fire when the dependencies are updated
  errorHandler, // (err, {moduleId, dependencyId}) => {}
);

// or
import.meta.webpackHot.accept(
  dependencies, // Either a string or an array of strings
  callback, // Function to fire when the dependencies are updated
  errorHandler, // (err, {moduleId, dependencyId}) => {}
);

當使用 ESM import 時,來自 dependencies 的所有匯入符號都會自動更新。 注意:相依性字串必須與 import 中的 from 字串完全匹配。 在某些情況下,甚至可以省略 callback。 在此處的 callback 中使用 require() 沒有意義。

當使用 CommonJS 時,您需要透過在 callback 中使用 require() 手動更新相依性。 在此處省略 callback 沒有意義。

accept 的 errorHandler

(err, {moduleId, dependencyId}) => {}

  • err:在第二個引數中的 callback 或在使用 ESM 相依性時相依性執行期間拋出的錯誤。
  • moduleId:目前的模組 id。
  • dependencyId:(第一個) 變更的相依性的模組 id。

accept (self)

接受本身的更新。

module.hot.accept(
  errorHandler, // Function to handle errors when evaluating the new version
);

// or
import.meta.webpackHot.accept(
  errorHandler, // Function to handle errors when evaluating the new version
);

當此模組或相依性更新時,可以處置並重新評估此模組,而無需通知父模組。 如果此模組沒有匯出 (或匯出以其他方式更新),則此方法才有意義。

當評估此模組 (或相依性) 拋出例外狀況時,將會觸發 errorHandler

用於 self accept 的 errorHandler

(err, {moduleId, module}) => {}

  • err:評估新版本時發生的錯誤。
  • moduleId:目前的模組 id。
  • module:目前的模組實例。
    • module.hot:允許使用發生錯誤的模組實例的 HMR API。 一種常見的情況是再次 self accept 它。 此外,新增 dispose 處理程式以傳遞資料也很有意義。 請注意,發生錯誤的模組可能已部分執行,因此請確保不會進入不一致的狀態。 您可以使用 module.hot.data 來儲存部分狀態。
    • module.exports:可以覆寫,但請小心,因為屬性名稱可能會在生產模式中被混淆。

decline

拒絕給定 dependencies 的更新,強制更新失敗並返回 'decline' 程式碼。

module.hot.decline(
  dependencies, // Either a string or an array of strings
);

// or
import.meta.webpackHot.decline(
  dependencies, // Either a string or an array of strings
);

將相依性標記為不可更新。 當無法處理或尚未實作處理此相依性的匯出變更時,此方法才有意義。 根據您的 HMR 管理程式碼,通常更新這些相依性 (或未接受的相依性) 會導致頁面重新載入。

decline (self)

拒絕本身的更新。

module.hot.decline();

// or
import.meta.webpackHot.decline();

將此模組標記為不可更新。 當此模組具有不可逆的副作用,或尚未針對此模組實作 HMR 處理時,此方法才有意義。 根據您的 HMR 管理程式碼,通常更新此模組 (或未接受的相依性) 會導致頁面重新載入。

dispose (或 addDisposeHandler)

新增一個處理程式,當目前的模組程式碼被取代時,將會執行此處理程式。 這應該用於移除您聲明或建立的任何持續性資源。 如果您想要將狀態傳輸到更新後的模組,請將其新增至給定的 data 參數。 此物件將在更新後於 module.hot.data 中提供。

module.hot.dispose(data => {
  // Clean up and pass data to the updated module...
});

// or
import.meta.webpackHot.dispose(data => {
  // Clean up and pass data to the updated module...
});

invalidate

呼叫此方法將會使目前的模組失效,這會在套用 HMR 更新時處置並重新建立它。 這會像此模組的正常更新一樣傳播。 此模組無法自行接受 invalidate

idle 狀態期間呼叫時,將會建立一個新的 HMR 更新,其中包含此模組。 HMR 將進入 ready 狀態。

readyprepare 狀態期間呼叫時,此模組將會新增至目前的 HMR 更新。

check 狀態期間呼叫時,如果有更新可用,此模組將會新增至更新。 如果沒有可用的更新,將會建立新的更新。 HMR 將進入 ready 狀態。

disposeapply 狀態期間呼叫時,HMR 將會在脫離這些狀態後將其擷取。

使用案例

條件式接受

模組可以接受相依性,但在無法處理相依性的變更時,可以呼叫 invalidate

import { x, y } from './dep';
import { processX, processY } from 'anotherDep';

const oldY = y;

processX(x);
export default processY(y);

module.hot.accept('./dep', () => {
  if (y !== oldY) {
    // This can't be handled, bubble to parent
    module.hot.invalidate();
    return;
  }
  // This can be handled
  processX(x);
});

條件式自我接受

模組可以自我接受,但在無法處理變更時,可以使自己失效

const VALUE = 'constant';

export default VALUE;

if (
  module.hot.data &&
  module.hot.data.value &&
  module.hot.data.value !== VALUE
) {
  module.hot.invalidate();
} else {
  module.hot.dispose(data => {
    data.value = VALUE;
  });
  module.hot.accept();
}

觸發自訂 HMR 更新

const moduleId = chooseAModule();
const code = __webpack_modules__[moduleId].toString();
__webpack_modules__[moduleId] = eval(`(${makeChanges(code)})`);
if (require.cache[moduleId]) {
  require.cache[moduleId].hot.invalidate();
  module.hot.apply();
}

T> 當呼叫 invalidate 時,最終會呼叫dispose處理程式並填入 module.hot.data。 如果未註冊dispose處理程式,則將會為 module.hot.data 提供一個空物件。

W> 請勿陷入 invalidate 迴圈,再次呼叫 invalidate。 這會導致堆疊溢位,且 HMR 會進入 fail 狀態。

removeDisposeHandler

移除透過 disposeaddDisposeHandler 新增的處理程式。

module.hot.removeDisposeHandler(callback);

// or
import.meta.webpackHot.removeDisposeHandler(callback);

管理 API

狀態

檢索熱模組替換程序的目前狀態。

module.hot.status(); // Will return one of the following strings...

// or
import.meta.webpackHot.status();
狀態 描述
閒置 (idle) 程序正在等待呼叫 check
檢查 (check) 程序正在檢查更新
準備 (prepare) 程序正在為更新做準備 (例如,下載更新後的模組)
就緒 (ready) 更新已準備就緒並可用
處置 (dispose) 程序正在對將被替換的模組呼叫 dispose 處理程序
套用 (apply) 程序正在呼叫 accept 處理程序並重新執行自我接受的模組
中止 (abort) 更新已中止,但系統仍處於先前的狀態
失敗 (fail) 更新拋出例外,系統狀態已受損

檢查 (check)

測試所有已載入的模組是否有更新,如果存在更新,則 apply 它們。

module.hot
  .check(autoApply)
  .then(outdatedModules => {
    // outdated modules...
  })
  .catch(error => {
    // catch errors
  });

// or
import.meta.webpackHot
  .check(autoApply)
  .then(outdatedModules => {
    // outdated modules...
  })
  .catch(error => {
    // catch errors
  });

autoApply 參數可以是布林值或傳遞給呼叫 apply 方法時的 options

套用 (apply)

繼續更新程序 (只要 module.hot.status() === 'ready')。

module.hot
  .apply(options)
  .then(outdatedModules => {
    // outdated modules...
  })
  .catch(error => {
    // catch errors
  });

// or
import.meta.webpackHot
  .apply(options)
  .then(outdatedModules => {
    // outdated modules...
  })
  .catch(error => {
    // catch errors
  });

可選的 options 物件可以包含以下屬性

  • ignoreUnaccepted (布林值): 忽略對未接受模組所做的變更。
  • ignoreDeclined (布林值): 忽略對已拒絕模組所做的變更。
  • ignoreErrored (布林值): 忽略在接受處理程序、錯誤處理程序和重新評估模組時拋出的錯誤。
  • onDeclined (函數(info)): 已拒絕模組的通知器
  • onUnaccepted (函數(info)): 未接受模組的通知器
  • onAccepted (函數(info)): 已接受模組的通知器
  • onDisposed (函數(info)): 已處置模組的通知器
  • onErrored (函數(info)): 錯誤的通知器

info 參數將會是一個包含以下某些值的物件

{
  type: 'self-declined' | 'declined' |
        'unaccepted' | 'accepted' |
        'disposed' | 'accept-errored' |
        'self-accept-errored' | 'self-accept-error-handler-errored',
  moduleId: 4, // The module in question.
  dependencyId: 3, // For errors: the module id owning the accept handler.
  chain: [1, 2, 3, 4], // For declined/accepted/unaccepted: the chain from where the update was propagated.
  parentId: 5, // For declined: the module id of the declining parent
  outdatedModules: [1, 2, 3, 4], // For accepted: the modules that are outdated and will be disposed
  outdatedDependencies: { // For accepted: The location of accept handlers that will handle the update
    5: [4]
  },
  error: new Error(...), // For errors: the thrown error
  originalError: new Error(...) // For self-accept-error-handler-errored:
                                // the error thrown by the module before the error handler tried to handle it.
}

addStatusHandler

註冊一個函數來監聽 status 的變更。

module.hot.addStatusHandler(status => {
  // React to the current status...
});

// or
import.meta.webpackHot.addStatusHandler(status => {
  // React to the current status...
});

請注意,當狀態處理程序返回 Promise 時,HMR 系統將等待 Promise 解析後才繼續。

removeStatusHandler

移除已註冊的狀態處理程序。

module.hot.removeStatusHandler(callback);

// or
import.meta.webpackHot.removeStatusHandler(callback);