美文网首页
3-9-10 Hot Module Replacement 热模

3-9-10 Hot Module Replacement 热模

作者: love丁酥酥 | 来源:发表于2020-02-03 21:18 被阅读0次

    1. 简介

    模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。

    2. HMR - CSS

    关于 HMR 的使用场景,我们来看一个简单的示例。

    // index.js
    import './index.css';
    
    var btn = document.createElement('button');
    btn.innerText = 'add';
    document.body.appendChild(btn);
    
    btn.onclick = function() {
      var div = document.createElement('div');
      div.innerText = 'item';
      document.body.appendChild(div);
    };
    
    /*index.css*/
    div:nth-of-type(odd) {
        background: yellow;
    }
    

    npm start 后,如下:


    image.png

    连续,点击 add 按钮后,如下:


    image.png
    这时候,如果我们修改 css,将背景色改为 blue,如下:
    /*index.css*/
    div:nth-of-type(odd) {
        background: blue;
    }
    
    image.png

    再次点击 add 按钮后,如下:


    image.png

    可以看到,我们修改 css 文件时,由于代码变动,重新编译并刷新了网页。导致之前的 js 操作都消失了,有没有变法只展示我们变动的 css 呢?答案是可以的。如下配置:

    const webpack = require('webpack');
    ...
        devServer: {
            contentBase: path.resolve(__dirname, 'dist'),
            open: true,
            port: 3000,
            hot: true, // 开启热更新
            hotOnly: true // 热更新失败时不刷新页面
        },
    ...
        plugins: [new HtmlWebpackPlugin({
            template: "./src/index.html"
        }), new webpack.HotModuleReplacementPlugin()]
    

    重新编译,发现修改在即时生效的同时,保留了 js 操作,实现了 css 的热更新。

    3. HMR - js

    关于 js 模块的热更新该如何实现呢,我们来看一下。
    首先去掉 hot 和 hot-only 配置。
    增加一个 counter.js 文件和一个 number.js 文件,并引入:

    // index.js
    import Counter from './counter';
    import Number from './number';
    
    new Counter();
    new Number();
    
    new Number();
    

    ···
    // counter.js
    export default function() {
    var div = document.createElement('div');
    div.innerText = '1';
    div.onclick = function() {
    div.innerText = (parseInt(div.innerText) + 1) + '';
    };
    document.body.appendChild(div);
    };
    ···

    // number.js
    export default function Header() {
        var number = document.createElement('div');
        number.innerText = '1000';
        number.id = 'number';
        document.body.appendChild(number);
    }
    

    点击上面一个数字后:


    image.png

    修改,number 的文案为 2000,如下:


    image.png

    之前的 js 操作没有了,也就是 number 模块的修改影响到了 counter 模块。
    我们试一下配置 hot 和 hot-only,重新编译,发现,此时修改 number 时,


    image.png

    number 没有被更新,这是因为依赖模块更新时,我们需要主动对更新做出响应。
    如下:

    // index.js
    import Counter from './counter';
    import Number from './number';
    
    new Counter();
    new Number();
    
    if (module.hot) {
        module.hot.accept('./number', function() {
            new Number();
        });
    }
    

    此时,修改 number 后,有:


    image.png

    可以看到,webpack 并不会帮我们把原 number 干掉,然后在原位置更新一个新的 number,这些逻辑都要用户主动去实现。

    // index.js
    import Counter from './counter';
    import Number from './number';
    
    new Counter();
    new Number();
    
    if (module.hot) {
        module.hot.accept('./number', function() {
            document.body.removeChild(document.getElementById('number'));
            new Number();
        });
    }
    
    image.png

    4. 小结

    为何 js 实现 HMR 要用户手动实现更新逻辑,但是样式更新不需要呢?其实样式更新也是需要实现这个更新逻辑的,只不过 style-loader 实现了 HMR 接口,当它通过 HMR 接收到更新时,它会使用新的样式替换旧的样式。而 Vue 通过 vue-loader,react 通过 babel-preset 都在底层实现了该接口,用户无需关注。

    参考

    https://www.webpackjs.com/concepts/hot-module-replacement/
    https://www.webpackjs.com/plugins/hot-module-replacement-plugin/
    https://www.webpackjs.com/api/hot-module-replacement/

    相关文章

      网友评论

          本文标题:3-9-10 Hot Module Replacement 热模

          本文链接:https://www.haomeiwen.com/subject/ydhkxhtx.html