You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
从 Webpack Wiki hot module replacement · webpack/docs Wiki 了解到,Webpack 能知道「哪个模块需要热更新」,并提供一些钩子,另外 webpack 自有一套模块管理,能够管理替换模块,让你访问的是热更新之后的模块。另外,要实现热加载的不仅要满足「再次加载」,还要考虑如何清空相关的「持久资源」。
背景
刚思考这个话题的时候,首先想到的是 Vue 或 React 的组件热更新(基于 Webpack HMR),后来又想到了 Lua、Erlang 等语言的热更新,不过在实际开发 Node.js 后台时,使用 remy/nodemon 之类的热重启(侦测代码改动重启程序)工具也够用,于是 Node.js 的热更新(替换模块,无须重启)的验证就一直搁置。
直到最近在使用[「微信机器人」](Chatie/wechaty: Wechat for Bot. Powered by WebDriver / Node.js / Docker)(Node.js) 时,遇到了强烈的需求。这类机器人程序就是:启动了一个网页,登录 Web 微信,通过抓取识别页面中的元素获得一些状态信息,如:消息、好友请求等等,由于它的启动时间也比较长,如果每次修改业务代码后都要重启,那么等待程序启动就要消耗不少时间,导致开发体验很差,于是实践 Node.js 的热更新就迫在眉睫了。
目标
以下是机器人的核心用法:
那么我们的目标:增/删/改 业务逻辑(事件处理器)的时候程序无须重启,自动热更新业务逻辑代码,从而提高开发效率。
思路一:基于 Webpack 验证可行
从 Webpack Wiki hot module replacement · webpack/docs Wiki 了解到,Webpack 能知道「哪个模块需要热更新」,并提供一些钩子,另外 webpack 自有一套模块管理,能够管理替换模块,让你访问的是热更新之后的模块。另外,要实现热加载的不仅要满足「再次加载」,还要考虑如何清空相关的「持久资源」。
所以说,如果基于 webpack HMR 来实现的话,需要完成几件事情:
1. 业务代码模块化
简单地把每个事件处理器定义为一个文件
*.biz.js
:其中
evt
是事件名,fn
是处理器,于是加载一个业务模块后就能拿到事件名称和处理器。(可能不满足实际要求,先简单验证热更新是否可行哈!)
2. 自动加载
我们约定,业务模块
*.biz.js
都放在/biz
目录下,该目录下的index.js
会加载所有业务模块,而main.js
就只需加载/biz/index.js
借助 webpack 的 require-context 加载所有
*.biz.js
模块,避免手写 require:3. 修改后热更新
参考 Wiki 的例子 Example 3,知道 require.context 如何使用热更新机制
到了这一步,修改任何
*.biz.js
的代码都能自动热更新了。4. 增删文件后热更新
上面的代码已经不小心实现了 「增加文件后热更新」,因为
module.hot.accept(requireContext.id
表示检测./biz/*.biz.js
的更新,如果增加一个c.biz.js
,那么requireContext.keys()
就变成[ ..., './c.biz.js']
,于是新模块不等于老模块(不存在),从而使用c.biz.js
注册事件监听器。对于删除文件后的热更新,则在上面代码基础上增加:
经过以上四步,算是初步验证了,借助 Webpack 来玩是可以的,当然我们作了不少严格约定,不过不影响这一阶段的思路。
完整代码请移步:zhenyong/webpack-hot-nodejs-demo: Webpack HMR demo use in Node.js, showing how to auto add/remove listeners.
思路二:基于 Webpack 进阶
上面一种思路存在一些问题
于是我想,约定业务代码格式是为了方便通过模块管理事件的注册和移除,假如说在不侵入代码,不作任何约定的情况下,也能知道某个模块注册了哪些事件,是不是就不需约定了,好像是的:
但是问题来了,我们的目标包括「自动加载所有业务模块,增删文件都能热更新」,那么在开发阶段我们还是借助 webpack 的 require.context 方法,并且约定每个业务模块的入口文件命名为
*.biz.js
,至于里面代码怎么写就随意了,而在生产阶段可以遍历文件找到所有*.biz.js
进行加载,无须依赖 webpack。剩下的大部分思路跟 #思路一 类似,代码可参考 zhenyong/webpack-hot-nodejs-demo: Webpack HMR demo use in Node.js, showing how to auto add/remove listeners.
更多思路
最开始写这篇文章是想深扒一下 Node.js 的模块管理和缓存结构,然后验证一下通过清除模块缓存来做热更新是否可行,后来感觉 webpack 给我们作了很多工作,于是就先用 webpack 玩了一轮,看来择日还得再写一篇(二)了
问题
热更新的主要目的是为了提高开发效率,并不是为了在生产上玩热更新,毕竟还有很多潜在问题,例如,模块中涉及全局状态或者单例资源,通过热更新可能会引起混乱......
参考
The text was updated successfully, but these errors were encountered: