preface

It was easy to confuse hot overloading with module hot replacement until I realized there were a few differences between the two when I implemented it myself.

  • Hot loading can be done by enabling webpack-dev-server and refreshing the entire page with each code change
  • Module hot replacement also known as HMR, when code is updated only the modified part of the update shows HMR benefits over hot loading:
  • More convenient for style debugging
  • Only the parts of the modified code are updated to improve development efficiency
  • Preserve application state that is lost when the page is fully reloaded.

Realize the HMR

HMR has two implementations, one kind is through plug-ins HotModuleReplacementPlugin and devserver match and implementation, one kind is through under the custom development services, Use webpack-dev-Middleware and webpack-hot-middleware to implement HMR

Through plug-ins HotModuleReplacementPlugin ()

1. Configure devServer in webpack.config.js

	devServer: {
		contentBase: './dist'.// create a server in the dist folder
		open: true.// Automatically opens the browser and accesses the server address
		port: 8085.hot: true.// Enable HMR
                 hotOnly: true   // Even if HMR is not in effect, it does not refresh automatically
	},
Copy the code

The use of HotModuleReplacementPlugin plug-in pluginsp configuration

    plugins: [
   ...// Other plug-ins
    new webpack.HotModuleReplacementPlugin()
    ],
Copy the code

If you don’t want to do the following, you can use module.hot.accept() to update the entire project as soon as there are code changes.

