Фотография с обложки Клэя Бэнкса на Unsplash.
Автономный компонент не зависит от модуля Angular. Он напрямую ссылается на декларируемые компоненты (компоненты, директивы и трубы), используемые в его шаблоне.
Объявляемые зависимости
Автономный компонент Angular указывает декларируемые зависимости в параметре метаданных Component.imports
для управления локальной областью применения компонента.
Рассмотрим автономную реализацию компонента детализации героя из учебника Tour of Heroes:
import { NgIf, UpperCasePipe } from '@angular/common';
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
imports: [FormsModule, NgIf, UpperCasePipe],
selector: 'toh-hero-detail',
standalone: true,
stylesUrls: ['./hero-detail.component.css'],
template: `
<div *ngIf="hero">
<h2>{{ hero.name | uppercase }} Details</h2>
<div><span>id: </span>{{ hero.id }}</div>
<div>
<label for="hero-name">Hero name: </label>
<input
id="hero-name"
[(ngModel)]="hero.name"
placeholder="Hero name"
/>
</div>
<button type="button" (click)="goBack()">go back</button>
<button type="button" (click)="save()">save</button>
</div>
`,
})
export class HeroDetailComponent {
// Class body omitted
}
Важно отметить, что параметр метаданных Component.standalone
имеет значение true
.
Далее мы перечислим декларируемые зависимости и/или модули Angular, экспортирующие декларируемые зависимости, в параметре метаданных Component.imports
. Посмотрите, как структурная директива NgIf
перечислена вместе с Angular pipe UppercasePipe
, обе из пакета @angular/common
. Это возможно, поскольку они оба являются отдельными декларируемыми параметрами в современных версиях Angular.
Информация
По-прежнему можно импортироватьCommonModule
для внедрения всех общих объявлений Angular в локальную область видимости отдельного компонента.
Кроме того, FormsModule
добавлен в опцию метаданных Component.imports
, вводя директиву атрибутов NgModel
в локальную область видимости компонента hero detail.
ℹ️ Примечание
Важно отметить, что компоненты, директивы и трубы, перечисленные вComponent.imports
, должны быть помечены опцией метаданныхstandalone: true
, доступной какComponent.standalone
,Directive.standalone
иPipe.standalone
.Начиная с 15 версии Angular, по умолчанию для этого параметра метаданных установлено значение
standalone: false
, которое может быть изменено в будущем в зависимости от того, насколько хорошо декларируемые автономные параметры будут приняты экосистемой и сообществом Angular.
Осмотрев шаблон компонента, мы видим, что используется директива NgIf
:
<div *ngIf="hero">
<!-- Conditional content omitted -->
</div>
Далее мы видим, что в шаблоне используется труба UppercasePipe
:
<h2>{{ hero.name | uppercase }} Details</h2>
Наконец, свойство Hero#name
привязывается к элементу управления формы с помощью двусторонней привязки данных с помощью директивы NgModel
:
<input
id="hero-name"
[(ngModel)]="hero.name"
placeholder="Hero name"
/>
Локальная область видимости компонента
В графе зависимостей локальной области видимости отдельного компонента hero detail мы видим связь между нашим компонентом и его декларируемыми зависимостями:
За исключением FormsModule
, это точно соответствует косвенным зависимостям шаблона компонента от используемых им декларируемых зависимостей:
Косвенные зависимости означают, что шаблон компонента использует селекторы элементов, селекторы атрибутов и имена труб, указанные в опциях метаданных Component.selector
, Directive.selector
и Pipe.name
декларируемых зависимостей компонента.
Переходная область компиляции
Если сравнить это с переходной областью компиляции декларирующего модуля классического компонента Angular, то можно заметить увеличение умственных накладных расходов в классическом стиле компонента Angular:
HeroDetailModule
и CommonModule
вносят уровни косвенности в граф зависимостей. Вместо прямой зависимости от HeroDetailComponent
к NgIf
и UppercasePipe
, нет прямого потока зависимостей между классом HeroDetailComponent
и любой из его декларируемых зависимостей. Это вызвано тем, что HeroDetailModule
ссылается на HeroDetailComponent
, а не наоборот. Еще одна непрямая связь — это ненужный CommonModule
, инкапсулирующий декларируемые Angular функции, из которых мы используем только две в шаблоне компонента.
Классический граф зависимостей Angular не соответствует косвенным зависимостям шаблона компонента от необходимых ему деклараций.
Представьте себе логику, необходимую компилятору Angular для определения зависимостей между классами, и то, какое обслуживание требуется при внесении значительных изменений в Angular, компилятор TypeScript и другие зависимости.
Хуже того, прежний классический граф зависимостей упрощается. В этом расширенном классическом графе зависимостей видна полная область транзитивной компиляции модуля hero detail:
Это 52 декларируемые переменные, импортированные в переходную область компиляции, из которых шаблон компонента использует только 3. 52.
К счастью для нас, дерево Build Optimizer в Angular Development Kit вытряхивает неиспользуемые декларативные файлы из переходных диапазонов компиляции и локальных диапазонов компонентов. Если бы это было не так, наш пучок увеличивался бы каждый раз, когда мы импортировали модуль Angular, который экспортировал больше деклараций, чем мы использовали в нашем шаблоне компонента.
Это подводит нас к следующей теме: Сопровождение.
Поддержание декларируемых зависимостей
Взгляните еще раз на предыдущий расширенный переходный диапазон компиляции. По мере развития кодовой базы, как нам поддерживать декларируемые зависимости в синхронизации с переходной областью компиляции? Как определить, когда наш шаблон компонента больше не использует ни одной декларируемой зависимости из модуля Angular, экспортирующего более десятка декларируемых зависимостей.
Это становится все сложнее для каждого объявленного компонента в модуле Angular и каждого импортированного модуля, не относящегося к SCAM.
ℹ️ Примечание
Пришло время преобразовать SCAM в самостоятельные декларируемые компоненты. В конце концов, это всегда было их целью.
Проще сканировать шаблон автономного компонента и сравнивать его с импортированными автономными декларируемыми модулями, перечисленными в параметре метаданных Component.imports
.
Заключение
Автономный компонент имеет локальную область видимости компонента, состоящую из зависимостей его декларируемых компонентов, которые перечислены в опции метаданных Component.imports
.
Мы должны поддерживать локальную область видимости компонента таким образом, чтобы она соответствовала декларируемым файлам, используемым в шаблоне компонента. Для этого мы сравниваем отдельный шаблон компонента с отдельными декларациями и модулями Angular, перечисленными в параметре метаданных Component.imports
, поддерживая их синхронизацию.
Общие декларируемые модули, такие как NgIf
и UppercasePipe
, экспортируемые CommonModule
, теперь являются отдельными декларируемыми модулями, на которые можно ссылаться непосредственно в параметре метаданных Component.imports
.