1. 程式人生 > >Webpack & The Hot Module Replacement

Webpack & The Hot Module Replacement

Legend:
Green — Webpack-dev-server related libs.
Blue — Webpack core and plugin libs.
Orange — chunk manifest or chunk JS file itself.
Red — React-loader or Style-loader HMR libs.
Teal — Your App
Purple — File or module that just changed.A JS or CSS file (module) changes
  1. Webpack uses HotModuleReplacementPlugin to generate a manifest
    (a JSON containing list of changed modules) and an update file(a JS with the actual change info).
  2. Webpack then tells webpack-dev-server about the changes
  3. webpack-dev-server tells “webpack-dev-server/client”(JS file) running in the browser via webSocket by sending “invalid” notification via WebSocket.
  4. “webpack-dev-server/client” then sends the initial hash(e.g. b2e2d54372f42c1b2352)
    that it got when the app was first loaded to hot/dev-server library. “hot/dev-server” acts like the main interface to all other JS files.
  5. “hot/dev-server” then calls internal libraries(like JSONP runtime) that are also injected by Webpack to download the manifest file.
  6. JSONP runtime uses hash and loads the manifest file from the webpack-dev-server.
  7. The manifest file contains details about chunks that need to be uploaded to the browser. It’s file name looks like: b2e2d54372f42c1b2352.hot-update.json and it’s content looks like this: {“h”:”b3632c2a800d437e17df”,”c”:[0]}
  8. JSONP runtime then uses information contained inside the manifest file to load all the “Update” files and adds them to the DOM.
  9. “Updates JS” themselves are JS files. They contain information about actual changes that needs to be applied. They are added to the DOM and executed.
//Example: 0.b2e2d54372f42c1b2352.hot-update.js chunk
//Notice that the chunk is actually a function call to "webpackHotUpdate" HMR function. So when the chunk is loaded to the DOM, this function instantly called with the Chunk's info.
//In this case, style-loader is telling HMR about a new CSS class:
//input { background: pink;} for module id "82"

webpackHotUpdate(0,
{
82:
function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(79)();
exports.push([module.id, “input {\n background: pink;\n}”, “”])
}
})

11. Updates call HMR runtime with the module id (e.g. moduleId “82” in the above example) and the actual changes.

12. But HMR runtime itself doesn’t know how to deal with the changes. So it delegates this job to corresponding loaders like react-hot-loader runtimes or style-loader runtimes to apply changes. (Note these are also injected into the Browser).

13. If there is no issues with applying the changes, the appropriate runtimes updates the module.

14. If there are issues (like syntax errors in the change), “hot/dev-server” lib is notified about the error. Note: if you are using “hot/dev-only-server”, an alternative to “hot/dev-server” then browser won’t reload.

A Deeper Look

Let’s take an example to see some of the above steps in details. Below is simple app that has a field and loads CSS (via css-loader and style-loader). The CSS currently changes body’s background color to gray.

With HMR working, if we change the background to green in the style.css file, HMR updates the app’s background to green without removing the text inside the input field (i.e. doesn’t reloads the browser and keeps the “state” as is).

0. Initial setup

Initially when you setup webpack-dev-server using — inline and — hot.

Note: You can click on the pictures to zoom and read

1. File Changed

Webpack along with HMR plugin generates a manifest file “<previousHash>.hot-update.json” and the update file “<cunkNumber>.<previousHash>.hot-update.js”.

Note the previousHash is the hash that’s generated when the app was first loaded and every time it’s patched. When ever there is a change to the modules, the “previousHash” is used to load new files and then a new hash is generated and set as “previousHash” and the cycle continues.

2. Update Client about the changes on the server

webpack-dev-server constantly communicates with the client about the changes via webSocket.

3. Upload changes

When webpack-dev-server receives “Invalid” notification via webSocket, it asks HMR libraries running in the client (browser) to load new files. The libraries use the current hash (e3472f4aac7404e2e5b2) and use it as part of the file name for manifest (e3472f4aac7404e2e5b2.hot-update.json) file and also for the changed file (0.e3472f4aac7404e2e5b2.hot-update.js). Note that the “0” is the chunk number.

websocket, manifest and update files

Below picture shows the contents of the manifest file

manifest w/ details about the changes

4. Apply Changes

Below picture shows contents of the update file. Notice that it’s calling “webpackHotUpdate” function. So when this JS file is added to the DOM, it passes the details like module id, “78” and raw changes like (“background: green”) to the HMR runtime. HMR Runtime then passes this info the correct loader (i.e. style-loader HMR runtime) that knows how to deal with this change.

final logs after changes are made

That’s it!