От монолита к монорепозиторию Nx

Теперь, когда у нас есть инструмент (CF Серия Monorepo, часть 3), давайте засучим рукава и приступим к затягиванию смазанных болтов и шестерен (т. е. к переносу нашего Monolith на архитектуру Monorepo на базе Nx).

Обзор этапов миграции

  1. Разделите кодовую базу на приложения
  2. Создайте рабочее пространство Monorepo
  3. Перенесите библиотеки
    а. Адаптируйте конфигурацию Monorepo
    b. Адаптировать конфигурацию Monolith
  4. Перенесите приложения и конфигурацию переключения: с Monolith на Monorepo
    a. Удалите команды Monolith (в нашем случае выполнение npm без обработки)
    b. Переключиться на команды Nx CLI
  5. Поднимите Monorepo на корневой уровень

Идея здесь состоит в том, чтобы разделить кодовую базу и реорганизовать ее по частям, одновременно адаптируя конфигурации инструментов.

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

Если вы этого не сделаете, вы можете оказаться в ловушке множества дублирующих функций и компромиссов ваших инструментов. Например, и tsconfig, и webpack позволяют обрабатывать пути и разрешение псевдонимов (изюминкой этого торта является то, что Jest также требует настройки для той же цели). Если вы ранее использовали webpack, вам следует перенести разрешение пути в tsconfig.

Действительно, Nx обрабатывает для нас всю путаницу webpack-tsconfig-jest через свои внутренние плагины. Таким образом, отдача от инвестиций высока и позволяет использовать единый источник правды, который может сэкономить вам МНОГО времени и усилий.

Давайте вместе шаг за шагом пройдем весь процесс миграции.

Этапы, шаг за шагом

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

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

  1. Разделите кодовую базу на приложения

В некоторых случаях вы также можете перенести библиотеки, которые уже используются в нескольких приложениях. Мы советуем ограничить процесс библиотеками, используемыми в качестве зависимостей в нескольких приложениях. Короче говоря, так проще. Мы подробно объясним причину позже (шаг 3).

На этом этапе разделение заявки означает:

  • изолировать код и предоставить единую точку входа (index.js|ts)
  • git mv (см. советы и рекомендации для получения более подробной информации) изолированный код в корне Монолита
  • создайте псевдоним пути в tsconfig для использования открытой точки входа
  • адаптировать пути импорта файлов, используя ранее созданный псевдоним

Сначала извлеките наиболее вложенные приложения и постепенно продвигайтесь вверх по цепочке. На приведенных выше диаграммах мы начинаем с App3 (но можно было бы начать и с App2) и извлекаем его. Поскольку существующие библиотеки (Библиотека 1 и 2) уже являются автономными в изолированных приложениях, мы пока не переносим их (количество псевдонимов, которые необходимо поддерживать/адаптировать, будет меньше).

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

Совет.

Если вы не хотите повторяться в конфигурационных файлах webpack и tsconfig, обратите внимание на этот плагин. Это может избавить вас от головной боли при проверке правильности числа ../.

2. Создайте рабочее пространство Monorepo

Затем создайте рабочее пространство монорепозитория на корневом уровне вашего монолита.

$> npx create-nx-workspace@latest

Просто следуйте инструкциям CLI, он выполнит всю тяжелую работу по настройке и сгенерирует рабочее пространство монорепозитория. У вас будет выбор из нескольких фреймворков, доступных из коробки (любезно предоставлено сообществом). Конечно, выбирайте наиболее подходящие фреймворки и библиотеки для своего случая использования.

В конце этого шага у вас должна быть новая папка, содержащая конфигурацию вашего монорепозитория (поле tooling на приведенной выше диаграмме) и базовую структуру fs (приложения/библиотеки и многоуровневые файлы конфигурации).

3. Перенесите библиотеки

Теперь, когда у нас есть рабочая область, мы изолируем и переносим библиотеки, следуя той же методологии, что и на шаге 1, с несколькими дополнительными шагами.

На этот раз специфика заключается в том, что одновременно будут использоваться конфигурации и Монолита, и Монорепо.

  • tsconfig Monolith должен содержать новый псевдоним пути, указывающий на библиотеку
  • Конфигурация tsconfig монорепозитория должна предоставлять точку входа в библиотеку в своей папке src.

