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

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

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

Мы начнем с демонстрации того, как организовать ваш проект и папки Angular. Далее мы рассмотрим компоненты, сервисы и лучшие практики Angular. Далее мы рассмотрим, как обращаться с управлением состоянием. В конце статьи мы рассмотрим основные передовые практики кодирования.

В конце этой статьи вы узнаете все основные рекомендации, которые помогут вам создавать высококачественные и масштабируемые приложения Angular. Мы используем Angular 13, но большинство из этих практик применимы и к предыдущим версиям.

Структура и организация приложения

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

Руководство по стилю Angular использует аббревиатуру LIFT в качестве ориентира. Это означает:

  • Местоположение — вы должны иметь возможность быстро находить файлы
  • Яидентифицирую — назовите файл так, чтобы вы сразу знали, что в нем содержится.
  • Flat — сохраняйте плоскую структуру папок как можно дольше.
  • Постарайтесь быть СУХИМ — не повторяйтесь, но избегайте быть настолько СУХИМ, чтобы не пожертвовать удобочитаемостью.

Ниже приведен формат, который я использую для средних и больших приложений Angular.

Основная папка и модуль

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

Общая папка и модуль

Общий модуль содержит компоненты, конвейеры и директивы, которые используются и на которые ссылаются компоненты в функциональных модулях.

Папка функций и модули

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

Стили и активы

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

Лучшие практики Angular Services

Отделите свои компоненты от поиска данных

Служба Angular обычно представляет собой класс с одной целью. Он делает что-то конкретное и делает это хорошо. Цель службы — защитить ваш компонент от прямого извлечения данных. Разделение этих обязанностей сделает логику поиска многократно используемой и более легкой для тестирования. Другим результатом является то, что ваши классы компонентов будут компактными и эффективными.

Поэтому избегайте соблазна получать данные или вызывать API непосредственно из ваших компонентов. Вместо этого используйте сервис.

Добавьте инъекционный декоратор ко всем сервисам

Когда службе требуется другая служба, вы внедряете ее через конструктор службы. Затем вам нужно добавить декоратор @Injectable в класс. Вы можете добавить @Injectable ко всем своим сервисам, даже если в данный момент им не нужен другой сервис. Я считаю, что проще добавить его напрямую, а не во время добавления сервисной зависимости. Я часто забываю это.

Понять, как Angular внедряет сервисы

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

Когда Angular запускается, он создает централизованный инжектор. Этот инжектор собирает все определенные зависимости и поддерживает все созданные экземпляры, которые приложение может повторно использовать внутри контейнера. Вы сообщаете Angular, что он может использовать сервис в своей системе DI, украшая его @Injectable и перечисляя сервис в разделе «Поставщики» модуля.

Обычно Angular внедряет один и тот же экземпляр службы в ваш компонент. Есть одно исключение с лениво загружаемыми функциональными модулями. Эти модули получают новый экземпляр службы. Помните об этом, когда используете ленивую загрузку и используете состояние внутри своего сервиса.

Рекомендации по повышению производительности

Ленивая загрузка

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

Мониторинг размеров пакетов

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

Source-map-explorer — это инструмент, который помогает визуализировать, откуда берется весь код в вашем бандле. Вы устанавливаете source-map-explorer с npm install -g source-map-explorer. После того, как вы сгенерируете производственную сборку с исходными картами, используя ng build --configuration production --source-map=true. Затем вы можете визуализировать сгенерированные js-файлы с помощью source-map-explorer. См. пример ниже.

Упреждающая компиляция и интерфейс командной строки

Есть два способа скомпилировать приложение Angular. Just-in-Time (JIT) компилирует ваше приложение в браузере во время выполнения. Или вы можете использовать Ahead-of-Time (AOT), который компилирует ваше приложение во время сборки. AOT используется по умолчанию, начиная с Angular 9.

Вы можете выбрать тип компилятора через свойство aot в файле конфигурации angular.json.

Лучше всегда использовать компиляцию AOT, так как она компилирует ваше приложение только один раз перед развертыванием, что экономит время.

Стратегия обнаружения изменений

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

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

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

Вторая стратегия, OnPush, сравнивает входные данные по ссылке. Использование стратегии OnPush улучшит производительность вашего приложения Angular.

Если вы используете метод OnPush, вы должны убедиться, что все ваши объекты станут неизменяемыми. Если вы этого не сделаете и продолжите работать с изменяемыми объектами, сложность вашего приложения возрастет. Затем это может привести к ошибкам, которые трудно воспроизвести.

Если вы переключитесь на OnPush, убедитесь, что ваши объекты стали неизменяемыми. Хорошим выбором для неизменяемости является использование библиотеки Immutable.js. Эта библиотека предоставляет неизменяемые примитивы для создания приложений, таких как неизменяемые объекты и списки.

Чистая и нечистая производительность трубы

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

