Published on

vite-1.0 CSS插件解读

Authors
  • avatar
    Name
    祝你好运
    Twitter

这个src/client/client.ts是HMR的客户端,我们之前提到过,HMR是通过WebSockets来做的,那它肯定是需要一个客户端和一个服务端的,通常就是客户端来连接服务端,然后服务端在特定条件下发送消息,客户端接收并处理消息,我们来看下代码主结构:

主结构

HMR-client-main-structor 这个文件跟之前看的插件不一样,插件是作为koa的中间件来运行的,这个文件是WebSockets的客户端代码,它是以ES Module直接注入到HTML文件里面的(被import),然后当浏览器通过网络请求拿到这个文件的内容的时候,是会直接执行了,所以才有了上面红色箭头指向的关键代码。

处理消息

我们发现最终所有的更新都会走到61行的handleMessage。vue相关的我们可以不管,因为这个是只针对vue的,和vite关系不大的。还有一个就是style有update和remove,但是JS就只有update,为啥JS没有remove?我还特意去看了下chokidar的文件删除的时间,删除是unlink,但是vite里面并没有监听unlink,后来我想了下,其实监听unlink没啥用,因为文件删除完,我们还是需要手动更新那些导入了这个被删除文件的文件,这样就有了update。那为啥CSS就有remove?这个remove其实只有vue里面会调用,普通的CSS更新只会先走update,update里面会先remove,再add。 HMR-client-handle-message

style更新

样式更新是这样一个流程:

  1. 用户更新样式文件
  2. chokidar触发changeserverPluginCss第43行)
  3. serverPluginCss发送style-update给WebSockets客户端
  4. 客户端拉去最新的代码
  5. 服务端返回最新的CSS代码
  6. 如果是<link>就直接挂在上去了,如果import,就会走ES module的路子,类似JSONP的套路,会执行到updateStyle,然后就更新了样式

下图就是根据是<link>或者import来走不同的路子

HMR-client-style-update-case

再来看下具体是如何更新的,首先175行就是通过文件名id拿到之前生成的具体元素,这个文件名id是在。具体元素有可能是HTMLStyleElement,也就是<style>...</style>。也有可能是CSSStyleSheet,这个可以直接用新的文件内容替换。

下面的逻辑一行行解释的话,效果也不理想,我来说一下大致思想吧。如果是纯的CSS内容,而且浏览器支持CSSStyleSheet,就用它挂载到document.adoptedStyleSheets上。否则就生成<style>...</style>插入到document.head里面。然后还需要注意这里是更新,也就是需要根据情况来移除上次的结果。

HMR-client-update-style

style移除

这里就两种情况,一种是移除<style>...</style>,另一种就是过滤document.adoptedStyleSheets,我觉得213行应该是无用代码,等分析vite 2.0代码的时候看它还在不在。

HMR-client-remove-style

JS更新

JS的更新是用了队列的:

queueUpdate(updateModule(path, changeSrcPath, timestamp))

参考: