Vite HMR

article/2025/10/7 14:15:11

传统webpack的hmr是使用webpack的HotModuleReplacementPlugin,而vite则是采用native ES Module的devServer。

  • 初始化本地服务器
  • 加载并运行对应的plugin
    最重要的一件事就是运行plugin,目前vite支持的plugin大体如下图所示
    在这里插入图片描述

1、建立ViteDevServer服务器(包含5大模块:httpServer fsWatcher pluginContainer webSocketServer moduleGraph),配置websocket便于实时更新、chokidar.watch来监听文件的变化、plugin处理特殊功能、moduleGraph记录文件与url的映射。
2、watcher.on()监听文件变化,获取文件地址,并使该文件所在的moduleGraph缓存失效
3、调用hmr.ts中的handleHMRUpdate,获取文件对应模块,检查是否有自定义HMR,如果有,执行自定义更新。
4、如果需要更新的模块为空,判断如果html文件修改,重载页面;否则返回not modules matched
5、更新模块:循环将需要更新的module文件信息放入updates数组,用于log输出。查找引用模块propagateUpdate,若找不到引用它的模块,设置needFullReload为true,需要重载页面。调用ws.send,发送更新信息,若重载页面,type设置为full-reload,否则设置为update。
6、到此,服务端的监听就完成了,代码片段如下,仅供参考:

// server.ts
export async function createServer(inlineConfig: InlineConfig = {}
): Promise<ViteDevServer>// 将服务升级为websocket,便于实时更新const ws = createWebSocketServer(httpServer, config, httpsOptions)// 使用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// 处理所有的plugin,并保存到container中const container = await createPluginContainer(config, watcher)// 生成moduleGraph,这里记录了import的关系,url到file的映射const moduleGraph = new ModuleGraph(container)const server: ViteDevServer// watcher监听文件变化并进行对应的热更新处理watcher.on('change', async (file) => {file = normalizePath(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)})}}})// hmr.ts
export async function handleHMRUpdate// 获取文件对应的模块const mods = moduleGraph.getModulesByFile(file)// 更新模块updateModules(shortFile, hmrContext.modules, timestamp, server)if (needFullReload) {config.logger.info(chalk.green(`page reload `) + chalk.dim(file), {clear: true,timestamp: true})ws.send({type: 'full-reload'})} else {config.logger.info(updates.map(({ path }) => chalk.green(`hmr update `) + chalk.dim(path)).join('\n'),{ clear: true, timestamp: true })ws.send({type: 'update',updates})}

7、在client.ts中监听websocket发送的文件更新消息,handleMessage()处理更新,这里我们常用的就是update和full-reload两种更新方式,代码片段如下:

case 'update': // 仅重新加载部分文件notifyListeners('vite:beforeUpdate', payload)// if this is the first update and there's already an error overlay, it// means the page opened with existing server compile error and the whole// module script failed to load (since one of the nested imports is 500).// in this case a normal update won't work and a full reload is needed.if (isFirstUpdate && hasErrorOverlay()) {window.location.reload() // 第一次加载或者页面出现错误时直接刷新页面return} else {clearErrorOverlay()isFirstUpdate = false}// 更新模块payload.updates.forEach((update) => {if (update.type === 'js-update') {// 更新js文件queueUpdate(fetchUpdate(update))} else {// css-update// this is only sent when a css file referenced with <link> is updatedlet { path, timestamp } = updatepath = path.replace(/\?.*/, '')// can't use querySelector with `[href*=]` here since the link may be// using relative paths so we need to use link.href to grab the full// URL for the include check.const el = ([].slice.call(document.querySelectorAll(`link`)) as HTMLLinkElement[]).find((e) => e.href.includes(path))if (el) {const newPath = `${base}${path.slice(1)}${path.includes('?') ? '&' : '?'}t=${timestamp}`el.href = new URL(newPath, el.href).href}console.log(`[vite] css hot updated: ${path}`)}})break
case 'full-reload':  // reload整个页面notifyListeners('vite:beforeFullReload', payload)if (payload.path && payload.path.endsWith('.html')) {// if html file is edited, only reload the page if the browser is// currently on that page.const pagePath = location.pathnameconst payloadPath = base + payload.path.slice(1)if (pagePath === payloadPath ||(pagePath.endsWith('/') && pagePath + 'index.html' === payloadPath)) {location.reload()}return} else {location.reload()}break

