Модули(Modules)

Модуль - это класс, аннотированный декоратором @Module(). Декоратор @Module() предоставляет метаданные, которые Nest использует для организации структуры приложения.

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

Декоратор @Module() принимает один объект, свойства которого описывают модуль:

Свойство

Описание

providers

провайдеры, которые будут созданы Nest injector и которые могут быть совместно использованы по крайней мере в этом модуле

controller

набор контроллеров, определенных в этом модуле, которые должны быть созданы

imports

список импортированных модулей, экспортирующих провайдеров, которые требуются в этом модуле

exports

подмножество провайдеров, которые предоставляются этим модулем и должны быть доступны в других модулях, импортирующих этот модуль

Модуль инкапсулирует провайдеры по-умолчанию. Это означает, что невозможно внедрить провайдеры, которые не являются ни непосредственно частью текущего модуля, ни экспортируются из импортированных модулей. Таким образом, вы можете рассматривать экспортированные провайдеры из модуля как публичный интерфейс модуля, или API.

Модуль - фича

CatsController и CatsService принадлежат к одному и тому же домену приложения. Поскольку они тесно связаны, имеет смысл переместить их в модуль-фичу. Модуль-фича просто организует код, относящийся к конкретному объекту, сохраняя код организованным и устанавливая четкие границы. Это помогает нам управлять сложностью и разрабатывать с SOLIDarrow-up-right принципами, особенно по мере роста размера приложения и/или команды.

Чтобы продемонстрировать это, мы создадим CatsModule.

cats/cats.module.ts

circle-info

Чтобы создать модуль с помощью CLI, просто выполните команду $ nest g module cats.

Выше мы определили CatsModule в cats.module.ts файл, и переместил все, что связано с этим модулем, в каталог cats. Последнее, что нам нужно сделать, это импортировать этот модуль в корневой модуль (AppModule, определенный в app.module.ts).

Общие модули

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

Каждый модуль автоматически является общим модулем. После создания он может быть повторно использован любым модулем. Давайте представим, что мы хотим разделить экземпляр CatsService между несколькими другими модулями. Для этого нам сначала нужно экспортировать провайдер CatsService, добавив его в массив exports модуля, как показано ниже:

cats.module.ts

Теперь любой модуль, импортирующий CatsModule, имеет доступ к CatsService и будет совместно использовать тот же экземпляр со всеми другими модулями, которые его импортируют.

Реэкспорт модуля

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

DI(инъекция зависимости)

Класс модуля также может инъектировать провайдеры(например, для целей конфигурации):

Однако сами классы модулей не могут быть инъектированы в качестве провайдеров из-за циклической зависимостиarrow-up-right.

Глобальные модули

Если вам придется импортировать один и тот же набор модулей везде, это может стать утомительным. В отличие от Nest, провайдеры Angular зарегистрированы в глобальной области видимости. Как только они определены, они доступны везде. Однако Nest инкапсулирует провайдеры внутри области видимости модуля. Вы не можете использовать провайдеры модуля в другом месте без предварительного импорта инкапсулированного модуля.

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

Декоратор @Global() делает модуль global-scoped. Глобальные модули должны быть зарегистрированы только один раз, как правило, корневым или основным модулем. В приведенном выше примере провайдер CatsService будет повсеместным, и модулям, которые хотят внедрить сервис, не нужно будет импортировать CatsModule в свой массив импорта.

circle-info

Делать все глобальным - это не очень хорошее дизайнерское решение. Глобальные модули доступны для уменьшения количества повторяющегося шаблонного кода. Массив импорта, как правило, является предпочтительным способом сделать API модуля доступным.

Динамические модули

Система модулей Nest включает в себя мощную функцию, называемую динамическими модулями. Эта функция позволяет легко создавать настраиваемые модули, которые могут динамически регистрировать и настраивать провайдеров. Здесьarrow-up-right подробно рассматриваются динамические модули. В этой главе мы дадим краткий обзор, чтобы завершить введение в модули.

Ниже приведен пример определения динамического модуля для модуля DatabaseModule:

circle-info

Метод forRoot() может возвращать динамический модуль либо синхронно, либо асинхронно (т.е. через Promise).

Этот модуль определяет провайдер Connection по-умолчанию (в метаданных декоратора @Module()), но дополнительно - в зависимости от entities(сущностей) и объекта options, передаваемых в метод forRoot() - предоставляет коллекцию провайдеров, например репозитории. Обратите внимание, что свойства, возвращаемые динамическим модулем, расширяют (а не переопределяют) метаданные базового модуля, определенные в декораторе @Module(). Именно так из модуля экспортируются как статически объявленный провайдер Connection, так и динамически генерируемые провайдеры репозиториев.

Если вы хотите зарегистрировать динамический модуль в глобальной области видимости, задайте для свойства global значение true.

circle-info

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

Модуль DatabaseModule можно импортировать и настроить следующим образом:

Если вы хотите в свою очередь ре-экспортировать динамический модуль, вы можете указать вызов метода forRoot() в массиве exports:

В главе динамические модулиarrow-up-right эта тема рассматривается более подробно и содержит рабочий примерarrow-up-right.

Last updated