Original is not easy, I hope you can pay attention to us, and then easily point a praise ~~
This post first appeared on the Front end team blog of THE Political Cloud: After reading this post, you will no longer be afraid of being asked about Webpack hot updates
preface
Webpack Hot Module Replacement (HMR), which updates all types of modules without completely refreshing the entire page, is one of the most useful features Webpack provides.
HMR as a Webpack built-in function, can pass – hot or HotModuleReplacementPlugin open.
Refresh can be divided into two types: one is page refresh, which does not retain the page state, that is, simple and violent, directly window.location.reload(); The other is module hot replacement based on WDS (Webpack-dev-server), which only needs to partially refresh the changed module on the page, while retaining the current page state, such as check box selected state, input box input, etc.
The benefits of HMR are well understood in daily development work: saving precious development time and improving development experience. To summarize, use the description on the official website:
The HMR-Hot Module replacement function replaces, adds, or removes modules while the application is running without reloading the entire page. Significantly speed up development in the following ways:
- Preserve application state that is lost during a full page reload.
- Update only the changes to save valuable development time.
- CSS/JS changes made in the source code are immediately updated in the browser, which is almost the same as changing styles directly in the browser DevTools.
In a development environment, HMR can be used as an alternative to LiveReload. So how does HMR implement hot update? Let’s take a look at the build process and analyze the source code.
This exploration relies on the company’s front-end Vue project to develop scaffolding configurations: Webpack + Webpack-dev-middleware + Webpack-hot-middleware + Express.
Webpack build
After the project is started, the first build package is performed, and the entire build process is printed in the console with a Hash value 3606e1AB1DDCF6626797.
Compiling appears on the console when you save after each code change. The words can be observed in the console:
-
The Hash value is updated to 4f8c0EFF7AC051C13277;
-
New generated file: 3606e1ab1DDCF6626797.hot-update. json
-
Main1.3606 e1ab1ddcf6626797. Hot – update. Js.
If nothing is changed, save it and the console prints the compilation and packaging information. The Hash value remains the same as 4f8c0EFF7AC051C13277.
Modify the code save again, and the console outputs the compile package information. Based on the file name, you can see that the Hash value generated last time is used as the identifier of the Hmr file generated this time. Similarly, the Hash value will be used as the identifier of the next hot update.
Webpack Watch
Why are changes saved automatically compiled and repackaged? This series of rechecks builds files that rely on Webpack listening: After the project is started, Webpack will start the compilation and construction process through the Run method of the Compiler class. After the compilation is completed, the Watch method will be called to monitor the file changes. When the file changes, it will be recompiled and continue to monitor after the compilation.
How do you pass the Webpack compiled and packaged files to a Web server that you rely on to access your pages? That’s where Webpack-dev-Middleware comes in. Webpack-dev-middleware is a wrapper, It can send webpack-processed files to a Server (where Webpack-dev-server has webpack-dev-Middleware and Express servers built in). While compiled files are written to memory, the Webpack-dev-Middleware plugin uses memory-FS for static resource requests to access memory files directly.
const webpack = require('webpack');
const webpackConfig = require('./webpack.dev.conf');
const compiler = webpack(webpackConfig);
debug('Webpack compiled');
debug('Will compile and stream through Webpack-dev-Middleware');
const devMiddleware = require('webpack-dev-middleware')(compiler, {
// self-define options
});
Copy the code
As you can see from the code above, Webpack gets compiled and packaged to get a Compilation and passed to the Webpack-dev-Middleware plug-in. Webpack-dev-middleware can monitor file changes in real time through Compilation by calling the Watch method in Webpack.
Looking at the browser side, you can see several requests in Network:
The message returned by the /__Webpack_hmr request contains the Hash value for the first time. After each code change and recompilation, the browser will issue hash.hot-update.json and filechunk.hash.hot-update.js resource requests.
Click hash.hot-update.json. In the returned result, H is a hash value, used as the prefix for the next hot update request, and C indicates that the current hot update file is main1.
Continue to look at filechunk.hash.hot-update. js and return the fileChunk content identified with webpackHotUpdate.
So how does the Webpack server communicate with the browser side? That’s where the Webpack-hot-middleware plugin comes in. Webpack-hot-middleware’s readme. md document describes this:
This module is only concerned with the mechanisms to connect a browser client to a Webpack server & receive updates.
The Webpack-hot-Middleware plugin provides communication between the browser and the Webpack server, and receives updates from the Webpack server on the browser side.
To better understand this paragraph, open the browser developer debugging tool and you can see that Webpack Js contains the following sections. The key parts are captured below for illustration:
- Webpack-hot-middleware/client.js
There is always a __Webpack_hmr request in the browser Network during development. Click on it and you will see the EventStream (server side EventStream, server push message to browser, In addition to websocket full-duplex channel two-way communication, there is another one-way channel communication method, server-sent Events. Only the Server can push messages to the browser through stream information. The page can use the EventSource instance to receive an event notification from the server and trigger the onMessage event) and update the message content every 2 seconds, each line with the ❤️ icon, which is a heartbeat request.
var options = {
path: '/__Webpack_hmr'.timeout: 20 * 1000.overlay: true.reload: false.log: true.warn: true.name: ' '.autoConnect: true.overlayStyles: {},
overlayWarnings: false.ansiColors: {}};Copy the code
Looking further down at the client.js code, you can see that this is nothing more than a Client that automatically establishes communication channels as long as the browser supports them.
if (typeof window= = ='undefined') {
// do nothing
} else if (typeof window.EventSource === 'undefined') {
// warning
} else {
if (options.autoConnect) {
// Establish a communication connectionconnect(); }}Copy the code
During communication, the browser side initializes an EventSource instance and listens for messages through the onMessage event. When the browser receives data from the server, it will trigger the onMessage event. You can define the onMessage callback function to process the received message.
// The browser establishes the connection
function EventSourceWrapper() {
var source;
var listeners = [];
// Initialize the EventSource instance
source = new window.EventSource(options.path);
// Define the onMessage event to listen for server-side message returns
source.onmessage = handleMessage;
function handleMessage(event) {
for (var i = 0; i < listeners.length; i++) { listeners[i](event); }}return {
addMessageListener: function(fn) { listeners.push(fn); }}; }// The browser establishes a communication channel and listens to the messages pushed by the server
function connect() {
EventSourceWrapper().addMessageListener(handleMessage);
function handleMessage(event) {
try {
processMessage(JSON.parse(event.data));
} catch (ex) {
// handler exception}}}Copy the code
Client.js listens for the following messages:
-
Building /built: Hot updates will not be triggered.
-
Sync: Starts the update process.
In the processUpdate method, the way to handle any exceptions/errors is to update the entire page directly by calling window.location.reload(), and first calling the module.hot.check method to check for updates. Then enter the HotModuleReplacement. Runtime Check phase.
function processMessage(obj) {
switch (obj.action) {
case 'building':
// tell you rebuilding
break;
case 'built':
// tell you rebuilt in n ms
// fall through
case 'sync':
/ / to omit...
var applyUpdate = true;
if (applyUpdate) {
processUpdate(obj.hash, obj.modules, options);
}
break;
default:
// do something}}Copy the code
Thermal renewal process
After the page code changes are saved, Webpack recompiles the file and sends a message to the browser. The browser triggers WebpackHotUpdateCallback after Check. Specific HotModuleReplacement. Runtime. Js will do the following operations:
-
Go to HotCheck and call hotDownloadManifest to send /hash.hot-update.json request.
-
Obtain the hot update file and Hash id of the next hot update through the Json request result, and enter the hot update preparation phase.
hotAvailableFilesMap = update.c;// The file needs to be updated hotUpdateNewHash = update.h;// Next hot update hash value hotSetStatus("prepare");// The system enters the hot update state Copy the code
-
HotCheck verifies the need for hot update and enters the hotAddUpdateChunk method. This method first checks whether the Hash identified module has been updated. If not, it dynamically requests JS by adding Script tags to DOM: / filechunk.hash.hot-update. js, to get the latest packaged JS content;
-
How does the newly packaged JS content get updated? HotModuleReplacement. Runtime. Js on the window object defines the WebpackHotUpdate method; WebpackHotUpdate (main1, {moreModules}) ¶ And execute the hotUpdate method update;
conclusion
Now that the page is hot updated, how does Webpack do it? The first step is to establish the communication between the browser and the server. The browser will receive the message pushed by the server. If hot updates are needed, the browser will initiate HTTP requests to the server to obtain packaged resource parsing and partially refresh the page.
, recruiting
ZooTeam, more than 50 partners are waiting for you to join the wave ~ If you want to change things have been torturing, I hope to start torturing things; If you want to change, you’ve been told you need more ideas, but you don’t have a solution. If you want change, you have the power to make it happen, but you don’t need it. If you want to change what you want to accomplish, you need a team to support you, but you don’t have the position to lead people. If you want to change “5 years of work and 3 years of experience”; If you want to change the original savvy is good, but there is always a layer of fuzzy window… If you believe in the power of believing, believing that ordinary people can achieve extraordinary things, believing that you can meet a better version of yourself. If you want to be a part of the growth of a front end team that has deep business understanding, technology systems, value creation, and impact spillover as the business takes off, I think we should talk. Any time, waiting for you to write something and send it to [email protected]
Recommended reading
Visual Construction System for Front-end Engineering Practice (PART 1)
Automated Web performance optimization analysis solution
After reading this, you can play React Hooks, too
Vue component data communication scheme summary