前言
上一节,已经比较详细的了解了如何塞一个客户端给浏览器,可以说,已经万事俱备,只欠“change”事件了
思路
我们页面显示的内容是由一个个vue组件组成的,那更新页面其实就约等于更新vue组件,那更新vue组件不就可以使用$forceUpdate,那理论上我们想办法拿到变更的vue文件对应的组件实例,然后去执行它的强制更新api,不就做到了局部更新嘛
源码
消息派发
chokidar包能够准确的知道哪一个文件发生了变更
由于缓存机制的存在,vite会先清一下缓存
接着调用handleHMRUpdate来处理热更新,需要对不同的文件变更做定制化处理:配置文件的修改需要重启服务器才能生效、html文件的修改必须是全量更新等
修改配置
找到vite.config.js,新增proxy配置项
由于vite只在服务启动时收集配置项并在开发周期中做相应的调用,因此需要重启node以重新收集
修改html文件
由于热更新的具体实现是由vue或react提供的,而这些框架操作的目标都是以某一个根节点开始的,故需要全量更新
修改.vue文件
这里也会去做一次清缓存操作,然后根据当前变动文件的缓存标识生成一条ws消息
最后使用ws.send发送给客户端(即client.js文件)
消息接收与处理
此时,我们已经完成了消息派发,只需要在client.js中对消息做下监听即可
那么,拿到这个消息后,怎么做才能实现局部更新呢???
热更新的接入对用户来说应当是无感的,且要想实现热更新,就必须能够定位得到具体是哪个组件发生了更新,因此,我们需要对每一个组件做收集
既然client.js中已经为我们提供了注册方法,那就只需要想办法去调用即可,我们知道在plugin阶段是能够拿到组件源码的,那么我们只需要在源码中拼接出对client.js中注册方法的调用,即可完成组件收集
这将把文件标记到dataMap中
同时返回一个包含accet函数的方法类
注册热更新回调
调用上一步向源码插入的accept函数
这将收集注册的回调函数并等待调用
执行回调
当接收到socket消息时,读取路径标识判断是否是可更新的文件请求
接着内部发起请求,获取修改后的文件源码,并借用plugin-vue的能力进行编译
此时在客户端拿到的值如下
这显然是一个组件实例,则对render函数的调用,理论上能正确渲染出修改后的内容,那么只需要找到vue中对应的组件实例,替换render函数,然后重新调用vue的updateComponent即可完成一次hmr
事实上,vue在开发环境中会向全局挂载相关api
其中的createRecord函数会将组件实例收集起来,而另外两个本质上都属于更新方法
因此,回调函数的核心即对上述api做调用
网友评论