Управление проектом Monorepo с помощью Turborepo
1. Почему стоит выбрать Monorepo?
Monorepo, или единый репозиторий кода, — это стратегия хранения нескольких независимых проектов или пакетов в одном репозитории. По сравнению с моделью Polyrepo, где у каждого проекта отдельный репозиторий, Monorepo дает несколько заметных преимуществ:
- Совместное использование кода: Обмен компонентами, вспомогательными функциями и определениями типов между разными проектами становится очень простым.
- Атомарные коммиты: Если изменение одной функции затрагивает несколько пакетов, его можно выполнить одним коммитом, обеспечив согласованность версий.
- Упрощенное управление зависимостями: Все проекты используют общий
node_modulesили оптимизируют его через workspace pnpm/yarn, что уменьшает конфликты зависимостей и расхождения версий.
Однако по мере роста репозитория Monorepo приносит и новую проблему: производительность сборки.
2. Проблемы Monorepo
Представьте, что в репозитории есть docs, webapp и общая библиотека UI-компонентов ui. Если вы исправили только одну опечатку в docs, меньше всего хочется, чтобы все проекты репозитория, включая webapp и ui, заново собирались и тестировались.
Традиционным инструментам управления Monorepo, таким как Lerna, не хватает возможностей оркестрации задач и кеширования сборки, что приводит к следующим проблемам:
- Повторная работа: При каждом запуске CI/CD все собирается и тестируется с нуля, даже если большая часть кода не изменилась.
- Долгая сборка: Невозможно эффективно использовать несколько ядер CPU для параллельного выполнения задач.
- Сложные скрипты: Для ручного управления порядком выполнения задач приходится писать сложные скрипты
package.json.
3. Turborepo: создан для скорости
Turborepo — высокопроизводительная система сборки для Monorepo на JavaScript/TypeScript, позднее приобретенная Vercel. Она решает описанные проблемы с помощью двух ключевых технологий: инкрементальной сборки и удаленного кеширования.
a. Инкрементальная сборка и конвейеры задач
Turborepo позволяет определять зависимости между задачами в файле turbo.json в корне проекта.
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": []
},
"lint": {
"outputs": []
},
"dev": {
"cache": false
}
}
}dependsOn: ["^build"]: Символ^означает, что задачаbuildпакета зависит от задачbuildвсех пакетов, от которых он зависит. Turborepo выполняет задачи в наиболее эффективном параллельном порядке на основе этого графа.outputs: Сообщает Turborepo, какие выходные файлы создает задача.
При запуске pnpm turbo build Turborepo вычисляет, какие файлы изменились, и заново собирает только затронутые пакеты. Если исходный код и зависимости пакета не изменились, Turborepo напрямую использует результат предыдущей сборки, что происходит мгновенно.
b. Удаленное кеширование
Это «главная особенность» Turborepo. Система не только кеширует результаты сборки на локальном компьютере, но и может загружать кеш на общий удаленный сервер, например Vercel или в собственный бакет S3.
Это означает:
- Ваш коллега, получив свежий код, может напрямую скачать кеш, если вы уже собрали нужную ему часть, и не выполнять локальную сборку заново.
- Сервер CI/CD также может подключаться к этому удаленному кешу. После сборки и кеширования PR в CI другие разработчики и последующие задачи CI смогут немедленно использовать результат.
Это способно сократить время сборки для всей команды с десятков минут до нескольких минут или даже десятков секунд.
Заключение
Turborepo не изобрел Monorepo, но благодаря передовым системам кеширования и планирования задач значительно улучшил разработку в Monorepo и устранил его главный узкий момент производительности. Если вы используете или планируете внедрить архитектуру Monorepo, Turborepo — мощный инструмент, способный сэкономить вам и вашей команде много времени.