背景
- 项目结构:pnpm Monorepo
-
packages/ui:React 组件库(使用 Vite + TS 打包)apps/react-demo:React 应用,依赖@my-org/ui
- 目标:
-
- ✅ 开发环境:修改
ui源码 → 自动热更新到react-demo - ✅ 生产构建:
react-demo能正确打包@my-org/ui
- ✅ 开发环境:修改
遇到的问题 & 解决方案
❌ 问题 1:生产构建时报错 ------ @my-org/ui 无法解析
arduino
// 错误信息
[vite]: Rolldown failed to resolve import "@my-org/ui" ...
🔎 根本原因:
react-demo的node_modules/@my-org/ui/中 没有 ****dist/****目录- 导致 Vite 找不到 JS 入口文件(如
ui.js)
✅ 解决步骤:
- 确认 ****
packages/ui/package.json****包含 ****"files": ["dist"]
→ 否则 pnpm 不会把dist链接到 consumer 的node_modules - 先构建 UI 库
css
pnpm --filter @my-org/ui build
- 确保 ****
react-demo****声明了依赖
sql
pnpm add @my-org/ui@workspace:* --filter react-demo
- 强制刷新链接
css
pnpm install --force
💡 关键认知:pnpm workspace 链接 ≠ 实时目录映射 ,它只链接 package.json 中声明的文件(通过 files),且需在 dist 存在后执行 install。
❌ 问题 2:package.json 入口文件名与实际输出不一致
- 配置写的是:
json
"main": "./dist/index.js"
- 但 Vite 默认输出:
bash
dist/ui.js
dist/ui.mjs
🔎 后果:
- 即使
dist被链接,Vite 仍尝试加载不存在的index.js→ 模块解析失败
✅ 解决方案(二选一):
| 方案 | 操作 |
|---|---|
| A(推荐) | 修改 package.json指向真实文件: "main": "./dist/ui.js" |
| B | 修改 vite.config.ts强制输出 index.js: fileName: (format) => index.${format === 'es' ? 'mjs' : 'js'}`` |
✅ 最终选择 方案 A,避免改构建配置,更简单直接。
❌ 问题 3:即使 files 正确,dist 仍不出现
运行 pnpm install --force 后,node_modules/@my-org/ui/dist 依然不存在。
🔎 深层原因:
react-demo/package.json未声明对 ****@my-org/ui****的依赖- pnpm 不会自动链接未声明的 workspace 包
✅ 解决:
sql
pnpm add @my-org/ui@workspace:* --filter react-demo
→ 显式建立依赖关系,pnpm 才会创建 symlink 并包含 dist/。
📌 这是 Monorepo 的核心规则: "未声明 = 不存在"
✅ 问题 4:开发环境如何实现热更新?
生产构建成功后,需支持开发时实时编辑 ui 组件。
✅ 解决方案:
- 在 ****
react-demo/vite.config.ts****中添加 alias:
css
resolve: {
alias: {
'@my-org/ui': path.resolve(__dirname, '../../packages/ui/src')
}
}
- 启动开发服务器:
css
pnpm --filter react-demo dev
💡 原理:Vite 直接编译 ui/src 源码(而非 dist),天然支持 HMR 和 TSX。
🧪 验证清单(最终状态)
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| UI 库已构建 | ls packages/ui/dist |
有 ui.js, ui.mjs, *.d.ts |
| 依赖已声明 | grep "@my-org/ui" apps/react-demo/package.json |
有 "@my-org/ui": "workspace:*" |
| 链接已同步 | ls apps/react-demo/node_modules/@my-org/ui/dist |
文件存在 |
| 生产构建成功 | pnpm --filter react-demo build |
无报错,生成 dist/ |
| 开发热更新 | 修改 ui/src/Button.tsx→ 浏览器自动刷新 |
✅ 实时生效 |
📚 经验总结
| 场景 | 关键配置 |
|---|---|
| 生产构建 | package.json的 main/module必须匹配真实文件名 + "files": ["dist"] |
| 依赖链接 | Consumer 必须在 package.json中显式声明 workspace:*依赖 |
| 开发体验 | 通过 Vite alias指向 src,绕过 dist,实现 HMR |
| 构建顺序 | 先 build ui→ 再 pnpm install→ 最后 build app |