背景最初想到这个话题的时候首先想到的是Vue或者React组件热更新(基于WebpackHMR),后来又想到了Lua、Erlang等语言的热更新update,但是在Node.js后台的实际开发中,使用remy/nodemon等热重启工具(检测代码变化并重启程序)也是足够的,所以Node.js热更新(更换模块)的验证无需重新启动)已被搁置。直到最近,在使用“微信机器人”)(Node.js)时,遇到了一个强烈的需求。这类机器人程序是:启动一个网页,登录微信,通过抓取识别页面上的元素,获取一些状态信息,比如消息,好友请求等。由于启动时间比较长,如果你每次修改后业务代码都要重启,等待程序启动会耗费大量时间,导致开发体验很差,所以实现Node.js的热更新迫在眉睫。下面是robot的核心用法:robot=newRobot()robot.addEventListener('msg',...)robot.removeEventListener('msg',...)然后我们的目标:增/删/改业务logic(Eventhandler)程序无需重启,业务逻辑代码自动热更新,提高开发效率。思路一:基于Webpack的Validation是可行的。从WebpackWiki模块热更新·webpack/docsWiki,Webpack可以知道“哪个模块需要热更新”,并提供一些hooks。另外,webpack有自己的一套模块管理,可以对替换模块进行管理。让你访问的是热更新后的模块。另外,要实现热加载,不仅要满足“重载”,还要考虑如何清除相关的“持久化资源”。因此,如果基于webpackHMR来实现,需要做几件事:将事件处理器的代码模块化,方便webpack管理。自动加载所有处理器模块更新事件处理模块后,您需要获取旧模块以移除旧的监听处理器。了解文件的增删改查,获取模块内容。1.业务代码模块化简单地将每个事件处理程序定义为一个文件*.biz.js://msg.biz.jsmodule.exports={evt:'msg',fn(){console.log('msghanlder....')}};其中evt是事件名,fn是处理器,所以加载一个业务模块后,可以得到事件名和处理器。(可能不符合实际需求,先简单验证一下热更新是否可行!)2.自动加载我们约定业务模块*.biz.js放在/biz目录下,该目录下的index.js会加载所有服务模块,而main.js只需要加载/biz/index.jssrc|---/biz|---a.biz.js|---b.biz.js|---index.js|---main.js使用webpack的require-context加载所有*.biz.js模块,避免手写require://index.js//加载当前目录下的所有`*.biz.js`constrequireContext=require.context('./',true,/\.biz.js/);//此时requireContext.keys()为['./a.biz.js','./b.biz.js']requireContext.keys().forEach(key=>{constmodule=requireContext(key);//等同于module=require('./biz/a.biz.js')//然后获取事件名称和处理程序,然后监听事件//robot.addEventListener(module.evt,module.fn)});3.修改后热更新参考wiki示例例3了解require.context如何使用热更新机制//index.js//当启动webpackHRM时则module.hot为trueif(module.hot){//表示必须检测和更新此上下文下的模块module.hot.accept(requireContext.id,()=>{constrequireContext=require.context('./',true,/\.biz.js/);requireContext.keys().forEach(key=>{constnewModule=requireContext(key);//第一次自动加载所有模块后,会记录在oldModules对象中(
