До свидания Лерна (вроде), привет Базель

Контекст

Как сопровождающий для formatjs & react-intl, я использую lerna для управления монорепозиторием, который включает в себя несколько задач:

  1. Управление установкой зависимостей npm
  2. Запускайте сценарии npm в топологически отсортированном порядке, например build или test
  3. Создавать новые выпуски GitHub
  4. Создать CHANGELOG
  5. Опубликовать в npm

Лерна довольно хорошо справляется со всеми этими 5 задачами, но с ростом монорепозитория и увеличением количества build времени, я полагаю, нам может понадобиться что-то, что лучше подходит для выборочной сборки. В своем сообщении в блоге я расскажу о своем решении отказаться от lerna в качестве системы сборки в пользу bazel.

Во-первых, результат

Теперь у нас есть рабочий процесс GitHub Action с кешем:

  • КИ: мы работаем на одном уровне со старой системой с большей точностью и воспроизводимостью (~ 14 минут).
  • Выборочная сборка (локальная): наш этап сборки увеличился с 9 минут до 50 - 10 минут (в зависимости от того, что изменилось).
  • Выборочный тест (локальный): наш этап сборки увеличился с 4 минут до 20 - 5 минут (в зависимости от того, что изменилось).
  • Намного меньше вопросов типа «работает на моем компьютере».

Наша настройка сборки

Наше монорепозиторий содержит 8 Intl polyfills ECMA402, каждый со своим собственным набором данных. Большая часть нашего build времени тратится на обработку CLDR и базы данных часовых поясов IANA. Этап предварительной обработки позволяет нашей реализации среды выполнения иметь высокую производительность при сохранении соответствия спецификации ECMA402.

Моя первая установка заключалась в обработке всего из источника, включая получение удаленных артефактов, таких как IANA. Это не масштабировалось. В холодной сборке GitHub Action CI наш build шаг может занять до 30 минут, а узкое место zdump занимает ~ 20 минут для всех часовых поясов IANA. Это делает DevEx чрезвычайно болезненным, поскольку небольшое изменение документа приведет к долгому ожиданию CI.

Моей второй попыткой было зафиксировать несколько сгенерированных артефактов вместе с поставкой в ​​базу данных IANA. Это не редкость при крупномасштабной CI-сборке. git имеет встроенную поддержку, позволяющую помечать их по-разному через .gitattributes, а GitHub также поддерживает через linguist-generated & linguist-vendored. Это значительно сокращает время нашей сборки примерно до 15 минут при холодной CI-сборке без «золотого» теста для проверки актуальности и детерминированности сгенерированных артефактов (для этого мы должны повторно запустить этап генерации, который по-прежнему занимает вечность. ).

Наша тестовая установка

Наша test установка вполне стандартна:

  • Модульный тест в jest
  • Тесты на селен в karma на платформе Sauce Labs
  • Тесты на соответствие Test262 в test262-harness

Удивительно, но нашим узким местом является не Selenium, а скорее test262, поскольку это довольно обширный набор тестов. Для тех, кто не знаком с test262, это набор тестов на соответствие TC39, который гарантирует, что любая реализация спецификации соответствует спецификации. Чтобы предотвратить загрязнение, он также запускает новый контекст v8 для каждого теста, делая его правильным, но медленным (время от времени у нас все равно время ожидания).

За исключением случайных тайм-аутов, наши тестовые часы показывают примерно 4 минуты.

Выборочная сборка

Выборочная сборка - это, по сути, возможность перестроить только часть измененной системы, тем самым повышая производительность. Обычно компромисс заключается в правильности из-за потенциальных проблем с кешированием и различий в настройке среды сборки. Сам Lerna не имеет большой (или, может быть, какой-либо) поддержки для этого, кроме флага --since. Здесь используется git ref в качестве механизма фильтрации того, что изменилось. Однако здесь есть несколько проблем:

  1. Единицей исполнения остается пакет.
  2. Транзитивные зависимости не принимаются. Это приводит к отсутствию сборки зависимостей, которые не позволяют выполнить сборку в целом. Включение тех, по сути, становится полной перестройкой.
  3. Проблемы с git псевдонимами, которые изменяют git выходные данные (как это было у одного из наших соавторов).

На высоком уровне есть проблемы как в базовом механизме обнаружения изменений (например, git), так и в степени детализации перестроения (пакет).

Поприветствуйте bazel, а именно rules_nodejs

Bazel - это герметичная система сборки, воспроизводимая, детерминированная и быстрая. В основе его лежат rule (как создавать вещи) и file (ну, файлы). Механизм системы сборки выражается во взаимосвязях между исходными файлами и сгенерированными файлами, выраженными в правилах. Bazel поддерживает свой собственный выходной каталог и не загрязняет дерево исходных текстов (если вы этого не укажете). Поскольку он герметичен, он может безопасно кэшировать выходные данные сборки и результаты тестирования, что позволяет мне выборочно восстанавливать и повторно тестировать только те части, которые изменились.

Еще один класс проблем, который решает bazel для максимальной воспроизводимости, что эффективно устраняет проблему «работает на моей машине». Мы настолько привыкли к обычному rm -rf node_modules && git clean -fd, а затем все переустанавливаем и пытаемся перезапустить, что это становится нормой. Эта проблема становится намного сложнее с OSS, где общение с сотрудниками затруднено.

Я не слышал о bazel до того, как присоединился к Dropbox, и, честно говоря, я не был его поклонником. У него довольно высокая кривая обучения, начиная от настраиваемого языка Starlark и заканчивая его философией и настройками. Он не очень хорошо взаимодействовал с существующей экосистемой веб-сборки, в первую очередь из-за неявных предположений о каталогах из существующих наборов инструментов сборки. Однако, как только я преодолел часть кривой обучения, результат был поразительным.

Заключительные слова

Давайте проясним: bazel не решает все существующие варианты использования. Если ваша сборка / тестирование выполняется достаточно быстро и вы знакомы с существующей цепочкой инструментов, нет причин переключаться. Если вы имеете дело с монорепозиторием с медленным циклом сборки / тестирования, это может значительно ускорить вас.

Наша текущая настройка завершена на https://github.com/formatjs/formatjs. Сообщество было очень полезным и активным, так что не стесняйтесь присоединяться к bazel’s Slack, если вам интересно.