熱模組替換

如果已透過 HotModuleReplacementPlugin 啟用 熱模組替換,其介面會在 module.hot 屬性以及 import.meta.webpackHot 屬性下公開。請注意,只有 嚴格 ESM 中可以使用 import.meta.webpackHot

通常,使用者會檢查介面是否可存取,然後開始使用它。以下是一個範例,說明您如何 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:使用 ESM 相依性時,由第二個參數中的 callback 或相依性執行期間引發的錯誤。
  • 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。常見的場景是再次自我接受。加入處置處理常程式以傳遞資料也很有意義。請注意,錯誤模組可能已經部分執行,因此請務必不要進入不一致的狀態。您可以使用 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();
}

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
檢查程序正在檢查更新
prepare程序正在準備更新(例如下載更新的模組)
ready更新已準備好且可用
dispose程序正在呼叫將被替換的模組上的 dispose 處理常式
套用程序正在呼叫 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);

6 貢獻者

sokraskipjacktbroadleybyzykwizardofhogwartssnitin315