以上就是我对vite热更新的简单分析,如有问题或建议,请多指教
参考文章
https://vitejs.cn/
https://blog.csdn.net/qianyu6200430/article/details/119122059


http://chatgpt.dhexx.cn/article/7b8Jbs1G.shtml

相关文章

webpack HMR

HMR或者hot模式下&#xff0c;启动webpack会在浏览器与服务器之间会建立一个websocket连接&#xff0c;使得浏览器可以和服务端建立全双工通信&#xff1b;当应用程序的代码更新时&#xff0c;会要求HMR runtime检查更新&#xff0c;有更新时&#xff0c;在websoket连接中会返回…

webpack中的HMR(热更新)原理剖析

简介 Hot Module Replacement&#xff08;以下简称 HMR&#xff09;是 webpack 发展至今引入的最令人兴奋的特性之一 &#xff0c;当你对代码进行修改并保存后&#xff0c;webpack 将对代码重新打包&#xff0c;并将新的模块发送到浏览器端&#xff0c;浏览器通过新的模块替换…

HMR(热替换)

HMR 即模块热替换&#xff08;hot module replacement&#xff09;的简称&#xff0c;它可以在应用运行的时候&#xff0c;不需要刷新页面&#xff0c;就可以直接替换、增删模块。webpack 可以通过配置 webpack.HotModuleReplacementPlugin 插件来开启全局的 HMR 能力&#xff…

面试官:说说Webpack的热更新是如何做到的?原理是什么?

一、是什么 HMR全称 Hot Module Replacement&#xff0c;可以理解为模块热替换&#xff0c;指在应用程序运行过程中&#xff0c;替换、添加、删除模块&#xff0c;而无需重新刷新整个应用 例如&#xff0c;我们在应用运行过程中修改了某个模块&#xff0c;通过自动刷新会导致整…

Webpack 热更新HMR 原理全解析

一、什么是 HMR HMR 全称 Hot Module Replacement&#xff0c;中文语境通常翻译为模块热更新&#xff0c;它能够在保持页面状态的情况下动态替换资源模块&#xff0c;提供丝滑顺畅的 Web 页面开发体验。 HMR 最初由 Webpack 设计实现&#xff0c;至今已几乎成为现代工程化工具…

curl.perform() pycurl.error: (23, 'Failed writing body (0 != 59)')

在使用python3.7编码时&#xff0c;引入pycurl模块和StringIO模块后&#xff0c;容易引起上述错误 导入StringIO模块的解决方案&#xff1a; 只有在python2中才能导入StringIO模块&#xff0c;直接 from StringIO import StringIO 即可 但是python3&#xff0c;STringIO和…

关于python的url处理

基本环境&#xff1a; python2.7 1 完整的url语法格式&#xff1a; 协议://用户名密码:子域名.域名.顶级域名:端口号/目录/文件名.文件后缀?参数值#标识 2 urlparse模块对url的处理方法 urlparse模块对url的主要处理方法有&#xff1a;urljoin/urlsplit/urlunsplit/urlpar…

windows10+python3.7使用pip安装pycurl失败

使用pip install pycurl安装pycurl失败&#xff1a; python setup.py egg_info did not run successfully. 可以单独下载pycurl依赖文件然后安装 sArchived: Python Extension Packages for Windows - Christoph Gohlke (uci.edu) 选择Python对应版本的文件进行下载&#xff0…

Pycurl介绍

pycurl — A Python interface to the cURL library Pycurl包是一个libcurl的Python接口.pycurl已经成功的在Python2.2到Python2.5版编译测试过了. Libcurl是一个支持FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 和 LDAP的客户端URL传输库.libcurl也支持HTTPS认证,H…

[windows]python 安装pycurl

