Мурад поправил одну строчку в web, а проверки в CI снова собирают и тестируют всё подряд: shared, ui, api, web. Девять минут ожидания ради строчки, которая не затрагивает ни api, ни shared. Менеджер пакетов здесь не поможет: он ставит и связывает пакеты, но не помнит, что уже было сделано. Для этого существуют оркестраторы задач, и самый распространённый среди них — Turborepo. В этом уроке вы настроите его, поймёте граф задач и кеш и увидите, как из девяти минут получаются секунды.
Зачем нужен оркестратор задач
Команда pnpm -r run build уже идёт от зависимостей к зависимым, но у такого запуска три слабых места.
- Нет памяти. Исходники не менялись, а
buildвсё равно выполняется заново. - Всё или ничего. Нельзя сказать «проверь только то, что затронуто моим изменением».
- Результат не делится. Что собрал ваш компьютер, не получит ни коллега, ни CI.
Turborepo — быстрая программа на Rust, которая запускает скрипты из package.json по графу зависимостей, распараллеливает всё, что можно, и запоминает результаты. Он не заменяет pnpm: pnpm ставит зависимости и связывает пакеты, а Turborepo запускает задачи. Ставится он один раз, в корень рабочей области. Сведения о менеджере пакетов он берёт из поля packageManager корневого package.json:
pnpm add -D -w turbo
pnpm exec turbo --versionВ корневой package.json добавьте скрипты-обёртки, а папку .turbo внесите в .gitignore — там Turborepo хранит кеш и логи:
{
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"lint": "turbo run lint",
"check-types": "turbo run check-types"
},
"devDependencies": {
"turbo": "^2.11.0"
}
}💡 В pnpm 12 порядок задач можно описать и без Turborepo, настройкой
tasks, а кеш есть у экспериментальной командыpnpm pipeline. Turborepo остаётся самым распространённым выбором, с готовым удалённым кешем и богатым набором команд.
Два графа: пакетов и задач
Граф пакетов строится сам: если в apps/web/package.json записано "@repo/shared": "workspace:*", то web зависит от shared. Граф задач вы описываете в turbo.json: какая задача должна дождаться какой.
{
"$schema": "https://turborepo.dev/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env*"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**", "!.next/dev/**"]
},
"lint": {
"dependsOn": ["^lint"]
},
"check-types": {
"dependsOn": ["^check-types"]
},
"dev": {
"dependsOn": ["^build"],
"cache": false,
"persistent": true
}
}
}Каждая задача в tasks связана со скриптами с тем же именем в package.json пакетов. Главные ключи: