Как стать автором
Обновить

NPM монорепозиторий (Lerna + автодеплой GitHub Actions)

Время на прочтение5 мин
Количество просмотров11K

Привет! Мы GrandCore Foundation. Создаём идеальную организацию для развития свободных проектов: ПО, этичных онлайн-сервисов и стандартов изделий. Подробнее читайте здесь. Присоединяйтесь к нашему чату в Telegram. Всегда рады единомышленникам!

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

Что такое монорепозиторий

Монорепозиторий — это совокупность множества проектов в одном репозитории.

Преимущества:

  • Нет необходимости поддерживать огромное количество репозиториев отдельно;

  • Возможность отслеживания и редактирования кода во всем проекте каждой отдельной командной;

  • Атомарные коммиты.

Проблемы:

  • Увеличение объема данных;

  • Возможная проблема с версионированием каждого подпроекта;

  • Уменьшение ответственности каждой команды, которая работает над подпроектами репозитория.

Lerna

В качестве основного инструмента работы с монорепозиторием в NPM необходимо рассматривать Lerna. Она является достаточно удобным инструментом для работы над монорепозиториями. Lerna позволяет решить множество возникающих при работе проблем.

Возможности:

  • Сквозное версионирование;

  • Индивидуальное версионирование каждого подпроекта;

  • Удобная публикация всех подпроектов;

  • Автоматическое управление зависимостями между подпроектами;

  • Работа с Yarn или NPM.

Создание монорепозитория

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

Установите Lerna глобально:

npm i lerna -g 

Инициализируйте проект:

lerna init

После этого в корне проекта создаестся директория packages/, файл package.json и файл lerna.json.

Содержимое lerna.json:

{
  "packages": [
    "packages/*"
  ],
  "version": "0.0.0"
}

Сначала указывается директория со всеми вложенными проектами (директорий может быть несколько). Далее указывается версия монорепозитория (для сквозного версионирования данное значение совпадает во всех подпроектах).

Cоздание нового пакета (подпроекта):

lerna create <name-pkg>

После ввода данной команды в директории packges/ (по умолчанию) создается новый каталог с именем, которое указывается в качестве параметра. Далее необходимо ответить на несколько стандартных вопросов от Lerna. Важно отметить, что для всех пакетов желательно использовать названия следующего типа @project_name/pkg_name. Таким образом можно привязать все пакеты, которые разрабатываются внутри репозитория, к одному монорепозиторию или одной организации.

Допустим, что мы создали новый пакет. Тогда в директории с этим пакетом создается файл package.json. Чтобы данный пакет в дальнейшем был доступен публично и корректно публиковался, необходимо добавить в данный файл:

"publishConfig": {
    "access": "public"
  }

Естественно, подпроекты можно создавать и вручную.

Публикация изменённых проектов:

lerna publish

Возможные проблемы:

  • Не авторизованы в NPM;

  • Забыли добавить публичный доступ в package.json пакета;

  • Занятое или некорректное название одного из пакетов.

Важные замечания:

  • Публикация возможна только после коммита при использовании данной команды в таком виде;

  • По умолчанию задается сквозная версия для всех пакетов.

Рекомендуем почитать в документации Lerna о дополнительных параметрах данной команды.

В нашем проекте

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

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

Наш файл lerna.json:

{
  "packages": ["plugins/*", "main/"],
  "version": "0.0.0",
  "command": {
    "run": {
      "npmClient": "npm"
    }
  }
}

В нашем проекте все плагины находятся в каталоге plugins/, а основной модуль в папке main/. Таким образом структура нашего проекта представляет из себя следующий вид:

├── lerna.json
├── LICENSE
├── main
│   ├── index.js
│   ├── lib
│   │   ├── finMd.js
│   │   └── manager.js
│   ├── package.json
│   └── README.md
├── package.json
├── plugins
│   ├── fin-html
│   │   ├── index.js
│   │   ├── package.json
│   │   └── README.md
│   └── gen-js-jsdoc
│       ├── index.js
│       ├── package.json
│       └── Readme.md
│       ...
└── README.md

Взаимодействие модулей и зависимости

Поговорим теперь о взаимодействиях между разными частями проекта. Очевидно, что в монорепозитории каждый подпроект может как-то зависеть от других. Возникает проблема зависимостей между подпроектами. Кроме того, не очень удобно устанавливать зависимости отдельно для каждого подпроекта. Lerna умеет решать данные проблемы.

Установка зависимостей:

lerna bootstrap

При выполнении данной команды Lerna анализирует все подпроекты и выполняет npm install в каждом из них. Если в зависимостях одного локального модуля (подпроекта) B находится другой A, то Lerna создает символическую ссылку в папке node_modules/ подпроекта B на подпроект A. Таким образом не происходит лишних копирований файлов в node_modules/. Работая с монорепозитоием, мы должны выполнять данную команду вместо установки зависимостей в каждом подпроекте.

Рекомендуем почитать в документации Lerna о дополнительных параметрах данной команды.

Автодеплой с помощью GitHub Actions

Мы создали монорепозиторий, даже смогли опубликовать его в NPM, но теперь возникает вопрос: "Как можно автоматически отправлять изменения в NPM?". Для решения такой задачи можно использовать GitHub Actions.

Создадим в корне проекта папку .github/workflows/, а в ней файл main.yml (название может быть любое). Рассмотрим на нашем примере.

Содержание нашего yml файла:

name: autodeploy

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  default:
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2

      - name: Install Packages
        run: npm install

      - name: Authenticate
        run: |
          echo "@grandcore:registry=https://registry.npmjs.org/" > .npmrc
          echo "registry=https://registry.npmjs.org/" >> .npmrc
          echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc
        env:
          NPM_TOKEN: ${{ secrets.NPMTOKEN }}

      - name: Publish
        lerna publish from-package --yes --no-verify-access
        env:
          NPM_TOKEN: ${{ secrets.NPMTOKEN }}

Что тут происходит:

  • В качестве тригера запуска установлен коммит или пулл реквест в мастер;

  • Операционной системой выбирается Ubuntu;

  • Далее в склонированном репозитории выполняется установка npm-пакетов;

  • После этого добавляем пользователя NPM. Для этого необхдоимо создать секрет в проекте с npm-токеном. В нашем проекте токен содержится в секрете NPMTOKEN.

  • Выполняем публикацию с помощью соответствующей команды lerna publish from-package --yes. В нашем случае, мы обновляем только те пакеты, которым мы поменяли вручную версию в их файлах package.json.

  • Отслеживать ход выполнения можно во вкладке Actions в вашем репозитории.


Будем рады выслушать ваши замечания в комментариях.

Если читателя заинтересуют наши Open Source проекты, будем рады видеть в нашем чате.

Теги:
Хабы:
+4
Комментарии16

Публикации

Изменить настройки темы

Истории

Работа

DevOps инженер
46 вакансий
React разработчик
61 вакансия

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн