5 приложений в одном репозитории - Turborepo-монорепа соло-разработчика
Как устроить Turborepo-монорепу для нескольких приложений и сайтов в одном репозитории. Общие конфиги, экономия сборок через кэш и деплой по приложениям - с практической точки зрения.
Главное
Когда делаешь несколько приложений в одиночку, конфиги расползаются. В Turborepo-монорепе eslint и tsconfig выносятся в packages, кэш turbo не пересобирает неизменённые приложения, а --filter деплоит каждое приложение отдельно.
Содержание
Когда делаешь приложения в одиночку, репозитории плодятся как грибы. Одно приложение, один сайт, ещё одно приложение… и вот ты уже пять раз копипастишь конфиг eslint. Я собрал всё это в одну монорепу.
Настоящая проблема - расползшиеся конфиги
Когда репозиториев много, больнее всего не код, а конфиги.
- eslint, prettier и tsconfig копируются в каждый репозиторий
- Поменял одно правило - обходи и правь все по кругу
- Общий UI и утилиты слишком мелкие, чтобы публиковать в npm
Монорепа меняет это на общий доступ из одного места.
Базовая структура
apps/
├── web/ # 랜딩
├── blog/ # 이 블로그
├── wave/ # 오늘의 파도
└── ...
packages/
├── eslint-config/ # 공용 eslint
└── typescript-config/ # 공용 tsconfig
apps/* - это то, что реально деплоится, packages/* - конфиги и код, общие для приложений. tsconfig.json каждого приложения просто наследуется.
{ "extends": "@repo/typescript-config/nextjs.json" }
Теперь правила правятся только в одном месте - в packages.
Кэш turbo - главное оружие
Настоящая сила Turborepo - кэш. Если входы задачи (исходники, конфиги) не изменились, прошлый результат переиспользуется как есть.
turbo run build # 전체 빌드(바뀐 것만 실제로 돎)
turbo run build --filter=blog # blog 앱만
В turbo.json достаточно объявить зависимости между задачами и их выходы.
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": [".next/**"] }
}
}
Начиная со второй сборки всё заканчивается за пару секунд с надписью "FULL TURBO".
Деплой по приложениям
Репозиторий один, но деплой у каждого приложения свой. Для Docker командой turbo prune можно вырезать поддерево только нужного приложения и получить лёгкий образ.
turbo prune blog --docker # blog + 내부 의존성만 남긴 out/ 생성
Этот блог я вырезал именно так и поднял в Docker на мини-ПК. Об этом подробнее в статье про self-hosting.
Итоги
apps/*= деплоймент,packages/*= общие конфиги- tsconfig и eslint управляются из одного места через наследование
- Кэш
turboне пересобирает неизменённые приложения --filterиpruneдля деплоя по приложениям
Если вы в одиночку крутите несколько продуктов, монорепа - это не роскошь, а инструмент выживания.
Частые вопросы
Со скольких приложений монорепа начинает окупаться?
Уже с 2, как только появляются общие конфиги (eslint, tsconfig, UI). Суть в том, что конфиг правится в одном месте и применяется ко всем приложениям.
Не замедлится ли сборка?
Наоборот, ускорится. turbo кэширует результаты задач с неизменёнными входами и пересобирает только изменённые приложения.
Похожие статьи
- 💻 Разработка
MDX-блог на Next.js своими руками - как сделан этот блог
Как я собрал блог на Next.js 16 App Router, который работает на одних markdown-файлах, без CMS. Структура папок, настройка MDX и SEO на реальном коде.
- 💻 Разработка
Self-hosting на мини-ПК с Docker и Cloudflare Tunnel
Как безопасно опубликовать несколько веб-сервисов с одного домашнего мини-ПК. Без открытия портов: HTTPS через Cloudflare Tunnel, запуск через Docker Compose.
- ☕ Будни
Распорядок дня соло-разработчика - как не выгорать в одиночку
Работать одному, без начальника и коллег, свободно, но выматывает. Делюсь дневной рутиной и парой правил, которые помогают мне не терять ритм.