Почему подкомпоненты в Angular должны регистрироваться через NgModule? Как насчет инкапсуляции?

У меня есть некоторый опыт работы с другими структурами и архитектурными принципами, и я абсолютно не понимаю решения Angular Team о том, чтобы отклонить свойство directivies Компонента в RC6 в пользу declarations в NgModule.

Обычно архитектура относится к инкапсуляции, но внезапно, если какая-то функция целостности компонента должна быть инкапсулирована дочерним компонентом, подкомпонент "протекает" до модуля, где он теперь должен быть зарегистрирован.

  1. Итак, почему, имея логическое дерево компонентов в модуле, все они должны быть зарегистрированы "plain" внутри NgModule?

  2. Разве этот подход не взорвал 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

  1. Концепция NgModule задерживалась до выпуска, она обеспечивает стандартный способ создания библиотек/модулей, добавляет эффективную систему импорта и функцию ленивой загрузки. Во многом это похоже на любую другую систему модулей/пакетов (т.е. объявлять зависимости модулей, публичный экспорт модулей и т.д.) С некоторыми ограничениями из-за характера JS.

  2. Вы можете выбрать уровень детализации при разработке модулей, чтобы избежать подробного импорта/деклараций. Библиотеки, как правило, используют модуль для каждой стратегии компонента, чтобы минимизировать влияние размера (вы импортируете именно то, что вам нужно, не более), но иногда вам приходится импортировать много модулей в этом случае.

  3. Проблема в том, что в AOT все ссылки на компоненты должны быть реплицированы статически во время компиляции, вы не можете иметь динамический код, например, функцию flatternDirectives поскольку он не статически анализируется. См. Https://angular.io/guide/aot-compiler#metadata- ограничения, я сомневаюсь, что можно написать функцию, которая может удалять повторяющиеся записи, но, вероятно, вы могли бы использовать даже дублированные записи, т declarations: [HomeViewComponent.directives] (необходимо проверить сгенерированный код).