Монорепозиторий — удобный формат для команды, которая развивает несколько пакетов одновременно. Lerna помогает связать эти пакеты, упростить установку зависимостей и автоматизировать релизы. В статье разберу, что делает Lerna полезным инструментом, как правильно его настроить и какие подводные камни стоит предусмотреть.

Кратко о том, зачем нужен Lerna

Lerna обеспечивает управление набором пакетов внутри одного репозитория. Он облегчает запуск скриптов по всем пакетам, оптимизирует установку общих зависимостей и помогает управлять версиями при публикации.

Главная идея — избежать дублирования и упростить рабочий цикл: вы можете менять несколько пакетов в одном коммите, запускать тесты централизованно и публиковать только то, что действительно изменилось.

Основные возможности

Lerna содержит набор команд, которые решают типовые задачи монорепозитория. Среди них bootstrap для связывания локальных пакетов, run для выполнения скриптов и publish для автоматического повышения версий и публикации в npm.

Отдельная опция — hoist, она поднимает общие зависимости в корень репозитория. Это экономит дисковое пространство и ускоряет установку, но требует внимания к совместимости версий.

  • bootstrap — связывает локальные зависимости и устанавливает внешние;
  • run / exec — запускает команды во множестве пакетов;
  • publish — автоматизирует версионирование и публикацию;
  • changed — определяет пакеты, затронутые последними коммитами.

Когда Lerna — хороший выбор

Если у вас несколько связанных пакетов и вы хотите управлять ими централизованно, Lerna часто оказывается проще, чем полностью ручной подход. Особенно это касается библиотек и SDK, где пакеты тесно связаны между собой.

При малом и среднем числе пакетов Lerna позволяет быстро организовать рабочий процесс и обеспечить единообразие скриптов. Однако при очень большом количестве пакетов появляются преимущества инструментов с продвинутым кэшированием сборок.

Кому стоит посмотреть в сторону альтернатив

Если критичны быстрые инкрементальные сборки и сложные зависимости между проектами, имеет смысл рассмотреть Nx или Turborepo. Эти системы содержат встроенное кэширование и граф задач, что экономит время CI.

Также в экосистеме развиваются workspace-подходы менеджеров пакетов — Yarn и pnpm — они отлично работают совместно с Lerna или сами по себе решают часть задач по управлению зависимостями.

Небольшая сравнительная таблица

Инструмент Управление зависимостями Кэш сборок Лучше для
Lerna Работает с npm/Yarn/pnpm; поддерживает hoist Нет встроенного Управление пакетами и релизами
Yarn Workspaces Интегрированное, простая конфигурация Нет Упрощённая установка зависимостей
pnpm Workspaces Эффективное хранение пакетов, жёсткая изоляция Частично через кеш менеджера Проекты с большим количеством пакетов
Nx / Turborepo Работают с workspaces Да, продвинутое Большие монорепозитории с CI-оптимизацией

Установка и базовая настройка

Начать просто: в корне репозитория создайте package.json и выполните инициализацию Lerna. Можно установить Lerna глобально или как dev-зависимость — выбирайте подход, удобный команде.

Типичный набор шагов выглядит так: инициализация npm, установка Lerna, создание папки packages и запуск lerna init. В lerna.json укажите npmClient и режим версии — фиксированную или независимую.

  1. npm init -y
  2. npm i -D lerna
  3. npx lerna init
  4. создайте структуру packages/* с package.json в каждом пакете

Пример минимального lerna.json:

{
  "packages": ["packages/*"],
  "version": "independent",
  "npmClient": "pnpm"
}

Практический пример структуры

Обычная структура монорепозитория выглядит предельно ясно: корень с конфигами и папка packages, в которой лежат отдельные модули. Каждый модуль — это полноценный npm-пакет со своим package.json.

  • /package.json — общие скрипты и dev-зависимости;
  • /lerna.json — конфигурация Lerna;
  • /packages/ui — компонентная библиотека;
  • /packages/core — бизнес-логика;
  • /packages/app — приложение, собираемое из внутренних пакетов.

Такое расположение упрощает локальное тестирование: при изменении core и сборке app Lerna автоматически свяжет локальные версии вместо загрузки из npm.

Советы по настройке зависимостей и hoisting

Hoisting экономит место и ускоряет npm install, но поднимает риск конфликтов версий. Если пакеты требуют разных версий одной библиотеки, hoist может ломать резолвинг модулей.

Практика показывает: включайте hoist для проектов со стабильной зависимостью, а в сложных случаях комбинируйте его с workspaces менеджера пакетов и точной фиксацией версий.

Автоматизация версий и публикаций

Lerna умеет вычислять, какие пакеты изменились, и повышать версии только для них. Это экономит время и уменьшает число публикаций.

Для управления процессом релизов удобно использовать схему conventional commits. Она даёт предсказуемые changelog и позволяет автоматизировать шаги в CI.

Типичные ошибки и как их избежать

Частая ошибка — смешение подходов: попытки полностью довериться Lerna для всех задач, не учитывая преимущества workspaces и кэша. Это ведёт к неэффективным сборкам и запутанным конфликтам зависимостей.

Другой источник проблем — неконсистентные версии зависимостей в пакетах. Рекомендую централизовать версии для ключевых библиотек и проверять их скриптами.

Опыт из практики

В одном из проектов мы использовали Lerna вместе с pnpm workspaces. Сначала всё шло гладко: разработчики могли одновременно работать над библиотеками и приложением. Публикации сократились, потому что Lerna публиковала только пакет с изменениями.

Проблемы возникли, когда начали экспериментировать с hoist: пара пакетов требовала разных minor-версий одной библиотеки, и разрешение импортов ломалось на CI. Решение — ограничить hoisting или унифицировать версии.

Переход на современные инструменты и интеграция с CI

Если проект растёт, имеет смысл добавить систему кэширования сборок и граф задач. Nx и Turborepo интегрируются с workspaces и дают выигрыш по времени в CI. Lerna при этом остаётся полезным для управления пакетами и публикаций.

В CI настройте кэш node_modules и кэш сборки. Также используйте команды вроде lerna changed, чтобы запускать тесты и сборки только для затронутых пакетов — это экономит ресурсы и ускоряет конвейер.

Когда мигрировать с Lerna

Если чашка сборок и трафик CI выросли до точки, где сборки занимают большую часть времени, подумайте о миграции. Lerna по-прежнему хорош для релизов, но тушение времени билда решают другие инструменты.

Миграция обычно включает перенос управления зависимостями в workspaces выбранного менеджера, добавление кэша задач и постепенное внедрение графа зависимостей. Делать это осторожно — пакет за пакетом.

Краткий чеклист перед внедрением

Перед тем как заводить Lerna в проект, проверьте несколько ключевых пунктов. Это поможет избежать типичных ошибок и сделает интеграцию предсказуемой.

  • Определите число и тип пакетов — библиотеки или приложения;
  • Решите стратегию версии: фиксированная или независимая;
  • Выберите менеджер пакетов и подумайте о workspaces;
  • Настройте CI с кэшем и ограничением областей сборки;
  • Документируйте скрипты и порядок релизов для команды.

Lerna остаётся практичным инструментом для тех, кто ценит простоту управления пакетами и автоматизацию выпуска. При разумной конфигурации он экономит время разработчиков и уменьшает количество рутины вокруг версий. Важно учитывать масштаб проекта и сочетать Lerna с workspaces и инструментами кэширования там, где это даёт реальную выгоду.