Why NextWhy Next
К списку
💻 Разработка3 мин чтения

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 кэширует результаты задач с неизменёнными входами и пересобирает только изменённые приложения.

Похожие статьи