← 返回文档列表

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 的核心价值

  1. 工程化: 完整的包管理、构建、测试体系
  2. 可维护性: 清晰的依赖关系、版本控制
  3. 性能: 构建缓存、并行优化
  4. 可扩展性: 易于跨项目重用、发布
  5. 工具支持: 完整的生态系统支持

Shared 的局限性

  1. 无包管理: 依赖关系不明确
  2. 无构建优化: 无法利用缓存
  3. 项目绑定: 难以跨项目重用
  4. 工具支持有限: 无法使用完整的工具链

✅ 结论

Packages 是 monorepo 的标准做法,提供了:

  • ✅ 更好的工程化支持
  • ✅ 更高的开发效率
  • ✅ 更强的可维护性
  • ✅ 更好的工具生态集成

Shared 目录适合

  • ⚠️ 非常简单的项目
  • ⚠️ 不需要版本管理的代码
  • ⚠️ 临时性的共享代码

对于生产级项目,Packages 是更好的选择! 🎉