От Монолита к Монорепо

С тех пор, как мы начали работать в Croud, одним из наших крупнейших проектов стал переход от большого монолита на основе PHP к более мелкой архитектуре, основанной на сервисах. Самая большая часть этого заключалась в том, чтобы переместить наш интерфейс с HTML-кода, сгенерированного PHP, на статические JS-ресурсы, управляемые API. Мы создали новый центральный сервер API Restful и начали заменять наш интерфейс на Vue SPA.

Обновление нашего Монолита

Поскольку компания требовала, чтобы сбои были как можно меньше, мы предпочли небольшие инкрементальные изменения и решили заменить только наш слой представления на наш SPA и продолжить размещение наших активов из нашего старого Monolith.

Наш старый сервер постепенно превратился в набор Vue 1 SPA, созданный одной задачей gulp. Это означало, что наши производственные сборки и сборки для разработчиков были очень ресурсоемкими и очень медленными. Кроме того, поскольку в нашем SPA используется множество общих зависимостей NPM, подключаемых модулей и служебных библиотек, обновление пакетов становится рискованным.

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

  • Новые проекты. Новые проекты, отделенные друг от друга, быстрее и проще для новых разработчиков.
  • Легко управлять: чем меньше времени мы тратим на управление репо, тем лучше
  • Совместное использование зависимостей. Наши проекты должны иметь возможность делиться своими зависимостями для обеспечения согласованности.
  • Гибкая зависимость: нам нужна возможность изолировать некоторые зависимости для каждого проекта, чтобы они случайно не повлияли на другие проекты.
  • Быстрая сборка. Чем короче цикл обратной связи, тем лучше

Оставляя наше наследие

Примерно в то же время, когда Vue выпустил 2.0, они также выпустили инструмент cli, который позволил нам создать собственный генератор, который быстро создавал бы Webpack SPA со вкусом Croud. Мы экспериментировали с хранением каждого SPA в собственном репо, вдали от унаследованного монолита.

Это обеспечивало большую гибкость зависимостей, а Webpack помог сузить петли обратной связи разработчиков. Но это также быстро привело к аду управления зависимостями и означало, что небольшие изменения в наших основных общих зависимостях потребовали часов тщательной перестройки.

Мы изучили такие инструменты, как Greenkeeper.io, чтобы помочь сохранить наши зависимости в действии, но мы обнаружили, что это шумно и потребовало бы от нас перенести наши репозитории из BitBucket, который в значительной степени не поддерживался этими инструментами.

Лерна Монорепо

Вдохновленный тем, как работают такие пакеты, как Babel и Jest, я начал экспериментировать с монорепозиториями. Монорепозиторий - это база кода, которая организована в единый репозиторий с несколькими пакетами. Lerna - это инструмент, который мы используем для построения и управления нашим монорепозиторием. Мы начали с того, что организовали наши пакеты вот так ...

| monorepo/
| ---- package.json
| ---- packages/
| -------- package-a/
| ------------ package.json
| -------- package-b/
| ------------ package.json
...

Корневой каталог нашего проекта package.json будет обрабатывать общие зависимости, а корневой каталог также будет содержать такие вещи, как конфигурации babel и eslint. В то время как каталог пакетов будет содержать каждый из наших SPA.

Инструменты Lerna

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

Каждый пакет по-прежнему имеет собственную индивидуальную сборку Webpack, поэтому его можно разрабатывать и строить в полной изоляции, как если бы они находились в отдельных репозиториях.

Пряжа Рабочие места

Наше монорепозиторий использует Рабочие области пряжи для обработки нескольких вложенных файлов package.json. Это дает нам единообразие и гибкость в управлении зависимостями, задавая основной набор зависимостей в родительском каталоге, но позволяет подкаталогам проекта переопределять эти значения по умолчанию и добавлять дополнительные зависимости по мере необходимости.

Lerna также может обрабатывать все ваши Пряжные ссылки, поэтому мы можем добавить ваши пакеты, размещенные на NPM, в монорепозиторий для локальной разработки.

Докер

Мы также включили файл конфигурации докера в наш монорепозиторий, который удаляет все, кроме каталога dist наших пакетов, и монтирует их в простой контейнер Nginx, готовый к интеграции в наши стеки Rancher.

Резюме

Lerna и Yarn Workspaces - мощная комбинация, которая позволила нам быстро развиваться и сократить накладные расходы на управление. Кажется, он ставит галочки во всех пунктах нашего мысленного контрольного списка и тоже хорошо масштабируется.