Published on

monorepo | pnpm workspace | turborepo

Authors
  • avatar
    Name
    Shelton Ma
    Twitter

1. Monorepo

Monorepo(Mono Repository) 是一种项目组织结构,指的是多个相关项目(比如多个 npm 包)共享一个仓库。

  1. 项目结构如下, 在这个结构下,backend, frontend, shared-lib, trpc 都是独立的项目,但它们共享一个 Git 仓库。

    my-monorepo/
    ├── apps/
    │   ├── backend/
    │   ├── frontend/
    ├── packages/
    │   ├── trpc/
    │   └── shared-lib/
    ├── package.json
    └── pnpm-workspace.yaml
    
  2. 优点

    • 更好的代码共享, 多个项目可以使用同一个共享模块,不需要发布到 npm
    • 一致性更强, 统一的依赖版本管理、更方便的 Lint、测试、构建脚本
    • 开发效率高, 本地开发时可以直接链接依赖,不需要频繁发布

2. pnpm workspace

pnpm workspacepnpm 提供的对 monorepo 项目的支持工具。作用包括:

  • 统一管理多个 package 的依赖
  • 自动将本地 package 相互链接
  • 支持在根目录运行构建、测试、发布等操作
  1. 根目录的 package.json

    {
      "name": "my-monorepo",
      "private": true,
      "devDependencies": {
        "typescript": "^5.0.0"
      }
    }
    
  2. pnpm-workspace.yaml

    packages:
      - "packages/*"
      - "apps/*"
      - "prisma"
    
  3. 使用pnpm install时会用符号链接的方式引用本地的 shared-lib

3. 一些常用命令

  1. pnpm install: 安装所有依赖
  2. pnpm -r buildpnpm --filter backend build: 在 workspace 中递归构建某个包或全部包
  3. pnpm add shared-lib --filter backend: 给 backend 添加对 shared-lib 的依赖

4. 使用共享包

1. 使用 @my-org/api-types(标准的 npm scope 名称)

  1. 优点:

    • 一致性和规范性:这符合 npm 的命名规则,方便团队成员理解这个包是属于组织(或项目)的一部分。
    • 未来扩展:如果项目增大,或者要发布公共版本时,可以直接将其发布到 npm(如发布 @my-org/api-types)而不会产生混淆。
    • 版本管理更清晰:通过规范的命名,你可以控制版本、依赖关系以及发布策略,方便团队管理版本和包之间的依赖。
    • 易于引用和共享:如果你需要将这个包单独发布或共享给其他项目、团队或外部,@my-org 的命名可以直接作为标识。
  2. 使用

    1. pnpm-workspace.yaml 中配置工作区

      packages:
        - "packages/*"
        - "apps/*"
        - "prisma"
      
    2. 配置需要共享的包

      // package.json
      {
        "name": "@penyo/api-types",
        "version": "1.0.0",
        "description": "Shared tRPC utilities",
        ...
      }
      
    3. 在需要的项目中配置, 这里的 workspace:* 会告诉 pnpm 使用当前工作区的版本,而不是从 npm 拉取。

      // apps/fastify-api/package.json
      ...
      "dependencies": {
        "@penyo/api-types": "workspace:*"
      },
      ...
      
    4. 之后执行pnpm install

    5. 使用

      import { appRouter, AppRouter } from "@penyo/api-types"; 
      

2. 通过路径映射

  1. 根目录配置tsconfig.json

    {
      "compilerOptions": {
        "baseUrl": ".",
        "paths": {
          "@api-types/*": ["packages/api-types/src/*"],
          "@api-types": ["packages/api-types/src/index.ts"]
        }
    },
    
  2. 其他目录继承"extends": "../../tsconfig.json",

  3. 使用 import { appRouter, AppRouter } from "@api-types";

5. pnpm workspaceTurborepo 搭配使用

1. 根目录package.json

// package.json
{
  "name": "sheltonScaffold",
  "private": true,
  "workspaces": ["apps/*", "packages/*"],
  "scripts": {
    "dev": "turbo run dev"
  },
  "devDependencies": {
    "turbo": "^1.11.0",
    "concurrently": "^8.2.0"
  },
  "packageManager": "pnpm"
}

2. 添加 turbo.json

{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "dev": {
      "cache": false,
      "parallel": true
    },
    "build": {
      "outputs": ["dist/**", ".next/**"],
      "dependsOn": ["^build"]
    },
    "lint": {},
    "test": {}
  }
}

3. 启动命令

  1. 启动所有服务 pnpm dev/ turbo run dev
  2. 构建所有服务 turbo run build
  3. 单独构建 pnpm --filter api build
  4. 清除缓存 turbo run build --no-cache