这个是组内一位同学在平时开发中,发现调试不便,为团队开发的热更新工具。很厉害,文章中的技术实现内容也是我了解了他的具体实现思路后,整理出来的。
热更新是什么
热更新就是当你在开发环境修改代码后,不用刷新整个页面即可看到修改后的效果。
如果你的项目中使用了webpack的话,你会很幸运,借助webpack-dev-server插件可以实现项目的热更新。
解决的问题
对于大型的系统级别项目会有下面几个特点
- 模块化(AMD)模式的广泛使用后,开发环境散文件特别多,很容易上百,一不小心还能上千
- 初始化的内容特别多,各种底层库,ui库等等
这两个特点直接导致每次调试后,刷新会很慢。如果初始化的js达到上千的数量级,每一次重新刷新都是5s,10s,甚至20s的等待。
而热更新的目的就是为了在一定程度上减少这5s,10s,甚20s的浪费。
遇到的问题
- 我们使用的是百度自己的开发环境工具edp,首先他不支持热更新
- 我们使用的AMD实践也是百度自己的esl,而且即使是requirejs也暂时没有找到对应的热更新策略,假如requirejs有对应的,我们也无法直接使用
所以最终的结论是我们自己去实现一个基于我们自己业务的。这样我们考虑的面不用太广,并且解决方案的更有针对性,即面向我们现有的业务框架。最重要的是可以尝试修改底层框架做配合。
等待路踩通了,我们再去考虑普适性。
解决的思路
从ehu/package.json 这个文件中,我们就可以看出一些具体的思路
- 需要一个watch功能,即能够监听到文件的修改
- socket.io通知浏览器处理文件的改变
- 修改esl这个文件,达到能够实时更新的效果
当时最简单的考虑,就是文件改变了后,能够通知浏览器,浏览器去重新load这个文件并且执行一次。这个时候再重新去打开这个模块或者功能后,会发现新load的代码在执行后会覆盖上一次的。
所以当时的我的第一直觉是,esl重复require时,如果后面一次会覆盖前面的,那么可以通过简单的覆盖思路去尝试,结果发现覆盖不了。经过验证,发现是esl内部维护了一个map,即require过的模块会存起来。我们如果希望更新这个模块,只能将map中的对应模块名删除。(后面会详细讲述esl的改造)
对于工具的要求
对应这个工具,我当时也提出了几个要求
- esl必然是需要修改的,但是如何对开发人员透明?首先是不能让大家都做这种修改。
- 页面中也必须加入socket.io支持,那么我们如何在不影响其他人员开发的情况下加入?
- 我们做的属于beta版本,如何选择性的使用?ehu工具和以前的开发模式随意切换?
- 安装方便,能否只是作为一个工具,即插即用,不需要繁琐的配置?