Быстрый способ решить эту проблему — изменить канал на нечистый, установив для свойства pure декоратора Pipe в строке 3 значение false. Это будет запускать конвейер при каждом изменении данных.

Однако лучше бы вы этого не делали! Грязная труба снижает производительность. Лучший способ решить эту проблему — использовать неизменяемость, когда вы меняете ссылку на объект, создавая новую.

Угловые компоненты

Разделение компонентов, CSS и файлов шаблонов

Компонент состоит из шаблона, стилей и машинописного кода компонента. Вы можете интегрировать шаблон и стили в файл typescript компонента. Лучшей практикой является то, что если ваш HTML состоит более чем из четырех строк, вы должны выделить HTML-шаблон в отдельный файл.

Префиксы селекторов компонентов

Рекомендуется использовать префикс для селекторов компонентов. Если вы сохраняете компонент в функциональном модуле, установите префикс компонента в соответствии с этим функциональным модулем. Если общий компонент находится в общем модуле, используйте имя приложения в качестве префикса селектора. Убедитесь, что длина префикса составляет от 2 до 4 символов.

Декорирование входных и выходных свойств

Существует два способа создания входных и выходных свойств ваших компонентов. Рекомендуемый способ — украсить ваши общедоступные свойства @Input. Второй не рекомендуемый метод — использование метаданных.

Делегирование сложной логики службам

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

Последовательность элемента компонента

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

  • Публичные свойства
  • Частная собственность
  • Конструктор
  • Публичные методы
  • Частные методы

Реализация интерфейсов хуков жизненного цикла

Когда Angular создает и уничтожает ваш компонент, вы можете привязать к нему несколько событий жизненного цикла. Вместо прямой реализации метода следует использовать интерфейс. Реализуя интерфейс через implements [Interface], вы убедитесь, что правильно реализуете событие.

Угловое управление состоянием

Когда ваше приложение Angular увеличится в размерах, ему потребуется управление состоянием. Вы можете реализовать управление состоянием, используя несколько шаблонов и библиотек. Один из наиболее простых способов — использовать привязки компонентов @Input и @Output. Вы также можете использовать службы Angular и простые переменные для хранения временных данных.

Когда ваше приложение разрастется, вам понадобится что-то другое. Мы знали, что наше приложение вырастет до размеров корпоративного приложения, поэтому начали с NGXS.

NGXS — это шаблон управления состоянием + библиотека для Angular. Этот знаменитый шаблон Redux и библиотека сделали его популярным. NGXS работает так же, как он централизовал состояние и логику вашего приложения. Таким образом, у вас есть центральное место в вашем приложении, которое содержит все состояние.

Например, я работал над приложением Angular для показа фильмов на самолетах. Приложение извлекло все фильмы через службу и сохранило их в том состоянии, в котором оно было запущено. Каждый компонент, который должен был показывать фильмы, выбирал их через центральное состояние.

Еще одним преимуществом NGXS является использование селекторов для получения данных из хранилища в виде Observable и Actions для изменения хранилища. Теперь, чтобы вдаваться в подробности использования NGXS, потребовалась бы почти полная статья, поэтому я сохранил ее для другой статьи.

Лучшие практики кодирования Angular

неизменность

Существует несколько рекомендаций по кодированию на JavaScript или TypeScript. Одной из первых лучших практик, о которой мы упоминали ранее, является неизменяемость. Неизменяемость — это общая рекомендация для всего вашего кода JavaScript. Неизменяемость относится к программированию, при котором вы не изменяете существующие объекты, а создаете новые объекты с необходимыми изменениями. Библиотека JavaScript, которая может помочь, — Immutable.js.

В строке 3 в приведенном выше примере мы используем Map from immutable, чтобы установить для ключа b значение 50. В результате получается новая карта, содержащая все значения map1, а значение ключа b изменено на 50.

Строгий режим

Строгий режим Angular относится к проверке TypeScript, которую Angular выполняет при компиляции вашего приложения. Строгий режим повышает удобство сопровождения и помогает заблаговременно выявлять ошибки. Строгий режим также позволяет автоматически обновлять Angular с помощью ng update.

Строгий режим включен по умолчанию, когда вы создаете новый проект Angular с помощью CLI.

Маленькие файлы и функции

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

Строгих ограничений для файлов или функций нет, но руководство по стилю Angular предлагает ограничить ваши функции более чем 75 строками.

Принцип единой ответственности

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

Когда я создаю новое приложение Angular, я разбиваю его на отдельные компоненты. Для каждого компонента я описываю его обязанности, а также входные и выходные данные. Я всегда начинаю описание со слов: «Этот компонент отвечает за…». — количество текста, которое мне нужно для описания ответственности, сигнализирует о необходимости дальнейшего разделения компонента.

Заключение

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

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

Я надеюсь, что эти рекомендации помогут вам при создании приложения Angular.