Почему подкомпоненты в Angular должны регистрироваться через NgModule? Как насчет инкапсуляции?
У меня есть некоторый опыт работы с другими структурами и архитектурными принципами, и я абсолютно не понимаю решения Angular Team о том, чтобы отклонить свойство directivies
Компонента в RC6 в пользу declarations
в NgModule.
Обычно архитектура относится к инкапсуляции, но внезапно, если какая-то функция целостности компонента должна быть инкапсулирована дочерним компонентом, подкомпонент "протекает" до модуля, где он теперь должен быть зарегистрирован.
-
Итак, почему, имея логическое дерево компонентов в модуле, все они должны быть зарегистрированы "plain" внутри NgModule?
-
Разве этот подход не взорвал ngmodule с большим количеством импорта и дебакаций?
Я понимаю, что мы можем разделить все на несколько модулей, но внутри одного модуля такая глобальная "загрузка и регистрация" запоминает меня, чтобы script [src]
теги глобального script [src]
внутри html. Я думал, что мы отошли от этого шаблона, но похоже, что Angular возвращается к нему.
Кажется, я кое-что пропустил, может кто-нибудь, пожалуйста, объясните мне?
[ РЕДАКТИРОВАТЬ 1 ] (разбивает компиляцию AOT, см. edit-2
). Прямо сейчас мы имитируем декларацию вложенных компонентов, так что каждый компонент экспортирует список используемых компонентов, а затем в NgModule мы идем через все корневые компоненты, собираем их зависимости и готовим полный список declarations
.
Это выглядит так:
src/app
- /components/home-view/
- /toolbar
/menu-button
- menu-button.component.ts
- toolbar.component.ts
- home-view.component.ts
- app.module.ts
app.module.ts
import { HomeViewComponent } from './components/home-view/home-view.component';
namespace Utils {
export function flatternDirectives (arr: any[] = []): any[] {
const declarations = arr.reduce((compos, compo) => {
compos.push(...flatternDirectives(compo.directives), compo);
return compos;
}, []);
return Array.from(new Set(declarations));
}
}
@NgModule({
declarations: Utils.flatternDirectives([
HomeViewComponent,
]),
bootstrap: [AppComponent]
})
export class AppModule { }
./components/home-view/home-view.component.ts
import { ToolbarComponent } from './toolbar/toolbar.component';
@Component({
selector: 'app-home-view',
template: '<app-toolbar></app-toolbar>',
})
export class HomeViewComponent {
static directives = [ ToolbarComponent ]
}
./components/home-view/toolbar/toolbar.component.ts
import { MenuButtonComponent } from './menu-button/menu-button.component';
@Component({
selector: 'app-toolbar',
template: '<app-menu-button></app-menu-button>',
})
export class ToolbarComponent {
static directives = [ MenuButtonComponent ]
}
./components/home-view/toolbar/menu-button/menu-button.component.ts
@Component({
selector: 'app-menu-button',
template: '<button></button>',
})
export class MenuButtonComponent {}
Существуют ли какие-либо оговорки в таком подходе?
[ EDIT 2 ] В DEV подход выше работал отлично, но компиляция AOT прерывается с ошибкой.
ERROR in : Cannot determine the module for class 'name' in 'path'! Add 'name' to the NgModule to fix it.
Поэтому мы должны вернуться к простым декларациям. Любые решения, как tofix для компиляции aot?
Спасибо.
Ответы
Ответ 1
-
Концепция NgModule
задерживалась до выпуска, она обеспечивает стандартный способ создания библиотек/модулей, добавляет эффективную систему импорта и функцию ленивой загрузки. Во многом это похоже на любую другую систему модулей/пакетов (т.е. объявлять зависимости модулей, публичный экспорт модулей и т.д.) С некоторыми ограничениями из-за характера JS.
-
Вы можете выбрать уровень детализации при разработке модулей, чтобы избежать подробного импорта/деклараций. Библиотеки, как правило, используют модуль для каждой стратегии компонента, чтобы минимизировать влияние размера (вы импортируете именно то, что вам нужно, не более), но иногда вам приходится импортировать много модулей в этом случае.
-
Проблема в том, что в AOT все ссылки на компоненты должны быть реплицированы статически во время компиляции, вы не можете иметь динамический код, например, функцию flatternDirectives
поскольку он не статически анализируется. См. Https://angular.io/guide/aot-compiler#metadata- ограничения, я сомневаюсь, что можно написать функцию, которая может удалять повторяющиеся записи, но, вероятно, вы могли бы использовать даже дублированные записи, т declarations: [HomeViewComponent.directives]
(необходимо проверить сгенерированный код).