monorepo 实战练习

656 阅读2分钟

项目结构

my-monorepo/
├── package.json           # 根项目配置
├── pnpm-workspace.yaml    # 工作空间配置
├── packages/              # 可共享的库/包
│   └── utils/             # 工具函数库
│       ├── package.json   # utils包配置
│       ├── tsconfig.json  # TypeScript配置
│       └── src/           # 源代码
│           ├── index.ts   # 入口文件
│           ├── format.ts  # 格式化函数
│           ├── validation.ts # 验证函数
│           └── string.ts  # 字符串处理函数
├── apps/                  # 应用程序
│   └── web/               # Web应用
│       ├── package.json
│       ├── tsconfig.json
│       └── src/
│           └── index.ts
└── tools/                 # 内部工具
    └── typescript-config/ # TypeScript配置共享
        ├── package.json
        ├── base.json      # 基础TS配置
        ├── nextjs.json    # Next.js项目配置
        ├── react-library.json # React库配置
        └── vue-library.json   # Vue库配置

1. 项目初始化

# 创建项目目录
mkdir my-monorepo
cd my-monorepo

# 初始化项目
pnpm init

# 安装开发依赖
pnpm add -D typescript eslint prettier @changesets/cli

编辑根目录 package.json

{
  "name": "my-monorepo",
  "version": "0.0.0",
  "private": true,
  "scripts": {},
  "devDependencies": {
    "@changesets/cli": "^2.26.0",
    "eslint": "^8.40.0",
    "prettier": "^2.8.8",
    "typescript": "^5.0.4"
  }
}

2. 配置工作空间(workspace)

新建 pnpm-workspace.yaml

packages:
  - 'packages/*'
  - 'apps/*'
  - 'tools/**'

💡 这样定义后,packages/apps/tools/ 目录下的所有子目录都会作为子包(package)纳入管理。

3 创建子项目

3.1 创建工具包:统一 TypeScript 配置 (tools/typescript-config)

# 创建目录
mkdir -p tools/typescript-config
cd tools/typescript-config

# 初始化 package.json
pnpm init

编辑 tools/typescript-config/package.json

{
  "name": "@workspace/typescript-config",
  "version": "1.0.0",
  "private": true,
  "files": [
    "base.json",
    "nextjs.json",
    "react-library.json",
    "vue-library.json"
  ]
}

新增基础 TypeScript 配置文件:

  • tools/typescript-config/base.json
  • tools/typescript-config/nextjs.json
  • tools/typescript-config/react-library.json
  • tools/typescript-config/vue-library.json

💡 @workspace/typescript-config 这个包的作用是:统一管理项目中所有子包的 TypeScript 配置,保证一致性,避免每个子包重复配置。

3.2 创建通用工具库 (packages/utils)

# 创建目录
mkdir -p packages/utils/src
cd packages/utils

# 初始化 package.json
pnpm init

编辑 packages/utils/package.json

{
  "name": "@workspace/utils",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "main": "dist/index.js",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "files": ["dist/**"],
  "scripts": {
    "build": "tsup src/index.ts --format esm,cjs --dts",
    "dev": "tsup src/index.ts --format esm,cjs --watch --dts"
  },
  "devDependencies": {
    "@workspace/typescript-config": "workspace:^",
    "lodash": "^4.17.21",
    "tsup": "^8.4.0"
  }
}

创建源码文件:

  • src/index.ts
  • src/format.ts
  • src/validation.ts
  • src/string.ts

💡 @workspace/utils 这个包的作用是:封装通用工具函数(如字符串处理、日期格式化、表单校验等)供各应用共享使用

3.3 创建 Web 应用项目 (apps/web)

# 创建目录
mkdir -p apps/web/src
cd apps/web

# 初始化 package.json
pnpm init

编辑 apps/web/package.json

{
  "name": "web",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "scripts": {
    "dev": "tsc -w",
    "build": "tsup src/index.ts --format esm,cjs --dts"
  },
  "dependencies": {
    "@workspace/typescript-config": "workspace:^",
    "@workspace/utils": "workspace:^",
    "tsup": "^8.4.0"
  }
}

创建入口文件 src/index.ts

import { capitalize } from '@workspace/utils';

const str = 'hello world';
console.log(capitalize(str));

新增 tsconfig.json

{
  "extends": "@workspace/typescript-config/base.json",
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules", "dist"]
}

4 安装所有依赖

在项目根目录执行:

pnpm install

5 构建与开发

构建所有包:

pnpm build

开发模式下启动 Web 应用:

pnpm --filter web dev

运行打包产物:

cd apps/web/dist
node index.js

输出:

Hello world

6 小结

通过这个实战,我们搭建了一个完整的 Monorepo 基础架构,包括:

  • 工具包:统一的 TypeScript 配置
  • 通用库:工具函数、组件库
  • 应用项目:Web 网站、管理后台等

使用了:

  • pnpm workspace 统一管理依赖
  • Tsup 快速打包构建
  • TypeScript 保证类型安全

这种结构可以随着项目扩大,灵活地扩展新的库或应用,同时保持良好的组织性和开发效率。