Привет! Меня зовут Даниил, я фронтенд-разработчик в Тинькофф Бизнесе. Мы строим удобные интерфейсы, чтобы клиенты могли быстро зарегистрировать бизнес. Сегодня я хочу рассказать, почему мы используем Nx для всех наших Angular-проектов, какие проблемы решает этот инструмент и чем он лучше Angular CLI. Nx — мощная система сборки, которая позволяет работать с монорепозиториями и предлагает разнообразные инструменты и библиотеки. Важно отметить, что многие разработчики используют Nx не из-за поддержки монорепозиториев, а из-за фич. Например, из-за настроенных из коробки инструментов. Больше о том, как использовать Nx, можно узнать на сайте. А мы рассмотрим следующие фичи, сравнив Angular CLI и Nx: Управление монорепозиториями. Инструменты из коробки. Кэширование артефактов. Миграция на новые версии технологий. Зачем вообще использовать монорепозитории и какие проблемы они решают? Об этом написано множество статей, но если вкратце, причин несколько: Переиспользование общих модулей и компонентов. Использование общих зависимостей одинаковых версий. Использование общих инструментов: тестирование, линтинг. Упрощение интеграций между проектами. Angular CLI. Не предлагает специального подхода для работы в монорепозиториях. Теоретически можно хранить все приложения в Projects. Для небольших проектов этого может быть достаточно, но при масштабировании могут возникнуть проблемы. Nx. Nx ориентирован на монорепозитории, поэтому есть ряд инструментов из коробки для удобной работы с ними: — Project Boundaries. Если проект находится в монорепозитории, не исключено, что один проект может импортировать части другого. Неявные зависимости между проектами ведут к огромному количеству проблем, включая нарушение SRP, высокий coupling, сложности с масштабированием и безопасностью. Для решения этой проблемы Nx предлагает правило ESLint. Оно позволяет контролировать доступ между проектами, определять явные границы между ними и обеспечивать соблюдение этих границ. Подробности можно узнать на сайте.  — Граф зависимостей. Nx также предлагает инструмент для визуализации всех зависимостей между проектами и оценки их влияния друг на друга. Граф позволяет лучше понимать структуру кодовой базы, выявлять проблемы с неявными зависимостями и обнаруживать циклические зависимости. Пример графа можно посмотреть на сайте проекта. Каждый новый проект сопровождается выбором и настройкой типовых инструментов для юнит-тестирования, интеграционного тестирования, линтинга и других. Интеграция инструмента с фреймворком — нетривиальная задача, и иногда разработчики тратят на нее много времени. Давайте разберем, какие инструменты предлагает Angular CLI, а какие — Nx. Angular CLI. Сейчас при генерации проекта с помощью Angular CLI мы получаем только приложение. Юнит-тестирование предполагает использование Jasmine & Karma, но, начиная с последних версий, там нет конфигурации, а еще совсем недавно Karma стала deprecated.  Что касается интеграционного тестирования и линтинга, то Protractor и TSLint тоже deprecated, поэтому в CLI их нет. Других альтернатив из коробки Angular CLI не предлагает. Скорее всего, вы захотите как минимум использовать ESLint. Тогда придется найти инструмент и разобраться, что такое Angular ESlint и как его завести. Это легко, но не хочется сталкиваться с проблемой уже на этапе генерации проекта.  Если вы решите писать юнит-тесты, придется затащить конфигурацию. А если захочется переехать с Jasmine & Karma на Jest, придется разобраться, как подружить Angular и Jest. С интеграционным тестированием чуть проще, но и в этом случае нужно будет понять, как подключить инструмент и завести его с нуля. Nx. В Nx есть набор генераторов, которые позволяют генерировать сущности, добавлять необходимые зависимости и инструменты, а также проводить миграции в проекте. Например, конвертацию SCAM в Standalone-компоненты. Сейчас при генерации Angular-проекта с помощью Nx вы получаете: Angular-приложение; Jest для юнит-тестирования; Cypress для интеграционного тестирования; ESLint для линтинга; Prettier для форматирования кода. С помощью официальных генераторов можно добавить и другие фичи: NgRx, Angular Universal, поддержку Module Federation, Storybook, Tailwind и многое другое. Набор технологий, поставляемых с приложением, позволяет не выбирать из бесконечного множества библиотек. Этим изначальным набором можно управлять с помощью флагов при генерации проекта. Например, убрать Jest или добавить Tailwind.  При этом никто не запрещает использовать свой стек. Можно вручную настроить кастомные пакеты или использовать список коммьюнити плагинов для Nx, позволяющих добавить в проект фичи, которых нет в официальной версии. Например, stylelint, electron, ionic, playwright и другие. Кэширование позволяет избежать повторной компиляции неизмененных файлов, что значительно ускоряет процесс сборки. Оно есть в обоих инструментах. Давайте разберемся, в чем разница. Angular CLI. Предоставляет кэширование, построенное на основе решения из Webpack. Если сильно упростить, для каждого файла вычисляется хэш на основе его содержимого. Благодаря этому можно отслеживать, какие файлы были изменены, и пересобирать только их. Проблема в том, что кэширование в Angular CLI ограничено только сборками и только одной машиной. Кроме того, оно медленнее, чем в Nx.  Для примера возьмем небольшую библиотеку компонентов и дважды соберем ее с помощью Angular CLI. Nx. В Nx кэширование — это не просто локальный кэш сборок, а кэш всех операций. То есть сборки, линтинг, тесты и любые кастомные операции. Кэширование в Nx построено на основе кэширования Angular CLI, но с добавлением своего кэша поверх всего этого. Таким образом, мы просто получаем улучшенный процесс из Angular CLI. Давайте соберем ту же библиотеку с помощью Nx. Для первого билда разница несущественная: 10 545 против 9027 мс. Но с ростом проекта разрыв будет увеличиваться. Во втором случае благодаря улучшенному кэшированию разница приличная: 4902 против 62 мс. Помимо локального кэширования Nx предлагает Nx Cloud, который сильно сокращает время сборок с помощью удаленного кэширования результатов сборок из-за шаринга артефактов между билд-агентами и машинами. График ниже показывает, сколько времени удалось сэкономить с помощью Nx Cloud за последние 30 дней в репозитории Nx. Результаты впечатляющие: Nx Cloud экономит больше половины времени для всех кэшируемых операций.  Посмотрим еще на один пример: Taiga UI, UI Kit наших коллег. В Taiga UI через Nx Cloud кэшируются только build- и test-операции, поэтому на графике мы видим сэкономленное время только для них. Для e2e и lint кэширования нет — так сложилось исторически. Здесь кэширование экономит примерно 30—40% времени. Показатели не такие высокие, как у Nx, но отчасти это зависит от кодовой базы и кэшируемых операций.  В любом случае Nx Cloud можно подключить одной командой: это никак не повлияет на ваш воркфлоу, но вы сильно выигрываете во времени.  Про кэширование можно почитать на сайте Nx на этой странице и на этой. А про Nx Cloud подробно рассказывал в докладе наш коллега Иван Ишмаметьев.  Технологии развиваются: что-то добавляется, что-то становится deprecated, иногда требуются мажорные изменения продуктов. Все это приводит к миграциям — неотъемлемой части разработки. И Angular CLI, и Nx предлагают миграции, но с разными подходами. Angular CLI. У миграций через Angular CLI есть ряд критических проблем. О них подробно говорится в официальной документации Nx, поэтому рекомендую почитать ее для полноты картины. Если вкратце, Angular CLI обновляет все и сразу. Это может быть недопустимо в больших проектах, так как миграции генерируют огромное количество изменений, которые невозможно контролировать. Возможности мигрировать частично нет. В результате мы всегда имеем огромный PR и высокие шансы что-то сломать. Одна из проблем, о которой не говорят в документации, — автоматическое обновление только Angular. То есть все сопутствующие технологии — Jasmine, Protractor, NgRx — нужно обновлять вручную или отдельными сторонними скематиками. Nx. Nx предлагает миграцию в два шага: поднятие версий в package.json и создание файла migrations.json, где указаны необходимые изменения. Разработчики сами выбирают, какие миграции произвести. Например, мы хотим мигрировать с Angular 13 на Angular 14. Запускаем nx migrate, получаем обновленные package.json и список необходимых миграций. Дальше мы сами выбираем, что хотим сейчас мигрировать, а что нет. Важно отметить, что в рамках той же миграции и той же одной команды Nx позволяет обновить все зависимости, созданные через генераторы, — линтер, инструменты для тестирования, менеджер состояний и так далее — до новых версий. Nx можно назвать оберткой над Angular CLI. Используя Nx, вы ничего не теряете, а только приобретаете.  Если вы не работаете с монорепозиториями, Nx полезно использовать ради инструментов, миграций и кэширования. Если же вы работаете с монорепозиториями, то помимо вышеперечисленных фич получите еще и удобные инструменты для работы с ними. Мы в Тинькофф полностью перешли на Nx, перестав поддерживать билдеры и скематики для Angular CLI. Nx умеет все, что умеет Angular CLI, но при этом добавляет множество фич. А нам не приходится поддерживать две огромные экосистемы.  Frontend Engineer