Vite Monorepo中React Context丢失问题求助
解决Lerna Monorepo中Vite构建下跨包Context失效问题
问题根源
核心原因是monorepo中依赖被重复实例化。当shared包和app1各自安装了React、Redux或React Router,或者虽根目录已安装,但Vite的ESM模块解析策略导致两个包加载了不同的依赖实例——shared用自身node_modules里的副本,app1用自己的,最终Context对象不是同一个引用,hook自然无法获取Provider中的值。此前用tsc输出CommonJS时,Node的模块解析逻辑会自动复用根目录依赖,因此未触发该问题。
解决方案
1. 统一依赖版本并提升到根目录
- 在monorepo根目录的
package.json中声明React、Redux、React Router等依赖的精确版本,根据使用场景标记为dependencies或devDependencies。 - 删除所有子包(shared、app1)
node_modules中的这些依赖,同时在子包的package.json中将它们设为peerDependencies,避免子包单独安装:// shared/package.json { "peerDependencies": { "react": "^18.2.0", "react-redux": "^8.1.2", "react-router-dom": "^6.15.0" } } - 运行
lerna bootstrap --hoist(或npm/yarn的工作区hoist命令),确保所有子包共享根目录的依赖实例。
2. 配置Vite强制复用依赖
在app1的vite.config.ts中添加resolve配置,强制Vite从根目录加载共享依赖,避免子包加载本地副本:
import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], resolve: { dedupe: ['react', 'react-dom', 'react-redux', 'react-router-dom'], }, });
dedupe数组列出所有需要强制复用的依赖包名,确保整个monorepo中只加载一份实例。
3. 调整shared包的构建配置
如果shared包用Vite打包,需确保打包时不将peer依赖打包进产物:
// shared/vite.config.ts export default defineConfig({ build: { lib: { entry: 'src/index.ts', formats: ['es'], }, rollupOptions: { external: ['react', 'react-redux', 'react-router-dom'], }, }, });
external配置告诉Rollup不要把这些依赖打包进shared产物,而是运行时从宿主环境(app1)获取,保证依赖实例一致。
4. 验证依赖实例一致性
可在app1和shared中分别打印依赖的引用地址,确认是否一致:
// shared/useSomeHook.ts import React from 'react'; import { useSelector } from 'react-redux'; console.log('shared React:', React); console.log('shared useSelector:', useSelector); // app1/SomeConsumer.tsx import React from 'react'; import { useSelector } from 'react-redux'; import { useSomeHook } from 'shared'; console.log('app1 React:', React); console.log('app1 useSelector:', useSelector);
若打印的引用地址相同,说明依赖实例已统一,Context问题应得到解决。
内容的提问来源于stack exchange,提问作者Geoff Harper
相关产品推荐
相关产品推荐

