如何在项目中实现热更新(上)

如何在项目中修改代码后实现热更新

这个是组内一位同学在平时开发中,发现调试不便,为团队开发的热更新工具。很厉害,文章中的技术实现内容也是我了解了他的具体实现思路后,整理出来的。

工具源码EHU(esl-hot-update)

热更新是什么

热更新就是当你在开发环境修改代码后,不用刷新整个页面即可看到修改后的效果。

如果你的项目中使用了webpack的话,你会很幸运,借助webpack-dev-server插件可以实现项目的热更新。

解决的问题

对于大型的系统级别项目会有下面几个特点

  1. 模块化(AMD)模式的广泛使用后,开发环境散文件特别多,很容易上百,一不小心还能上千
  2. 初始化的内容特别多,各种底层库,ui库等等

这两个特点直接导致每次调试后,刷新会很慢。如果初始化的js达到上千的数量级,每一次重新刷新都是5s,10s,甚至20s的等待。

而热更新的目的就是为了在一定程度上减少这5s,10s,甚20s的浪费。

遇到的问题

  1. 我们使用的是百度自己的开发环境工具edp,首先他不支持热更新
  2. 我们使用的AMD实践也是百度自己的esl,而且即使是requirejs也暂时没有找到对应的热更新策略,假如requirejs有对应的,我们也无法直接使用

所以最终的结论是我们自己去实现一个基于我们自己业务的。这样我们考虑的面不用太广,并且解决方案的更有针对性,即面向我们现有的业务框架。最重要的是可以尝试修改底层框架做配合。

等待路踩通了,我们再去考虑普适性。

解决的思路

从ehu/package.json 这个文件中,我们就可以看出一些具体的思路

  1. 需要一个watch功能,即能够监听到文件的修改
  2. socket.io通知浏览器处理文件的改变
  3. 修改esl这个文件,达到能够实时更新的效果

当时最简单的考虑,就是文件改变了后,能够通知浏览器,浏览器去重新load这个文件并且执行一次。这个时候再重新去打开这个模块或者功能后,会发现新load的代码在执行后会覆盖上一次的。

所以当时的我的第一直觉是,esl重复require时,如果后面一次会覆盖前面的,那么可以通过简单的覆盖思路去尝试,结果发现覆盖不了。经过验证,发现是esl内部维护了一个map,即require过的模块会存起来。我们如果希望更新这个模块,只能将map中的对应模块名删除。(后面会详细讲述esl的改造)

对于工具的要求

对应这个工具,我当时也提出了几个要求

  1. esl必然是需要修改的,但是如何对开发人员透明?首先是不能让大家都做这种修改。
  2. 页面中也必须加入socket.io支持,那么我们如何在不影响其他人员开发的情况下加入?
  3. 我们做的属于beta版本,如何选择性的使用?ehu工具和以前的开发模式随意切换?
  4. 安装方便,能否只是作为一个工具,即插即用,不需要繁琐的配置?

微信公众号

前端修炼