Итак, если подытожить:

  • изолировать код библиотеки и предоставить единую точку входа (index.js|ts)
  • создайте библиотеку с помощью Nx CLI
    -
    nx g @nrwl/[plugin]:lib [libName]
    — она автоматически создаст псевдоним tsconfig Monorepo
  • git mv (см. советы и рекомендации для получения дополнительной информации) изолированный код в папке src библиотеки Monorepo.
  • найдите зависимости библиотеки от Monolith и добавьте их в пакет Monorepo package.json (могут потребоваться обновления)
  • создайте псевдоним пути в tsconfig Monolith для использования открытой точки входа
  • адаптируйте файлы пути импорта, используя ранее созданный псевдоним
  • 🔁 повторить для каждой библиотеки (по одному PR за раз, чтобы избежать конфликтов с работой других команд)

Вы должны получить все свои библиотеки в папке Monorepo, которые все еще используются приложениями через конфигурацию Monolith.

Как и в шаге 2, ваши приложения все еще должны собираться, а тесты должны проходить с использованием конфигурации Monolith. Но на этот раз тесты (и сборка сборных библиотек) также должны проходить в монорепозитории (nx run-many --all --target=test).

4. Перенесите приложения и конфигурацию коммутатора: с Monolith на Monorepo.

Устали от перемещения вещей? Потерпите меня, мы почти закончили! 💪

Нам все еще нужно перенести наши приложения. Это будет более или менее тот же процесс, что и на шаге 3, с парой изменений:

  • изолировать код приложения и предоставить единую точку входа (index.js|ts)
  • [улучшено] создать приложение через Nx CLI
    npx nx g @nrwl/[plugin]:app [applicationName]
    — оно автоматически создаст псевдоним tsconfig Monorepo
  • git mv (см. советы и рекомендации для получения дополнительной информации) изолированный код в папке src приложения Monorepo.
  • найдите зависимости приложений от Monolith и переместите их в Monorepo package.json (могут потребоваться обновления)
  • [улучшено] создать псевдоним пути в tsconfig Monolith для использования открытой точки входа (псевдоним должен соответствовать тому, который используется в конфигурации Monorepo)
  • адаптируйте файлы пути импорта, используя ранее созданный псевдоним
  • 🔁 повторить для каждого приложения (по одному PR за раз, чтобы избежать конфликтов с работой других команд)

5. Поднимите Monorepo на корневой уровень

Теперь наш монорепозиторий запущен и работает, давайте просто очистим корневую папку, удалив устаревшие файлы конфигурации (tsconfig, webpack.config, jest.config|setup, eslintrc и т. д.). И, наконец, поднимите содержимое нашей папки Monorepo на корневой уровень.

И, вуаля 🎉🥳

Хитрости и советы

  • Миграция выполняется в то время, когда другие команды работают над той же кодовой базой
    – Используйте git mv
    – Это позволяет плавно интегрировать изменения команд, выполняемые параллельно
    – Не полагайтесь слишком сильно на трюке git move и разделите ваши изменения на несколько промежуточных PR (один на lib-app, иначе git rebases будет неуправляемым из-за конфликтов, порожденных изменениями других команд)
  • Трудно найти правильный баланс между различными инструментами и перекрывающимися функциями
    - Псевдоним [webpack.config / tsconfig / jest.config]
    - Потратьте время, чтобы понять возможности ваших инструментов
  • Возможно, вам потребуется понизить версию пакета Nx core или plugin (например: @nrwl/react в зависимости от уровня совместимости вашего кода Monolith)
  • Некоторые из ваших зависимых пакетов могут потребовать некоторых обновлений (Nx использует Webpack 5) или откатов (например, TypeScript, React…)
  • Ваша версия Node может потребовать обновления
  • Проблема с переменной среды
    — Nx требует, чтобы переменные среды имели префикс NX_ для внедрения в process.env ваших приложений (все переменные среды без префикса NX_ будут отфильтрованы)
    — Подробнее об этом читайте здесь является рациональным
  • Если делать все правильно, можно выявить скрытые проблемы
     — CSS-модули и глобальный CSS
     — Обнаружили ли вы какие-либо проблемы на своей стороне?

Выводы

В этом посте мы шаг за шагом проследили основные этапы миграции монолитного репозитория с несколькими приложениями в монорепозиторий.

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

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

Увидимся в последнем посте этой серии, в котором будут показаны улучшения и возможности, предоставляемые Monorepo.