Monorepo下Vite HMR失效:如何让UI组件实现热更新而非全页重载?
实现Monorepo中UI组件库的Vite HMR热更新
项目场景
我使用npm workspaces开发Monorepo项目,结构如下:
monorepo/ apps/web - (Vite React应用) packages/ui - (使用tsc构建、无打包工具的React组件库)
web应用的vite.config.ts配置:
export default defineConfig({ plugins: [react()], resolve: { alias: { "@": path.resolve(__dirname, "./src"), }, }, optimizeDeps: { exclude: ["@monorepo/ui"], }, define: { "process.env": {}, }, });
UI包的package.json配置:
{ "name": "@monorepo/ui", "type": "module", "scripts": { "dev": "tsc --watch", "build": "tsc" }, "exports": { "./button": { "default": "./dist/button.js", "types": "./src/button.tsx" }, ... }
web应用中组件引入方式:
// web应用的home.page.ts import { Button } from "@monorepo/ui/button";
问题
修改UI包中的Button组件时,web应用会触发全页重载,如何实现组件级的HMR热更新而非全页重载?
解决方案
1. 调整UI包的exports配置,开发环境指向源码
当前UI包默认指向编译后的dist/button.js,Vite对dist文件的变化无法触发React组件级HMR。修改package.json,为开发环境单独配置源码入口:
{ "name": "@monorepo/ui", "type": "module", "scripts": { "dev": "tsc --watch", "build": "tsc" }, "exports": { "./button": { "development": "./src/button.tsx", // 开发环境直接用源码 "default": "./dist/button.js", "types": "./src/button.tsx" }, ... }
2. 配置Vite允许访问UI包源码
Vite默认限制文件访问范围,需要修改vite.config.ts让它能读取monorepo根目录下的文件:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import path from 'path'; export default defineConfig({ plugins: [react()], resolve: { alias: { "@": path.resolve(__dirname, "./src"), }, }, optimizeDeps: { exclude: ["@monorepo/ui"], }, define: { "process.env": {}, }, server: { fs: { allow: [path.resolve(__dirname, '../../')] // 允许访问monorepo根目录 } } });
3. 确保组件符合HMR要求
UI组件需要满足:
- 采用命名导出或默认导出(当前Button的命名导出符合要求)
- 组件文件无全局副作用(比如顶级DOM操作、全局变量修改)
4. 启动开发服务的正确流程
- 先在UI包目录执行
npm run dev启动tsc watch,保证类型实时更新 - 再在web应用目录启动Vite开发服务
完成以上配置后,修改UI组件时会触发React组件级的HMR,不再触发全页重载。
内容的提问来源于stack exchange,提问作者Alym Sagymbaev
相关产品推荐
相关产品推荐

