Packages vs Shared 目录对比
📊 核心区别
| 特性 | Packages | Shared 目录 | |------|----------|-------------| | 包管理系统 | ✅ 集成 pnpm workspace | ❌ 无包管理 | | 依赖声明 | ✅ 明确的 package.json | ❌ 隐式依赖 | | 版本控制 | ✅ 独立版本号 | ❌ 无版本概念 | | 构建系统 | ✅ Turbo 自动处理 | ❌ 手动管理 | | 类型系统 | ✅ 完整的 TypeScript 支持 | ⚠️ 路径映射 | | 工具支持 | ✅ 完整生态支持 | ⚠️ 有限支持 | | 可重用性 | ✅ 易于跨项目使用 | ❌ 项目绑定 | | 构建缓存 | ✅ Turbo 缓存优化 | ❌ 无缓存 |
🎯 Packages 的核心优势
1. 包管理系统集成 ✅
Packages (有 package.json)
{
"name": "@interview/utils",
"version": "0.1.0",
"dependencies": {
"clsx": "^2.0.0"
}
}
优势:
- ✅ 明确的依赖声明
- ✅ 自动依赖解析
- ✅ 版本锁定机制
- ✅ 依赖冲突检测
Shared (无包管理)
// ❌ 依赖关系不明确
// ❌ 无法声明外部依赖
// ❌ 版本管理困难
2. 构建系统支持 ✅
Packages (Turbo 自动处理)
// turbo.json
{
"tasks": {
"build": {
"dependsOn": ["^build"], // 自动处理依赖顺序
"outputs": ["dist/**"]
}
}
}
优势:
- ✅ 自动构建顺序 (
dependsOn: ["^build"]) - ✅ 并行构建优化
- ✅ 增量构建支持
- ✅ 构建缓存机制
Shared (手动管理)
# ❌ 需要手动确保构建顺序
# ❌ 无法利用构建缓存
# ❌ 构建顺序容易出错
3. 依赖关系图 ✅
Packages (自动依赖图)
@interview/admin
├── @interview/utils (workspace:*)
├── @interview/types (workspace:*)
└── @interview/constants (workspace:*)
@interview/utils
└── clsx (^2.0.0)
优势:
- ✅
pnpm list查看完整依赖树 - ✅ 自动检测循环依赖
- ✅ 依赖更新影响分析
- ✅ 清晰的依赖边界
Shared (隐式依赖)
# ❌ 依赖关系不明确
# ❌ 无法追踪依赖链
# ❌ 循环依赖难以发现
4. 版本管理和发布 ✅
Packages (独立版本)
{
"name": "@interview/utils",
"version": "0.1.0" // 可以独立版本化
}
优势:
- ✅ 使用 Changesets 管理版本
- ✅ 语义化版本控制
- ✅ 可以发布到 npm
- ✅ 版本回滚支持
Shared (无版本)
// ❌ 无法版本化
// ❌ 无法发布
// ❌ 版本管理困难
5. TypeScript 类型系统 ✅
Packages (完整类型支持)
// packages/utils/src/index.ts
export function validateEmail(email: string): boolean {
// ...
}
// 自动生成类型定义
// packages/utils/dist/index.d.ts
优势:
- ✅ 自动生成
.d.ts类型文件 - ✅ 类型导出完整
- ✅ IDE 智能提示更好
- ✅ 类型检查更严格
Shared (路径映射)
// tsconfig.json
{
"paths": {
"@shared/*": ["../../shared/*"] // 简单的路径映射
}
}
劣势:
- ⚠️ 类型定义需要手动维护
- ⚠️ IDE 支持可能不完整
- ⚠️ 类型检查可能不够严格
6. 构建缓存和性能 ✅
Packages (Turbo 缓存)
# Turbo 自动缓存
$ turbo build
✓ @interview/utils:build (cache hit)
✓ @interview/types:build (cache hit)
✓ @interview/admin:build (0.5s)
优势:
- ✅ 增量构建,只构建变更的包
- ✅ 构建结果缓存
- ✅ CI/CD 中显著加速
- ✅ 并行构建优化
Shared (无缓存)
# ❌ 每次都要重新构建
# ❌ 无法利用缓存
# ❌ 构建时间较长
7. 工具生态支持 ✅
Packages (完整工具链)
# 依赖分析
pnpm why clsx
# 依赖更新
pnpm update @interview/utils
# 依赖检查
pnpm audit
# 包信息
pnpm list --depth=0
优势:
- ✅ pnpm 完整功能支持
- ✅ Changesets 版本管理
- ✅ Turbo 构建优化
- ✅ 各种工具原生支持
Shared (工具支持有限)
# ❌ 无法使用包管理工具
# ❌ 依赖分析困难
# ❌ 更新管理不便
8. 可重用性和跨项目使用 ✅
Packages (易于重用)
# 在其他项目中安装
pnpm add @interview/utils
# 或通过 workspace
"@interview/utils": "workspace:*"
优势:
- ✅ 可以发布到 npm
- ✅ 可以在其他 monorepo 中使用
- ✅ 版本控制清晰
- ✅ 依赖管理简单
Shared (项目绑定)
// ❌ 只能通过路径映射使用
// ❌ 无法跨项目重用
// ❌ 无法发布
9. 开发和调试体验 ✅
Packages (更好的开发体验)
# 独立开发包
cd packages/utils
pnpm dev # 监听模式
# 独立测试
pnpm test
# 独立 lint
pnpm lint
优势:
- ✅ 每个包可以独立开发
- ✅ 独立的开发脚本
- ✅ 更好的代码组织
- ✅ 更容易定位问题
Shared (统一管理)
# ❌ 无法独立开发
# ❌ 需要手动管理脚本
# ❌ 代码组织不够清晰
10. CI/CD 集成 ✅
Packages (CI/CD 友好)
# .github/workflows/ci.yml
- name: Build packages
run: pnpm turbo build --filter='@interview/utils'
- name: Test packages
run: pnpm turbo test --filter='@interview/utils'
优势:
- ✅ 可以单独测试/构建包
- ✅ 并行执行优化
- ✅ 缓存机制加速
- ✅ 更好的错误隔离
Shared (整体构建)
# ❌ 无法单独构建
# ❌ 缓存效果差
# ❌ 错误隔离困难
📈 实际场景对比
场景 1: 添加新依赖
Packages
# 1. 在包的 package.json 中添加
cd packages/utils
pnpm add clsx
# 2. 自动更新 lockfile
# 3. 依赖关系清晰
Shared
# ❌ 需要在根目录添加
# ❌ 依赖关系不明确
# ❌ 可能影响其他包
场景 2: 更新依赖
Packages
# 只更新特定包
pnpm update @interview/utils
# 查看更新影响
pnpm why @interview/utils
Shared
# ❌ 需要手动检查所有使用处
# ❌ 更新影响不明确
# ❌ 容易遗漏
场景 3: 构建优化
Packages
# Turbo 自动优化
$ turbo build
✓ @interview/utils:build (cache hit, 0.1s)
✓ @interview/types:build (cache hit, 0.1s)
✓ @interview/admin:build (0.5s)
# 总时间: 0.7s (利用缓存)
Shared
# ❌ 每次完整构建
$ build
✓ Building all... (5.2s)
# 总时间: 5.2s (无缓存)
场景 4: 跨项目使用
Packages
# 项目 A
pnpm add @interview/utils@^0.1.0
# 项目 B (另一个 monorepo)
pnpm add @interview/utils@^0.1.0
Shared
// ❌ 需要复制代码
// ❌ 无法版本管理
// ❌ 维护困难
🎯 总结
Packages 的核心价值
- 工程化: 完整的包管理、构建、测试体系
- 可维护性: 清晰的依赖关系、版本控制
- 性能: 构建缓存、并行优化
- 可扩展性: 易于跨项目重用、发布
- 工具支持: 完整的生态系统支持
Shared 的局限性
- 无包管理: 依赖关系不明确
- 无构建优化: 无法利用缓存
- 项目绑定: 难以跨项目重用
- 工具支持有限: 无法使用完整的工具链
✅ 结论
Packages 是 monorepo 的标准做法,提供了:
- ✅ 更好的工程化支持
- ✅ 更高的开发效率
- ✅ 更强的可维护性
- ✅ 更好的工具生态集成
Shared 目录适合:
- ⚠️ 非常简单的项目
- ⚠️ 不需要版本管理的代码
- ⚠️ 临时性的共享代码
对于生产级项目,Packages 是更好的选择! 🎉