问题描述 pip install pycurl 报错 手动安装 下载地址&#xff1a;https://www.lfd.uci.edu/~gohlke/pythonlibs/ 页面搜索&#xff1a; pycurl 下载对应版本的whl文件&#xff0c;我是windows环境 python3.8 所以下载pycurl-7.45.1-cp38-cp38-win32.whl 安装&#xff1a;…

Python实用模块之pycurl

软硬件环境 ubuntu 19.04 64bitanaconda3 with python 3.7.3pycurl 7.43.0.2 简介 CURL是一个基于URL进行数据传输的命令行工具&#xff0c;使用C语言编写&#xff0c;支持http&#xff0c;https&#xff0c;ftp&#xff0c;telnet&#xff0c;file&#xff0c;ldap等常见网络传…

ipcs -a

消息队列、共享内存、信号量

ipcc

IPCCX装完后连接不了LDAP,怎么解决&#xff1f;&#xff1f; 装完了IPCCX, 靠&#xff0c; 直接给我来歌60秒关机&#xff0c; 后面还有LDAP连接问题&#xff0c; 我的IPCCX server 可以ping通ccm server, 为什么LDAP会挂呢&#xff1f;&#xff1f;&#xff1f; 请问我现在要怎…

ipcs报错:kernel not configured for shared memory、semaphore、message queues [解决方法]

前言 今天在复习linux进程间通信的shared memory 共享内存时&#xff0c;在PC端的VMare Workstation虚拟机的Ubuntu上测试我写的shared_memory_CREAT.c 和shared_memory_CONSUME.c 时正常在PC端运行&#xff0c;就想着把程序用交叉编译器编译成arm格式放到linux开发板上运行试…

ipcs

&#xfeff;&#xfeff; linux命令-ipcs 格式&#xff1a;ipcs [-asmq] [-tclup] ipcs [-smq] -i id ipcs -h 功能描述&#xff1a;ipcs命令用来显示系统存在的ipc&#xff08;进程间通信&#xff09;相关信息。 参数&#xff1a;-i 显示指定id的ip…

IPC方案

近期了解了不少网络摄像头相关知识&#xff0c;主要功能组成如下&#xff1a; WIFI&#xff0c;USB接口或者SDIO接口实现 RJ45 本地TF存储 IR CUT&#xff0c;滤光片切换 移动侦测&#xff0c;人体感应 夜视功能&#xff0c;依靠红外灯 云台控制&#xff0c;PWM控制Moto&#…

Linux15 --- 信号量、ipcs

1、IPC机制&#xff1a; 进程间通信&#xff08;管道、信号量、共享内存、消息队列、套接字&#xff09; 2、信号量&#xff1a; 可以类比于红绿灯&#xff0c;对于路口这个共享的通行权&#xff0c;谁得到红绿灯的通行信号&#xff0c;才可以得到路口的通行权&#xff0c;没…

Linux ipcs命令与ipcrm命令的用法详解

转载地址&#xff1a;http://www.jb51.net/article/40805.htm linux/uinx上提供关于一些进程间通信方式的信息&#xff0c;包括共享内存&#xff0c;消息队列&#xff0c;信号 ipcs用法 ipcs -a 是默认的输出信息 打印出当前系统中所有的进程间通信方式的信息 ipcs -m 打印出…

ipcs命令详解——共享内存、消息队列、信号量定位利器

多进程间通信常用的技术手段包括共享内存、消息队列、信号量等等&#xff0c;Linux系统下自带的ipcs命令是一个极好的工具&#xff0c;可以帮助我们查看当前系统下以上三项的使用情况&#xff0c;从而利于定位多进程通信中出现的通信问题。目前也有一些帖子介绍ipcs命令的使用方…

(1)IPC简介

Unix/Linux IPC简介 简述1. 消息传递演变过程2. 同步形式演变 进程、线程与信息共享IPC对象的持续性名字空间fork、exec和exit对IPC对象的影响总结参考资料 简述 IPC是进程间通信(interprocess communication)的简称。用来描述运行在一个操作系统之上的不同进程间各种消息传递…