使用 pnpm、turborepo 构建 monorepo 项目,changesets 管理日志和版本详解,从零至 github actions(CI)云端缓存 发布 npm 流程
环境与版本
platform
=>mac os
node
=>v22.2.0
npm
=>10.8.0
pnpm
=>9.1.3
yarn
=>1.22.22
turbo
=>1.13.3
changesets
=>2.27.5
前置准备
快速开始
命令初始化
pnpm dlx create-turbo@latest
使用模版
本文使用的模版:monorepo with changesets
pnpm dlx create-turbo -e with-changesets
目录结构
demo-turoborepo
├── apps
│ ├── docs
│ └── web
├── packages
│ ├── ui
│ ├── eslint-config
│ └── typescript-config
├── package.json
├── turbo.json
└── pnpm-workspace.yaml
Turborepo
Turborepo
介绍
Turborepo
是专为 JavaScript
和 Typescript
的 monorepo
项目设计的高性能构建系统。可以高效管理和构建项目中多个 packages
,通过缓存构建和测试结果,来提升开发和持续集成的效率。Turborepo
旨在提高大型 monorepo
项目的构建效率,在复杂的项目中,可以更好的处理任务之间的依赖关系,并保证构建的正确性和效率。
优势
- 多任务并行处理
- 增量构建
- 云缓存
Pipeline - 管道
Turborepo
为开发人员提供了一种以常规方式显示指定任务关系的方法。 在 Turborepo
中可以在项目根目录中定义 turbo.json
来配置输出、缓存依赖、打包等功能。
在 pipeline
中的每一个 key
都指向我们在 package.json
中定义的 script
脚本执行命令,并且在 pipeline
中的每一个 key
都可以被 turbo run
执行。
在执行 turbo run
命令时,turbo
会根据 pipeline
中的配置,对每个 package.json
中的 script
执行脚本进行有序的执行和 缓存输出的文件
和日志
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
// `build` tasks being completed first
// (the `^` symbol signifies `upstream`).
"dependsOn": ["^build"],
// note: output globs are relative to each package's `package.json`
// (and not the monorepo root)
"outputs": [".next/**", "!.next/cache/**"]
},
"test": {
// A package's `test` script depends on that package's
// own `build` script being completed first.
"dependsOn": ["build"],
"outputs": [],
// A package's `test` script should only be rerun when
// either a `.tsx` or `.ts` file has changed in `src` or `test` folders.
"inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts", "test/**/*.tsx"]
},
"lint": {
"dependsOn": ["^lint"]
},
"dev": {
// Setting cache to false is useful for daemon or long-running "watch"
// or development mode tasks you don't want to cache.
"cache": false,
// Label a task as persistent if it is a long-running process
// such as a dev server or --watch mode.
"persistent": true
}
}
}
dependsOn
常规依赖
如果任务需要依赖其他任务,则可以放入 dependsOn
内。例如执行 deploy
任务时需要 build
、test
、lint
任务先完成
当然,在这里你只需要执行 turbo run deploy
即可,turbo
会按 dependsOn
中定义脚本执行
{
"turbo": {
"pipeline": {
"deploy": {
"dependsOn": ["build", "test", "lint"]
}
}
}
}
依赖工作空间中的包 - From dependent workspaces
目录结构
例如当 docs
build
时,需要 ui
和 hooks
build
完成之后,此时需在 dependsOn
中配置 ^
符号来明确依赖关系。
apps/
docs/package.json # 依赖 ui 和 hooks
packages/
ui/package.json
hooks/package.json
turbo.json
package.json
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
// A workspace's `build` command depends on its dependencies'
// and devDependencies' `build` commands being completed first
"dependsOn": ["^build"]
}
}
}
拓扑依赖 - Dependencies outside of a task
目录结构
apps/
docs/package.json # 依赖 ui
web/package.json # 依赖 ui
packages/
ui/package.json # 无依赖
turbo.json
package.json
{
"pipeline": {
// fake task
"topo": {
"dependsOn": ["^topo"]
},
"typeCheck": {
"dependsOn": ["topo"]
}
}
}
{
"name": "docs",
"script": {
"typeCheck": "tsc --checkJs --noEmit"
}
}
应用场景
先了解业务场景,再尝试理解这段逻辑。
{
"pipeline": {
"topo": {
"dependsOn": ["^topo"]
},
"typeCheck": {
"dependsOn": ["topo"]
}
}
}
本地远程缓存
登录 Vercel
执行命令后,你将跳转至 Vercel 的授权页面
turbo login
# or
pnpm dlx turbo login
开启缓存
turbo link
# or
pnpm dlx turbo link
测试远程缓存
rm -rf ./node_modules/.cache/turbo
关闭缓存
turbo unlink
# or
pnpm dlx turbo unlink
在 CI 中使用远程缓存 - Using Turborepo with GitHub Actions
设置环境变量
name: Release
on:
push:
branches:
- "main"
jobs:
release:
name: Release
runs-on: ubuntu-latest
# To use Turborepo Remote Caching, set the following environment variables for the job.
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
steps:
- name: Install Dependencies
run: pnpm i
- name: Build
run: pnpm build
生成 secrets
TURBO_TOKEN
生成 variables
TURBO_TEAM
缓存效果
changesets
安装 changeset
pnpm add -Dw @changesets/cli
# or
pnpm add -Dw @changesets/cli @changesets/changelog-github
# or
pnpm add -Dw @changesets/cli @changesets/changelog-git
初始化
pnpm changeset init
{
"$schema": "https://unpkg.com/@changesets/config@3.0.1/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "tardis-ksh/demo-turborepo" }
],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"updateInternalDependencies": "patch",
"ignore": ["@tardis-ksh/docs", "@test/**"],
"baseBranch": "main"
}
配置说明
* baseBranch
(git branch name)
access
(restricted | public)
commit
(boolean, or module path as a string, or a tuple like [modulePath: string, options: any])
updateInternalDependencies
(patch | minor | major)
ignore
(array of packages)
{
"ignore": ["@tardis-ksh/docs", "@test/**"]
}
* changelog
@changesets/changelog-github
{
"changelog": [
"@changesets/changelog-github",
{ "repo": "tardis-ksh/demo-turborepo" }
]
}
@changesets/changelog-git
{
"changelog": "@changesets/changelog-git"
}
custom
{
"changelog": "./getChangelogEntry",
}
命令
changeset add
添加变更
pnpm changeset add
# or
pnpm changeset
变更文件
changeset version
生成 版本变更 和 changelog
pnpm changeset version
problem with @changesets/changelog-github
add `GITHUB_TOKEN
$ vim ~/.zshrc
# add in your file
# export GITHUB_TOKEN = "some string"
$ source ~/.zshrc
$ echo $GITHUB_TOKEN
或者临时使用
GITHUB_TOKEN=your_token pnpm changeset version
Cannot read properties of null (reading ‘author’)
publish
pnpm changeset publish
在 CI(actions)中使用
name: Release
on:
push:
branches:
- "main"
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
# This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits
fetch-depth: 0
- name: Setup pnpm
run: corepack enable
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install Dependencies
run: pnpm i
- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
# This expects you to have a script called release which does a build for your packages and calls changeset publish
publish: pnpm release
commit: 'chore: release packages'
title: 'chore: release packages'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: if a publish happens
if: steps.changesets.outputs.published == 'true'
# You can do something when a publish happens.
run: |
echo "down"
处理 Pull requests - changeset-bot
结尾
Turborepo
changesets
changesets/action
https://juejin.cn/post/7129267782515949575