Turborepo简易教程

参考官网:https://turbo.build/repo/docs

开始

安装全新的项目

pnpm dlx create-turbo@latest

测试应用包含:

  • 两个可部署的应用
  • 三个共享库

image.png
运行:

pnpm install
pnpm dev

会启动两个应用web(http://localhost:3000/)、docs(http://localhost:3001/)。
image.png
image.png
可以看到,两个应用都依赖了packages下的ui组件。

安装到已有项目中

按官方的说法,Turborepo可以安装到所有类型的应用中,不仅仅是multirepo,还有singlerepo。

安装turbo

官方建议是同时安装到全局和应用中

# Global install
pnpm add turbo --global
# Install in repository
pnpm add turbo --save-dev
新增一个turbo.json文件
# 示例应用中的json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

编辑.gitignore

+ .turbo

初始化仓库

下面以monorepo为例。
目录结构:
image.png

最低要求

包管理

官方推荐apps目录下存放应用,packages目录下存放公共库或者工具类。

packages:
  - "apps/*"
  - "packages/*"

monorepo用pnpm比较好,所以只贴了pnpm的例子,如果要看yarn的,可以看Structuring a repository | Turborepo
使用此配置,apps或packages目录中包含package.json的每个目录都将被视为一个包。

Turborepo不支持嵌套,例如apps/或者packages/
如果一定要嵌套,可以配置为packages/和packages/group/,然后不要创建packages/group/package.json文件

根目录package.json

示例:

{
  "private": true,
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint"
  },
  "devDependencies": {
    "turbo": "latest"
  },
  "packageManager": "pnpm@9.0.0"
}

packageManager不可少,否则报错。

根目录turbo.json

turbo.json用于配置turbo的行为。

lockfile

例如pnpm-lock.yaml,这是复用缓存的关键。

依赖管理

依赖分为外部依赖和内部依赖。

{
  "dependencies": {
    "next": "latest", // External dependency
    "@repo/ui": "workspace:*" // Internal dependency
  }
}

创建一个内部包示例

在packages中新建math目录,作为公共仓库。
image.png
创建package.json

{
  "name": "@repo/math",
  "type": "module",
  "scripts": {
    "dev": "tsc --watch",
    "build": "tsc"
  },
  "exports": {
    "./add": {
      "types": "./src/add.ts",
      "default": "./dist/add.js",
    },
    "./subtract": {
      "types": "./src/subtract.ts",
      "default": "./dist/subtract.js",
    },
  },
  "devDependencies": {
    "@repo/typescript-config": "workspace:*",
    "typescript": "latest"
  }
}

exports: 为包定义多个入口点,以便可以在其他包中使用。import { add } from '@repo/math'
Turborepo会将@repo/math识别为@repo/typescript-config的依赖项,用于对任务进行排序。
添加tsconfig.json,使用extends关键字继承公共配置:

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

在src中编写源码:
./packages/math/src/add.ts

export const add = (a: number, b: number) => a + b;

./packages/math/src/subtract.ts

export const subtract = (a: number, b: number) => a - b;

最后在应用中使用该库:
apps/web/package.json

"dependencies": {
+ "@repo/math": "workspace:*",
  "next": "latest",
  "react": "latest",
  "react-dom": "latest"
},

apps/web/src/app/page.tsx

import { add } from '@repo/math/add';

function Page() {
  return <div>{add(1, 2)}</div>;
}

export default Page;

turbo.json中添加编译缓存"dist/**",这样以后编译时就可以跳过math的编译:

{
"tasks": {
  "build": {
    "dependsOn": ["^build"],
    "outputs": [".next/**", "!.next/cache/**", "dist/**"]
  },
}

任务配置

定义tasks

tasks中每个key都是一个会被turbo run执行的任务。Turborepo会在每个package.json中查找同名脚本来执行。
例如一个最基础的task,不包含dependencies和outputs:

{
  "tasks": {
    "build": {} // Incorrect!
  }
}

使用该配置,turbo将不会使用缓存,导致每次构建时间都很长。

指定tasks顺序

dependsOn用于指定在另一个任务开始运行之前必须完成的任务。
假如你需要在应用编译前先执行公共仓库的构建,可以这样配置:

{
  "tasks": {
    "build": {
      "dependsOn": ["^build"] 
    }
  }
}

依赖^的任务

^告诉Turbo从依赖树的最底层开始构建。
假如你的应用依赖了一个仓库ui且这个ui有一个build脚本,那么这个build脚本会先执行。一旦这个uibuild任务执行完毕,应用的build就会立即执行。

依赖同一个package中的任务

假如在当前应用中,你想在执行test前先执行build任务,test需要定义dependsOnbuild。(没有^!)

{
  "tasks": {
    "test": {
      "dependsOn": ["build"] 
    }
  }
}

依赖特定包中的任务

有时你可能需要依赖特定包中的任务。
例如在所有lint任务执行前先执行util库中的build任务:

{
  "tasks": {
    "lint": {
      "dependsOn": ["utils#build"] 
    }
  }
}

还可以更具体地说明相关任务,将其限制为某个包:

{
  "tasks": {
    "web#lint": {
      "dependsOn": ["utils#build"] 
    }
  }
}

使用此配置,web包中的lint任务只能在utils包中的构建任务完成后运行。

无依赖

在这种情况下,可以省略dependsOn键或提供一个空数组。

{
  "tasks": {
    "spell-check": {
      "dependsOn": [] 
    }
  }
}

定义outputs

outputs告诉Turborepo在任务成功完成后应该缓存的文件和目录。如果不配,就不会使用缓存。

{
  "tasks": {
    "build": {
      "outputs": ["dist/**"] 
    }
  }
}

定义inputs

inputs用于指定要包含在任务哈希中以进行缓存的文件。默认情况下,Turborepo将包含Git跟踪的包中的所有文件。但是,您可以使用inputs键来更具体地确定哪些文件包含在散列中。
例如,在Markdown文件中查找拼写错误的任务可以这样定义:

{
  "tasks": {
    "spell-check": {
      "inputs": ["**/*.md", "**/*.mdx"] 
    }
  }
}

这样的话只有md文件的变更才会让turbo不使用缓存。

高级用例

有副作用的任务

有些任务无论如何都应该运行,比如在缓存构建之后运行部署脚本。可以使用"cache": false:

{
  "tasks": {
    "deploy": {
      "dependsOn": ["^build"],
      "cache": false
    },
    "build": {
      "outputs": ["dist/**"]
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值