Vite 是如何做热更新的

5 篇文章 0 订阅
1 篇文章 0 订阅

Vite 是如何做热更新的

假如我们自己做热更新HMR(Hot Module Reload/Replacement),我们大体的思路是什么呢,很常见得一个场景,在项目中写代码的时候,修改一个元素的样式,ctrl/commad+s保存后,修改的样式在页面中发生了变化,这个场景,我们可以捕获到两个动作

  • 保存文件之后文件内容发生了变化
  • 修改的内容被replace/reload页面重新渲染了

我们从这两方面看Vite是怎么做的

监听文件变动

Node.jsFS模块中,有fs.watchfs.watchfile 两个监听文件夹和文件变化的API,我们可以通过这两个API实现我们的思路的第一步,但是这里边有些坑,在这个chokidar库中有说明

Node.js fs.watch:

  • Doesn’t report filenames on MacOS.
  • Doesn’t report events at all when using editors like Sublime on MacOS.
  • Often reports events twice.
  • Emits most changes as rename.
  • Does not provide an easy way to recursively watch file trees.
  • Does not support recursive watching on Linux.

Node.js fs.watchFile:

  • Almost as bad at event handling.
  • Also does not provide any recursive watching.
  • Results in high CPU utilization.

三个字总结就是有问题chokidar解决了以上问题,所以文件监听的任务就交给chokidar了,下边的代码是vite2.x中通过chokidar监听变动的代码

const watcher = chokidar.watch(path.resolve(root), {
    ignored: [
      '**/node_modules/**',
      '**/.git/**',
      ...(Array.isArray(ignored) ? ignored : [ignored])
    ],
    ignoreInitial: true,
    ignorePermissionErrors: true,
    disableGlobbing: true,
    ...watchOptions
  }) as FSWatcher

知道了文件的变动,如何把变动的文件更新到页面呢

更新文件变动

更新文件到页面,需要我们通过websocket 对server端和client端建立链接,websocket逻辑在packages\vite\src\node\server\ws.ts

Server端

通过监听change事件,通过handleHMRUpdate方法判断不同的type去执行不同的逻辑(通过ws发送消息)

watcher.on('change', async (file) => {
    file = normalizePath(file)
    if (file.endsWith('/package.json')) {
      return invalidatePackageData(packageCache, file)
    }
    // invalidate module graph cache on file change
    moduleGraph.onFileChange(file)
    if (serverConfig.hmr !== false) {
      try {
        await handleHMRUpdate(file, server)
      } catch (err) {
        ws.send({
          type: 'error',
          err: prepareError(err)
        })
      }
    }
  })
// handleHMRUpdate 方法里的部分代码
...
updates.push(
 ...[...boundaries].map(({ boundary, acceptedVia }) => ({
 type: `${boundary.type}-update` as Update['type'],
 timestamp,
 path: boundary.url,
 acceptedPath: acceptedVia.url
 }))
)
...

packages\vite\types\hmrPayload.d.ts路径下定义的type类型

image-20220507113931278.png

Client端

在client端监听socket消息,代码如下

// Listen for messages
socket.addEventListener('message', async ({ data }) => {
  handleMessage(JSON.parse(data))
})

下图在handleMessage方法中,对应server端的类型,被折叠的代码中有一个fetchUpdate方法 里边的逻辑是热更的逻辑

image-20220506183925227.png
可以在packages\vite\src\client\client.ts查看详细的逻辑

总结

  1. 通过chokidar监听文件变动,变动的类型不同执行的方式也不一样
  2. 通过websocket,建立server端和client端通信
    image-20220506183925227.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值