Настройка Monorepo (Lerna) для веб-проекта

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Настройка Monorepo (Lerna) для веб-проекта
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Настройка Monorepo (Lerna) для веб-проекта

Lerna — один из первых инструментов для JavaScript monorepo. Долгое время был де-факто стандартом, потом потерял популярность, а с версии 6+ возродился под управлением Nrwl (создателей Nx) с интеграцией с Nx под капотом. Сегодня Lerna — хороший выбор для проектов, которым нужно управление версиями пакетов и публикация в npm, но не нужна сложная infrastructure Nx.

Когда Lerna, а не Turborepo или Nx

Lerna имеет смысл, когда:

  • Проект — библиотека или набор пакетов, которые публикуются в npm
  • Нужно автоматическое управление версиями (semver) и CHANGELOG
  • Команда небольшая, сложная инфраструктура избыточна

Для закрытого продукта без публикации в npm — лучше Turborepo или Nx.

Инициализация

# Новый monorepo
npx lerna init --packages="packages/*" --independent
cd my-monorepo

# Или добавить в существующий
npm install lerna --save-dev
npx lerna init

Флаг --independent означает, что каждый пакет версионируется независимо. Альтернатива — fixed mode, когда все пакеты имеют одну версию (как в React/Vue monorepo).

Конфигурация lerna.json

{
  "$schema": "node_modules/lerna/schemas/lerna-schema.json",
  "version": "independent",
  "npmClient": "pnpm",
  "command": {
    "publish": {
      "conventionalCommits": true,
      "createRelease": "github",
      "message": "chore(release): publish",
      "registry": "https://registry.npmjs.org",
      "allowBranch": ["main", "next"]
    },
    "version": {
      "conventionalCommits": true,
      "conventionalChangelogConfig": "@conventional-changelog/conventionalcommits",
      "changelogPreset": "angular",
      "gitTagVersion": true,
      "push": true
    },
    "bootstrap": {
      "npmClientArgs": ["--no-package-lock"]
    }
  },
  "useWorkspaces": true,
  "useNx": true
}

conventionalCommits: true — Lerna определяет тип версионирования по формату коммитов: fix: → patch, feat: → minor, BREAKING CHANGE → major.

Структура для библиотеки компонентов

my-ui-library/
├── packages/
│   ├── button/
│   │   ├── src/
│   │   │   ├── Button.tsx
│   │   │   └── index.ts
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── input/
│   ├── modal/
│   ├── table/
│   └── theme/
├── apps/
│   └── docs/              # Storybook или документационный сайт
├── package.json
├── lerna.json
└── pnpm-workspace.yaml
// packages/button/package.json
{
  "name": "@acme/button",
  "version": "1.2.0",
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
    "test": "vitest run",
    "typecheck": "tsc --noEmit"
  },
  "peerDependencies": {
    "react": ">=17.0.0"
  },
  "devDependencies": {
    "@acme/theme": "workspace:*",
    "tsup": "^8.0.0",
    "vitest": "^1.0.0"
  }
}

Управление версиями

# Определить, что изменилось (dry run)
npx lerna changed

# Обновить версии интерактивно
npx lerna version

# Автоматически по conventional commits
npx lerna version --conventional-commits --yes

# Версия с предрелизным тегом (для beta)
npx lerna version --conventional-commits --conventional-prerelease --preid=beta

При запуске lerna version происходит:

  1. Определяет изменившиеся пакеты
  2. Предлагает новые версии по semver правилам
  3. Обновляет package.json и зависимости между пакетами
  4. Генерирует CHANGELOG.md
  5. Создаёт git commit и теги

Публикация

# Публикация всех непубликованных пакетов
npx lerna publish from-package

# Публикация только изменившихся (после lerna version)
npx lerna publish from-git

# В private registry (Verdaccio, GitHub Packages, JFrog)
npx lerna publish from-git --registry=https://npm.pkg.github.com
# .github/workflows/release.yml
name: Release
on:
  push:
    branches: [main]

permissions:
  contents: write
  packages: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0       # нужно для conventional commits анализа
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: pnpm/action-setup@v3

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: 'https://registry.npmjs.org'

      - run: pnpm install --frozen-lockfile

      - name: Build all packages
        run: npx lerna run build

      - name: Version and publish
        run: |
          git config user.email "[email protected]"
          git config user.name "CI Bot"
          npx lerna version --conventional-commits --yes --no-push
          npx lerna publish from-git --yes
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Запуск задач с Nx под капотом

Lerna 6+ использует Nx для умного запуска задач:

# Запустить build для всех пакетов параллельно с кешем
npx lerna run build

# Только для изменившихся пакетов
npx lerna run test --since=main

# Для конкретного пакета и его зависимостей
npx lerna run build --scope=@acme/modal --include-dependents
// nx.json (создаётся автоматически при --useNx)
{
  "extends": "nx/presets/npm.json",
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "cache": true
    },
    "test": {
      "cache": true
    }
  }
}

Работа с зависимостями между пакетами

# Добавить зависимость в конкретный пакет
pnpm add react --filter @acme/button

# Добавить локальный пакет как зависимость
pnpm add @acme/theme --filter @acme/button --workspace

# Добавить devDependency во все пакеты
pnpm add -D typescript --recursive

Если пакет A зависит от пакета B внутри monorepo, и B изменился — lerna run build --scope=A --include-dependencies пересоберёт B перед A.

Типичные проблемы

Версия зависимости не обновляется при lerna version — проверьте, что зависимость указана без ^ или ~, иначе Lerna не сделает хардкодный апдейт. Флаг --force-publish обновит все пакеты принудительно.

CHANGELOG дублирует записи — Lerna по умолчанию добавляет только коммиты, затронувшие файлы данного пакета. Используйте --changelog-include-commits-root-path если нужны корневые коммиты.

Публикация падает на CI из-за npm publish --dry-run в .npmrc — убедитесь, что dry-run=false в CI окружении.

Сроки

Настройка Lerna для набора npm-пакетов с нуля — два-три дня: конфигурация, настройка конвенциональных коммитов (commitlint + husky), CI/CD для автоматической публикации, документирование процесса релиза для команды.