Node中关于如何热更新一个模块

最近做了一些基于Egg的web项目,在开发阶段,一般会在本地安装nodemon这样的工具,从而当我们改变一个文件时,他可以监听到这个改动,然后重新启动进程,将数据从硬盘里重新加载到内存中,所以我们新的改动可以应用到应用程序中去。这里不免想到一个问题,如果不重新启动的话,我修改了一个文件,怎么去应用最近的改动呢?

  1. 首先先简单介绍一下require这个属性,当我们编写完Node.js代码后,被解释器执行时,会做一层包装,像下面那样
(function(module,exports,require,__dirname,__pathname ){
	// your code ...
})

所以我们可以直接在任何地方引用require这个方法,除了用来引入模块以外,它上面还有一些额外的数据。我们先建立2个简单的文件,在同一个目录下

// entry.js
const lib = require('./lib');
const name = lib.getName();
console.log(name);
//lib.js
console.log('I got it');
const lib = {
    name: 'kasol',
    getName: function() {
        return this.name;
    }
};
module.exports = lib;

然后我们直接执行entry.js,结果很明显

//I got it
//kasol
  1. 接下来我们做一点点简单的改动
// entry.js
const lib = require('./lib');
const lib2 = require('./lib');
const lib3 = require('./lib');
const name = lib.getName();
console.log(name);

我在entry.js中,多次引用了lib,输出的结果会怎么样呢?

//I got it
//kasol

是的,“I got it” 始终只输出了一次,因为Node在加载执行完一个模块之后,会将它缓存下来,之后再有模块想要去引用它时,就会直接从缓存中返回,所以这个console只执行了一次。

  1. 从上面看来,就算我们能够在模块改动后,重新 require对应的文件,还是会从缓存中去取,那么也不能拿到最新的改动,所以要先解决怎么让他重新去加载的问题,这时候就要看上述提到的require.cache了。我们再来改改entry.js
//entry.js
const lib = require('./lib');
console.log(require.cache);

我们执行下,看看打印的结果

{ 
   Module {
     id: '/Users/zhongzeming/webpackDemo/test/lib.js',
     exports: { name: 'kasolll', getName: [Function: getName] },
     parent:
      Module {
        id: '.',
        exports: {},
        parent: null,
        filename: '/Users/zhongzeming/webpackDemo/test/entry.js',
        loaded: false,
        children: [Array],
        paths: [Array] },
     filename: '/Users/zhongzeming/webpackDemo/test/lib.js',
     loaded: true,
     children: [],
     paths:
      [ '/Users/zhongzeming/webpackDemo/test/node_modules',
        '/Users/zhongzeming/webpackDemo/node_modules',
        '/Users/zhongzeming/node_modules',
        '/Users/node_modules',
        '/node_modules' ] } }

简单起见,我只贴出了lib模块的信息,可以看到上面这个cache里面是存在的,所以在第二次去require的时候,就去这里拿了。

  1. 所以我们再改改entry
//entry.js
const lib = require('./lib');
console.log(require.cache);
delete require.cache[require.resolve('./lib.js')];
console.log(require.cache);

这时候会发现,这个cache里面就不存在lib模块的信息了,上面的代码里面,有一个delete require.cache[require.resolve(’./lib.js’)],require.resolve就是返回这个模块的绝对路径,作为一个key值去cache里面把这个模块的信息给删去,之后再去require的话,就又会去重新加载这个模块了,最后我们把俩个文件都改改
如下

// entry.js
let lib = require('./lib');
const fs = require('fs');
const path = require('path');
fs.watch(path.join(__dirname, 'lib.js'), { encoding: 'utf-8' }, (eventType, filename) => {
    delete require.cache[require.resolve('./lib.js')];
    lib = require('./lib');
    console.log(lib.getName());
});


// lib.js
console.log('I got it');
const lib = {
    name: 'kasol',
    getName: function() {
        return this.name;
    }
};
module.exports = lib;

这里用了fs.watch,作为监听文件改动来说可能不是那么完美,但是我们这里用来演示改动更新已经足够了。先执行entry,然后可以不停的改动lib.js中的name值看看,就会发现console出来的值已经不一样了。

总结

上面的代码只是简单的演示,虽然在生产环境中热更新一个模块文件好像并没有什么太大的意义,而在开发环境中,其实我们最常用的还是诸如nodemon这类的工具,不过,这也提供了一个思路,可以在不重新启动进程的情况下,去重新加载一到个模块。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值