Монорепозитарии на примерах с использованием Lerna. Часть 1

Spread the love

Определения монорепозитария могут быть разными, но мы будем считать репозитарий как моно если выполняются следующие условия :

  • Репозиторий содержит более одного логического проекта (например, клиент iOS и веб-приложение)
  • Эти проекты, скорее всего, не связаны между собой или слабо связаны другими способами (например, с помощью инструментов управления зависимостями)
  • Эти проекты, скорее всего, не связаны между собой или слабо связаны другими способами (например, с помощью инструментов управления зависимостями)

Так же еще нужно учесть что рост каждого репозитория по отдельности обусловлен следующими параметрами:

  • Количеством коммитов
  • Количество веток и / или тегов
  • Количество отслеженных файлов
  • Размер отслеживаемого содержимого (измеряется путем замером каталога .git).

Вместо то что бы высказываться за или против использования монорепозитарий я планирую в этой статье исследовать несколько практических вопросов использования их. В частности для управления проектов, я планирую использовать инструмент Lerna на примере тестового проекта monorepo (проект будет на JavaScript).

Финальная версия проекта monorepo доступна по  ссылке.

Введение

Прежде чем мы перейдем к созданию проекта, на нужно установить Lerna. Хорошая новость в том, что это очень просто.

Установите Lerna глобально командой:

sudo npm install --global lerna

примечание: это статься написана с использованием Node.js v8.9.4 и Lerna v2.9.0.

Создайте новую папку и в ней запустите следующие команды для инициализации Lerna.

git init
lerna init

В результате должна появиться следующая структура файлов:

Создание Packages

Теперь, когда у нас есть проект monorepo c Lerna, мы можем начать создавать пакеты. В контексте развертывания в npm Registry пакетами будут отдельные пакеты npm. То есть каждый пакет npm по сути будет отдельный проект. Так же пакеты будут иметь слабую связь между собой и независимое управление зависимостями (подробнее об этом позже).

Мы создаем отдельные проекты, создавая папки в директории packages, например, apple, banana и grocery, и запустим следующую команду в каждой из них:

npm init -y

Теперь структура папок у нас будет такая:

Сторонние зависимости

Допустим что нам нужно что бы все три проекта зависили бы от npm пакета sillyname@0.0.3 (с определенной версией); для этого нам нужно запустить команду (команды Lerna могут быть запущены в любой папке проекта):

lerna add sillyname@0.0.3

Теперь у нас будет такая структура папок:

В результате:

  • Так как нам нужно что бы наши пакеты (проекты) были независимы друг от друга, у каждого пакета будет свой  package.json (с зависимостью sillyname).
  • В каждой папке будет сгенерированный новый package-lock.json
  • С Lerna, мы можем добавить зависимости в несколько пакетов с помощью одной команды.

В итоге в каждом пакете своя копия пакета sillyname; что не очень хорошо с точки зрения потребления дискового пространства и более медленной процедуры инсталляции. Для решения этих проблем можно вручную обновить каждый package.json и установить пакет sillyname только один раз в родительскую папку node_modules ( Node.js будет искать пакеты в родительских папках). Но это достаточно утомительно.

У Lerna есть другое решение; опция hoist:

lerna add sillyname@0.0.3 --hoist

В результате структура папок будет такой (на скриншете не показа родительская папка node_modules):

В итоге мы получим:

  • В каждом package.json есть зависимость от sillyname.
  • Пакет sillyname инсталлирован в корневой папке node_modules .

Выборочное обновление

Допустим нам нужно обновить версию sillyname только для проекта grocery; для этого нам нужно запустить команду:

lerna add sillyname@0.1.0 –scope=grocery

В результате получим такую структуру папок (на скриншете не отображена корневая папка node_modules):

В итоге:

  • Файл package.json из проекта grocery обновлен и туда включена зависимость sillyname v0.1.0
  • В папке grocery появилась папка node_modules с новой версией  sillyname.

Внутренние зависимости

Сейчас допустим что нам надо что бы пакет grocery зависил от пакетов apple и banana. Для запустим команду:

lerna add apple banana --scope=grocery

Теперь у нас будет такая структура папок:

Как результат:

  • Файл  package.json проекта grocery обновлен и в нем указаны зависимости от пакетов  apple и banana.
  • Lerna сама создала линки в папке node_modules проекта grocery.

Код

Теперь когда у нас установлены все зависимости мы можем написать какой нибудь код.

packages/apple/index.js

const sillyname = require('sillyname');
module.exports = `apple and ${sillyname()}`;

packages/banana/index.js

const sillyname = require('sillyname');
module.exports = `banana and ${sillyname()}`;

packages/apple/grocery.js

const sillyname = require('sillyname');
const apple = require('apple');
const banana = require('banana');
console.log(`grocery and ${sillyname()}`);
console.log(apple);
console.log(banana);

Далее выполним следующую команды из папки пакета grocery:

node index.js

Мы должны получить что-то вроде этого:

grocery and Linenhiss Butterfly
apple and Trailspeaker Scribe
banana and Translucentpuma Kangaroo

Закончив с кодирование, внесем изменения в .gitignore, так как нам не нужно хранить папку node_modules в системе контроля версий.

**/node_modules

Затем добавьте файлы в коммит и отправим проект в удаленный репозиторий.

Запуск (Bootstrap)

Теперь предположим, что другой член команды захочет работать над проектом. Сначала ему нужно глобально устанавливить Lerna.

sudo npm install --global lerna

Затем ему нужно клонировать репозиторий и из корневой папки проекта запустить следующую команду, чтобы установить все зависимости (включая символические ссылки).

lerna bootstrap --hoist

Все этого достаточно что бы приступить к работе над кодом.

Следующая статья: Монорепозитарии на примерах с использованием Lerna. Часть 2

Оригинал статьи: Monorepos By Example: Part 1


Spread the love