if(module.hot) {
    module.hot.accept('./number', () = > {// Use the updated Library module to perform some operations...})}Copy the code

3. The most important thing about startup: Don’t forget to modify the startup command

    "start": "webpack-dev-server"
Copy the code

At this point, run NPM start to realize hot update of the module

Through the Node. Js API

Hmr. 1 is implemented by building a local server and using webpack-dev-middleware and Webpack-hot-middleware plug-ins. The installation

// Install Express, webpack-dev-middleware, webpack-hot-middleware
cnpm install express webpack-dev-middleware webpack-Hot-middleware -D
Copy the code

2. Configure dev.server.js dev.server.js

const path = require('path');
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require("webpack-Hot-middleware")
const config = require('./webpack.dev.js');

const complier = webpack(config);   // The compiler repackages the code once it executes
const app = express();  // Generate an instance
const {devServer: {port, contentBase}} = config
const DIST_DIR = path.resolve(__dirname, '.. / ', contentBase);  // Set the static access file path
// Equivalent to const DIST_DIR = path.resolve(__dirname, '.. /dist');


let devMiddleware = webpackDevMiddleware(complier, {  // Use the compiler
    publicPath: config.output.publicPath,
    quiet: true.// Display anything to the console
    noInfo: true
})

let hotMiddleware = webpackHotMiddleware(complier,{
    log: false.heartbeat: 2000
 })

app.use(devMiddleware)

app.use(hotMiddleware)

// Set the path to access static files
app.use(express.static(DIST_DIR))


app.listen(port, () => {
    console.log("Successful startup: localhost:"+ port)
})  // Listen on the port
Copy the code

Webpack. Dev. Js configuration

module.exports = {
        entry: {             // Import file configuration
        Webpack-hot-middleware /client? NoInfo =true&reload=true is mandatory
        main: ['webpack-hot-middleware/client? noInfo=true&reload=true'.'./src/index.js']},devServer: {
        contentBase: 'dist'.port: 8081
    },
       plugins: [  
        new webpack.NamedModulesPlugin(),  // Used to display the relative path of the module when starting HMR
        new webpack.HotModuleReplacementPlugin(), 
        new OpenBrowserPlugin({ url: 'http://localhost:8081' }), // Automatically open the browser],...// Other configurations
}
Copy the code

The full implementation is here

Configuration item for Webpack-hot-middleware

Configuration items can be added to the webpack Config path via query to be passed to the client

  • Path – The path provided by the middleware for the event flow
  • Name – Bundle name, specifically for multi-compiler mode
  • Timeout – The time to wait after disconnecting after attempting to reconnect
  • Overlay – Set to false disables DOM-based client overlays.
  • Reload – Set to true to automatically reload the page if the Webpack gets stuck.
  • NoInfo – Set to true disables information console logging.
  • Quiet – Set to true to disable all console logging.
  • DynamicPublicPath – Set to true using webpack publicPath as the prefix for path. (We can set __webpack_public_path__ dynamically at runtime at the entry point, see the comment output.-publicpath.)
  • AutoConnect – Set to false to prevent the connection from the client from automatically opening to the Webpack back end – modify the option if necessary using the setOptionsAndConnect feature

By passing the second parameter, configuration options can be passed to the middleware

webpackHotMiddleware(webpack,{
    log: false.path: "/__what".heartbeat: 2000
})
Copy the code
  • Log – A function for logging rows, passing false to disable. Defaults to the console. The log
  • Path – The middleware must match the path of the service event flow with the client Settings
  • Heartbeat – How long it takes to send heartbeat updates to clients to keep the connection active. Should be smaller than the client’s timeout setting – usually set to half its value. More webpack-hot-Middleware configurations are available here

Note: After starting the server with Express, the configuration in devServer does not take effect.

3. Start the command

    "start": "node ./build/dev-server.js".Copy the code

To implement the HMR function, run the NPM start command

HMR implementation principle

1. Update process of HMR

  • One or more files have been modified.
  • The file system receives the changes and notifies Webpack.
  • Webpack recompiles to build one or more modules and notifies the HMR server of the update.
  • HMR Server uses WebSockets to notify HMR Runtime that an update is needed. (The HMR runtime requests these updates over HTTP.)
  • The HMR runtime replaces the updated module. If it is determined that these modules cannot be updated, a full page refresh is triggered

2.HMR Workflow Diagram This is a more detailed process analysis:

  • The red box at the bottom of the image is the server side, and the orange box above is the browser side.
  • The green boxes are the areas controlled by the WebPack code. The blue box is the area controlled by the WebPack-dev-server code, the magenta box is the file system where the changes to the modified files occur, and the cyan box is the application itself:
  • First, in Webpack’s Watch mode, a file in the file system changes, WebPack listens to the file changes, recompiles and packages the module according to the configuration file, and saves the packaged code in memory through a simple JavaScript object.
  • The second step is the interface interaction between Webpack-dev-server and Webpack. In this step, it’s mainly the interaction between Webpack-Dev-middleware of Dev-server and Webpack. Webpack-dev-middleware calls the API exposed by Webpack to monitor code changes and tells Webpack to pack the code into memory.
  • The third step is a monitoring of file changes by Webpack-dev-server, which is different from the first step in that it does not monitor code changes for repackaging. . When we are in the configuration file is configured with devServer watchContentBase to true, the Server will listen to these configuration static files in the folder change, change will notify the browser after the live for the application to reload. Notice that this is browser refresh, and HMR are two different things.
  • The fourth step is also the work of the webpack-dev-server code. This step mainly uses sockJS (webpack-dev-server dependency) to establish a websocket long connection between the browser and the server. This tells the browser about the status of the various stages of the Webpack compilation and packaging, as well as the information that the Server listens for static file changes in step 3. The browser performs different operations based on these socket messages. Of course, the most important information passed by the server is the hash value of the new module, and the subsequent steps use this hash value to perform module hot replacement.
  • The webpack-dev-server/client cannot request updated code and does not perform hot module operations, handing the work back to Webpack. The job of webpack/hot/dev-server is to decide whether to refresh the browser or hot update the module based on the information passed to it by webpack-dev-server/client and the configuration of dev-server. Of course, if you just refresh the browser, there are no further steps.
  • HotModuleReplacement runtime is the centre of the client HMR, step on it receives hash value passed to his new module, it through JsonpMainTemplate. Runtime sends an Ajax request to the server end, The server returns a JSON that contains the hash values of all the modules to be updated. Once the updated list is retrieved, the module requests the latest module code again via JSONP. These are steps 7, 8 and 9 in the figure above.
  • In step 10, the HotModulePlugin will compare the old and new modules and decide whether to update the module. After the decision is made, the dependency relationship between the modules will be checked and the dependency references between the modules will be updated.
  • As a final step, when HMR fails, we fall back to live Reload, which is a browser refresh to get the latest packaging code.

Refer to the link

  • Module hot replacement
  • Webpack HMR principle analysis