需求背景
Q: pnpm通过workspace功能已经可以实现管理monorepo项目,为什么还需要引入turbo一起来管理
A: pnpm的workspace功能确实可以管理monorepo项目,但turbo提供了一些额外的优势
- 更快的构建速度:
turbo利用缓存和并行执行来显著加快构建过程。 它可以智能地跳过已经构建过的部分,只构建发生变化的部分。 - 任务编排:
turbo提供了强大的任务编排功能,可以定义复杂的任务依赖关系。 这使得管理大型monorepo项目中的构建、测试和部署流程变得更加容易。 - 远程缓存:
turbo支持远程缓存,可以在团队成员和CI/CD环境之间共享构建结果。 这进一步提高了整个团队的开发效率。 - 更好的可视化:
turbo提供了构建过程的可视化工具,帮助开发者理解和优化构建流程。 - 与其他工具的集成:
turbo可以与其他常用的开发工具和CI/CD系统无缝集成。
A: 以上是ai的回答,对我来说有用的并且我用到的就两方面。
- 构建速度
- 任务编排
总之,虽然pnpm的workspace功能可以满足基本的monorepo管理需求,但turbo通过提供更高级的功能和优化,可以进一步提高大型项目的开发效率和构建性能。
大纲
本文分为两个部分来介绍如何来实现pnpm+turbo来管理monorepo结构项目
- 通过pnpm来管理项目
- 引入turbo,和pnpm一起来管理monorepo项目
pnpm管理monorepo
首先我们来搭建一个基础的monorepo模板
pnpm init
将生成的package.json的private改为true,type改为module
主仓/package.json
{
"name": "turbo-post",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
创建子仓(pnpm init),并配置pnpm-workspace.yaml,这里拿eslint-config为例(隶属于internal 此时的目录结构
.
|-internal
| |-eslint-config
| | |-package.json
|-package.json
|-pnpm-workspace.yaml
pnpm-workspace.yaml
packages:
- 'internal/*'
eslint直接使用antfu的eslint-config
cd internal/eslint-config
pnpm i -D eslint @antfu/eslint-config
eslint-config/package.json
{
"name": "@afe1/eslint-config",
"type": "module",
"version": "1.0.0",
"private": true,
"description": "",
"author": "",
"license": "ISC",
"keywords": [],
"devDependencies": {
"@antfu/eslint-config": "^3.6.2",
"eslint": "^9.10.0"
}
}
创建eslint.config.mjs配置如下
eslint-config/package.json
// eslint.config.mjs
import antfu from '@antfu/eslint-config'
export default antfu({
ignores: [
'index.d.ts',
],
})
将”@afe1/eslint-config“添加到主仓/package.json的peerDependencies中
pnpm i "@afe1/eslint-config@workspace:*" -w -D
基本工作已完成,接下来我们引入turbo
pnpm+turbo管理monorepo
由于主仓下的eslint.config.mjs,使用的是子仓eslint-config的打包产物,这里我们还需要下载一个打包器这里选择的是unjs的unbild
pnpm i unbuild turbo -w -D
现在去配置下eslint-config的unbuild配置
build.config.ts
import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
clean: true,
declaration: true,
entries: ['eslint.config.mjs'],
})
type类型声明
index.d.ts
import type { Linter } from 'eslint';
declare const defineConfig: Linter.Config;
export default defineConfig;
package.json中配置unbuild打包产物引用路径和turbo里面tasks的脚步配置
eslint-config/package.json
{
"name": "@afe1/eslint-config",
"type": "module",
"version": "1.0.0",
"private": true,
"description": "",
"author": "",
"license": "ISC",
"keywords": [],
"exports": {
".": {
"types": "./index.d.ts",
"import": "./dist/index.mjs"
}
},
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./index.d.ts",
"files": [
"dist"
],
"scripts": {
"stub": "pnpm unbuild --stub"
},
"devDependencies": {
"@antfu/eslint-config": "^3.6.2",
"eslint": "^9.10.0"
}
}
根目录配置turbo.json 根目录package.json配置packageManager
turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", "dist.zip"]
},
"stub": {
"cache": false
},
"dev": {
"persistent": true,
"cache": false
}
}
}
执行 turbo run stub 这时候会看到eslint-config会生成dist的打包产物
在主仓的eslint.config.mjs中引用
import defineConfig from "@afe1/eslint-config";
export default defineConfig;
这样就实现了turbo和pnpm一起管理monorepo项目