gnosis23 / hello-world-blog

还是 issues 里面写文章方便
https://bohao.work
0 stars 0 forks source link

webpack 热模块替换 #30

Open gnosis23 opened 5 years ago

gnosis23 commented 5 years ago

探索下热模块更新(以下简称 HMR )原理,主要偏重开发者所能控制的部分,原理部分尽量减小。

入门资源

什么是 HMR

想想看以前每次改变代码以后,需要手动刷新页面查看效果,非常低效。后来出现的 live reload 改变了一点,但是每次刷新原来页面的状态就全部丢失了。 HMR 是一种在运行时动态改变模块代码的技术,可以理解为模块范围内的 live reload,这样的好处时可以保留页面的状态。

怎么利用 HMR

那怎么写热更新部分的代码呢?

参照下一节

其他思路

每次都要这么写也太折腾人了,而且不能指望所有用户都对 HMR 有了解。

dva.js 就用了一个 babel 插件 来自动替我们处理这些事情。(很有局限性)

gnosis23 commented 5 years ago

入门资料 3 里介绍了 webpack + webpack-dev-server HMR 的原理,但是业务代码部分介绍的相对简单,看完了还是不会自己写代码。

我在下面简单描述下 HMR runtime 部分的流程,然后结合官方例子进行实战。

流程

hotCheck():

hotApply():

例子

Example 1

var requestHandler = require("./handler.js");
var server = require("http").createServer();
server.on("request", requestHandler);
server.listen(8080);

// 下面也会立即执行
if(module.hot) {
    // module.hot.accept 事件被保存的起来,不会立即执行。一旦 handler.js 更新就会调用
    module.hot.accept("./handler.js", function() {
        server.removeListener("request", requestHandler);
        requestHandler = require("./handler.js");
        server.on("request", requestHandler);
    });
}

Example 2

// addStyleTag(css: string) => HTMLStyleElement
var addStyleTag = require("./addStyleTag");

var element = addStyleTag(".rule { attr: name }");
module.exports = null;

// check if HMR is enabled
if(module.hot) {

    // accept itself:accept可以不传参数
    module.hot.accept();

    // removeStyleTag(element: HTMLStyleElement) => void
    var removeStyleTag = require("./removeStyleTag");

    // dispose handler:当移除或更新自己时执行
        // 常用于清历老模块的内容
    module.hot.dispose(function() {
        // revoke the side effect
        removeStyleTag(element);
    });
}