hmr of remote module
Published: 2023-12-11 03:23:37

Hot update of a single application is generally available out of the box, while hot update of remote modules requires some adaptation processing according to the development environment of multiple projects, and there is no mainstream mature solution.

### Problem manifestation

<https://github.com/wpmjs/examples/tree/main/module-federation-react-hmr> You can clone this example and run it locally

There are three modules: app1 (localhost:9001), app2 (localhost:9002), and app3 (localhost:9003). As the root application, app1 introduces app2 and app3 through module-federation. At this time, start the development environment of the three apps. Try Modify local code.

-   When you access the port of each app individually and modify the corresponding code, the page will be updated.
-   When accessing localhost:9001 directly, only the code page of app1 will be updated, and the code pages of app2 and app3 will not be refreshed or changed (websocket successfully triggered and completed the code update, and the react component did not change)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/idwf1zrxe7m6a1ma61tl.png)

### Cause Analysis

As a result, only the first loaded root application can be hot updated, and other subsequently loaded modules cannot be hot updated. The reason is actually that the hot update conditions of react are relatively strict:

1.  React and react-dom are singletonsReact and react-dom are singletons
2.  react, react-dom is the development version
3.  Register __REACT_DEVTOOLS_GLOBAL_HOOK__ with global through react-refresh
4.  react-dom.development gets __REACT_DEVTOOLS_GLOBAL_HOOK__ (react-dom will get __REACT_DEVTOOLS_GLOBAL_HOOK__ when the code is executed for the first time, so you must strictly follow the order of loading react-refresh first, completing the registration hook, and then loading react-dom. If the order is wrong, hot update cannot be started., there is no remedy, this is also the most error-prone and difficult to troubleshoot)

Well, since the previous example uses module-federation to share react and react-dom and both are locally started services, it actually meets the above conditions 1 and 2.

The reason why app2 and app3 cannot be hot updated is <https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/426490f7bf7bf166efc85a0588e5c3b8e64cd72f/client/ReactRefreshEntry.js#L17> This plug-in found that global hooks already existed, so it did not register app2 and app3. Only app1 successfully registered __REACT_DEVTOOLS_GLOBAL_HOOK__ (by the way, react-dom.development is obtained directly from global __REACT_DEVTOOLS_GLOBAL_HOOK__, so it is not feasible to register each application individually.)

For specific questions, please see this issue: [Component modifications are not applied in module federation · Issue #394 · pmmmwh/react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/394)

### Solution

Multiple modules reuse the same __REACT_DEVTOOLS_GLOBAL_HOOK__:

<https://github.com/zhangHongEn/universal-module-federation-plugin/tree/main/packages/single-react-refresh-plugin>

> Vue's hot update is not so troublesome to integrate. Logically, it only needs to satisfy the vue singleton and the development version plus vue-loader. If anyone encounters similar problems, you can leave a message.

### Remote module optimization points

It is not difficult to find from the above example that although we have three modules that can be independently constructed and released, we need to start the root application + remote module project locally during development. If we only need to modify one module and disassemble the project, it will reduce efficiency. of. **The better way is to start only the modules that need to be debugged or modified locally, so that they can be directly connected to the resources that have been deployed online or in the test environment (you can experience the micro front-end example built below)**, In this way, you can truly achieve minimal independent construction, independent release and independent debugging, to improve the development and deployment efficiency of the project and even reduce the scope of release impact.

This development method involves how to start a remote module so that the main application can be switched to the development version, which will be discussed separately later.

### micro frontend

An application composed of multiple independently built and independently released modules can also be called a micro front end.

You can also use the following link to experience starting the remote module alone and directly connecting to the online environment for development and debugging:

1.  Visit the micro front-end root application demo address: <https://zhanghongen.github.io/universal-module-federation-plugin/>
2.  clone remote module mf-app-01: <https://github.com/zhangHongEn/universal-module-federation-plugin/tree/main/packages/mf-example/app1>
3.  npm install && npm run start
4.  Activate the local connection switch

You can see the effect in the picture below, a remote page, part of the page uses locally started components


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hbm1s1qbms5emxahswaw.png)




The above micro front-end page is implemented using wpmjs and npm-federation:

<https://github.com/zhangHongEn/universal-module-federation-plugin/tree/main/packages/npm-federation-webpack>

Finally, I will share some micro-front-end related technologies.:

Loader:

-   systemjs、module-federation（Can be regarded as a mainstream remote module loader）
-   wpmjs（Versioned loading of remote modules, and integration of multiple module specifications such as: umd, system, module-federation）
-   npm-federation（Load the plug-in of the remote npm package in the module-federation method, and you can also load the umd package）

Open up the technology stack:

vuereact-combined（vue2 and react components refer to each other）

veaury（vue3 and react components refer to each other）

Application isolation: qiankun, single-spa, etc.