Angular: NgModule в крупных проектах

Созданный на 7 авг. 2016  ·  144Комментарии  ·  Источник: angular/angular

Я отправляю ... (отметьте один знаком "x")

[X] feature request / proposal

Я читал о NgModule и хочу изложить некоторые варианты использования, которые, я не совсем уверен, учитывает текущее предложение (https://docs.google.com/document/d/1isijHlib4fnukj-UxX5X1eWdUar6UkiGKPDFlOuNy1U/pub). .

Контекст

Я являюсь частью команды, разрабатывающей Enterprise Framework (на основе Angular 2). Затем эта структура станет основой для других приложений в той же экосистеме.

Мы разделили фреймворк на более мелкие проекты/модули (думайте о них как об отдельных пакетах npm). Эти модули представляют собой наборы элементов управления (которые затем повторно используются в других модулях) или страницы, использующие эти элементы управления.

Пример

Быстрый пример может быть:

Модуль управления

import {Component} from "@angular/core";

@Component({
   selector: "my-combobox",
   ...
})
export class MyComboBox{

}

Модуль контрольного списка
// Модуль контрольного списка зависит от модуля управления. Элементы управления рассматриваются как сторонний модуль.

import {Component} from "@angular/core";
import {MyComboBox} from "controlsmodule/components/mycombobox";
// Please note that we are only loading a specific component within the module, not all components inside that module.

@Component({
     selector: "my-checklist-page",
     directives: [MyComboBox, ...],
     ...
})
export class ChecklistPage{

}

Bootstrap не знает модулей Controls и Checklist. Они лениво загружаются в зависимости от взаимодействия с пользователем. В этом случае, если пользователь перейдет к контрольному списку, компонент ChecklistPage будет загружен, а затем MyComboBox также будет следовать (из-за _import_, сделанного ChecklistPage)

Модуль контрольного списка имеет еще дюжину компонентов. Каждый зависит от других десятков компонентов из нескольких модулей.

Непрактично (если не сказать почти невозможно) импортировать все компоненты в объявление NgModule. Мы говорим о нескольких сотнях компонентов, которые _могут_ использоваться во время выполнения приложения.

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

Ожидаемое/желаемое поведение

Текущее решение с директивами области действия компонентов отлично подходит для этого варианта использования. Не уверен, как это будет работать с NgModule.

Более того, в настоящее время мы можем четко видеть зависимости, необходимые каждому компоненту (в данном случае ChecklistPage). Делая техническое обслуживание намного проще.

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

Вывод

Пожалуйста, дайте мне знать, если я ясно объяснил. Цель этого выпуска — повысить осведомленность об этой ситуации и получить от вас отзывы о том, как действовать дальше.

Мы готовы показать вам нашу текущую работу, у нас есть несколько сотен компонентов Angular 2 для 8 проектов, разработанных за последний год (начиная с альфа-версии 27).

Самый полезный комментарий

Всем спасибо за отзывы, приносим извинения за то, что так долго не могли получить ответ - мы были очень заняты на прошлой неделе (перенос внутренних приложений Google на NgModules, поэтому мы тоже чувствуем боль от рефакторинга)

Позвольте мне посмотреть, смогу ли я прояснить некоторые вопросы и неправильные представления здесь.

Первое, что нужно понять о @NgModule() (а также @Component и любом другом декораторе Angukar), это то, что они являются конструкцией исключительно времени компиляции - они существуют, чтобы позволить компилятору angular обнаруживать граф зависимостей в приложении.

(Упрощенная) версия того, что делают наши декораторы, выглядит так:

//simplified Component decorator
export function Component(componentConfig){
  return function(componentClass){
    Reflect.defineMetadata('annotations', componentConfig, componentClass);
  }
}

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

В режиме JiT это происходит «как раз вовремя» — между вызовом bootstrapModule и рендерингом вашего первого компонента компилятор Angular извлекает метаданные, прикрепленные к классам, с помощью Reflect API:

let metadata = Reflect.getOwnMetadata('annotations', componentClass);

Однако в режиме AoT это работает немного по-другому — во время сборки мы _статически_ (то есть без выполнения вашего кода) извлекаем одни и те же метаданные из исходного кода, сканируя декораторы.

Это работает нормально, когда вы загружаете один компонент, но мы слышали много отзывов от разработчиков, которые делают более сложные вещи — загружают несколько корневых компонентов или загружают разные компоненты на основе статуса аутентификации и т. д.

Таким образом, в то время как декораторы @Component давали нам возможность статически анализировать компонент, у нас не было возможности надежного статического анализа _приложения_.

Вещи, которые попадают под зонтик «приложения»

  • PLATFORM_DIRECTIVES/PIPES/PROVIDERS
  • вещи, которые вы ранее добавили в bootstrap()
  • настройки уровня компилятора
  • несколько корневых компонентов
  • использование на стороне сервера.

NgModules представляет идею статически анализируемого набора функций. Что интересно, в режиме компиляции AoT мы анализируем ваш корневой модуль и _генерируем_ ModuleFactory для каждого модуля в приложении — это предварительно скомпилированная версия модуля, которая содержит _только_ фабрики, на которые вы статически ссылаетесь в шаблонах, и те, которые вы пометить как "entryComponents"

Поскольку мы уже извлекли информацию, необходимую для компиляции заблаговременно, мы можем на самом деле вытряхнуть декораторы из дерева (ngc сделает это автоматически для финала) — и вместо того, чтобы связывать ваше приложение, начиная с вашего корневого модуля, вы начинаете в сгенерированном вами корневом Module_Factory_, который содержит только тот код, который фактически используется в вашем приложении, поэтому вы не платите штраф за модульность, а такие инструменты, как rollup и webpack2, могут работать _более_ эффективно

дальше в следующем ответе...

Все 144 Комментарий

Мне не кажется, что ngModules запрещает настройку, которую вы собираетесь использовать, вы уже играли с ней? У вас может быть несколько разных модулей и ленивая загрузка и т. д. http://plnkr.co/edit/NAtRQJBy50R19QAl90jg?p=info

Для чего-то более похожего на то, что вы пытаетесь сделать, следите за переходом material2: https://github.com/angular/material2/pull/950/files

Привет @qdouble ,

Спасибо за быстрый ответ.
Глядя на https://github.com/jelbourn/material2/blob/ecbb4f42e0473899f6ad15d8e4ed8f262ded7a99/src/components/button-toggle/button-toggle.ts , вы говорите, что для достижения той же функциональности, что у нас есть сейчас, нам нужно объявить NgModule для каждого компонента? (это то, что было добавлено в конец файла, верно?)

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

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

Что касается второй проблемы, вы можете объявить ngModule и компонент рядом друг с другом, поэтому, хотя это добавит в ваши файлы дополнительные 3 или 4 строки кода, я не думаю, что это создает огромную проблему.

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

@qdouble Спасибо.

Я не уверен, что это ситуация или/или, я вижу, что оба сценария работают вместе, нет необходимости удалять функциональность, которая у нас уже есть. Если кто-то хочет использовать модули, я вижу в этом отличное дополнение. При этом фреймворк мог бы работать и без модулей (как работает сегодня). Я считаю, что даже проблема автономной компиляции может быть решена в том виде, в каком она есть на данный момент.

Я открываю это, чтобы посмотреть, есть ли у кого-то что-то, чтобы добавить к этому вопросу.

@jpsfs понял, если бы я был в вашей ситуации, я бы определенно предпочел, чтобы они оставили оба варианта открытыми :)

Они написали причину отказа от директив компонента в опубликованном вами документе, поскольку он создает две области, они думают, что область действия ngModule достаточно мала и больше соответствует модели ES6.

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

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

Даже я в настоящее время работаю над проектированием архитектуры для огромного корпоративного приложения.
В отличие от вашей ситуации @jpsfs , я в восторге от NgModules и в значительной степени основываю архитектуру своего приложения на NgModule.

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

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

Создание иерархии модулей также намного проще, и оно предоставляет отличную функцию Plug and Play бесплатно.

В настоящее время мы также работаем над приложением с довольно большим количеством компонентов (не сотнями, а десятками). У нас нет архитектурной необходимости разбивать это приложение на несколько (лениво загружаемых) модулей, но теперь импорт всех этих компонентов в файл начальной загрузки и передача их в declarations как-то кажется неправильным и нарушает инкапсуляцию компонента . Как сказал @jpsfs , раньше было совершенно ясно, какие компоненты и директивы используются другим компонентом. Так что я был бы также признателен за выбор:

  • Если это довольно часто используемая директива, объявите ее в модуле
  • Если это что-то вроде TaskListItem , просто импортируйте его в TaskList .

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

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

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

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

Я чувствовал, что первоначальная функциональность соответствовала аналогичным преимуществам, предоставляемым эмуляцией теневого DOM CSS, в том смысле, что мы могли меньше беспокоиться о коллизиях селекторов и т. Д. В больших приложениях. Это было большое преимущество ИМО.

Моей первой мыслью о ngModule было «О, это как в angular 1». Каким бы отличным ни был угловой 1, угловой 2 намного лучше по многим пунктам. Лучше всего для меня было то, что Компоненты создают своего рода дерево зависимостей. У меня есть основной компонент с маршрутизатором, который определяет несколько точек входа со своим собственным компонентом. И каждый компонент знает, что ему нужно, нет никаких оснований для того, чтобы главный компонент знал, что нужно любому из компонентов в конце дерева.
Теперь мы вернулись к старым добрым временам angular 1, где у нас есть гигантское определение модуля.
Помните времена, когда ваша точка входа в приложение выглядела так?

angular.module("myApp")
.controller("…")
.controller("…")
.controller("…")
.controller("…")
.controller("…")
.controller("…")
.component("…")
.component("…")
.component("…")
.component("…")
.component("…")
.component("…")
.directive("…")
.directive("…")
.directive("…")
.directive("…")
.directive("…")
.directive("…")
.directive("…")
.service("…")
.service("…")
.service("…")
.service("…")
.service("…")
.service("…")

Я думал, что это осталось в прошлом. Я начал работать с ng-метаданными, чтобы улучшить старые проекты angular 1 и подготовиться к миграции. Мне очень нравится тот факт, что у него есть дерево зависимостей, а не глобальный список «что может появиться в этом приложении».

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

@DaSchTour @damiandennis Я понимаю критику этой архитектуры, однако называть ее какой-то глобальной областью неточно, методология, которую они предлагают вам, заключается в том, чтобы иметь функциональные модули: https://angular.io/docs/ts /latest/guide/ngmodule.html#! #функциональные модули

@qdouble Ну, в конце концов, это просто замена всех компонентов на модули. Хотя это объявлено как изменение, направленное на сокращение стандартного кода, оно вводит множество необходимых шаблонов.

Хотя до RC4 было достаточно компонента для каждой «страницы»/представления приложения, знайте, что мне придется создать модуль, компонент и маршрутизацию для каждого представления. Я понимаю намерение. Но у меня почему-то сложилось впечатление, что он предназначен для облегчения некоторых вещей, не затрагивая многих других моментов. И даже с шаблоном функционального модуля мне приходится сокращать их до минимума, чтобы избежать ада зависимостей, добавляя все, что может понадобиться, потому что я не вижу, какая часть моего приложения нуждается в каких компонентах.

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

В конце концов, он не решает того, для чего был разработан, а только добавляет много работы. У меня такое ощущение, что здесь есть какое-то несоответствие между замыслом и реальностью.

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

@DaSchTour , если каждому отдельному компоненту нужна своя область, то да, это создаст больше шаблонов ... но я полагаю, что команда ng считает, что для большинства людей создание нового модуля для каждого раздела функций достаточно, и несколько компонентов смогут жить в каждом функциональном пространстве.

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

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

@qdouble шаблон проектирования прост. Он использует дерево зависимостей вместо перемещения зависимостей в глобальную область модуля. Я думаю, главное в том, что повторно используемые компоненты теперь должны быть модулями, даже если они очень маленькие и имеют очень небольшую функциональность. Angular material2 — очень хороший пример. Кнопка — это модуль, включающий один компонент. Возможно, это общее заблуждение многих разработчиков, что модуль — это нечто большее, чем просто кнопка. А теперь давайте подумаем еще на шаг. Просто следуя идеям из этой статьи https://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html , я обнаружил, что у меня есть много модулей, которые импортировать список модулей angular material2, и каждый из этих модулей состоит из одного компонента.
На самом деле это именно то, что делает angular material2.

Никто на самом деле не понимает, почему мы теперь должны обернуть «все» наши компоненты в модули. Или, может быть, мы должны рассматривать это как разделение декларации. Зависимости компонентов теперь представляют собой модуль, а определения компонентов остались прежними.

Я думаю, дело в том, что ngModules — это не просто приятное дополнение, облегчающее жизнь, но мы вынуждены все менять. Может быть, кто-то должен дать четкое объяснение, почему оба не могут сосуществовать.

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

Я нахожусь в том, что у меня есть много модулей, которые импортируют список модулей angular material2, и каждый из этих модулей состоит из одного компонента.

Для этого вы должны использовать общие модули: https://angular.io/docs/ts/latest/guide/ngmodule.html#! #общиймодуль

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

Я думаю, что критика удаления директив/каналов с областью действия компонентов совершенно справедлива. Тем не менее, я не думаю, что нужно делать вид, что для ngModules нет хороших шаблонов проектирования.

@qdouble Думаю, никто не сомневается, что для ngModules есть хорошие шаблоны проектирования. Но, насколько я понимаю, модули — это просто оболочка для набора компонентов, директивы и сервисы для их предоставления представляют собой единицу для приложения. Это верная и отличная идея. Но почему я должен определять зависимости (которые могут существовать только внутри модуля) для модуля, а не для компонента.

Беря пример с @choeller
Модуль TaskDashboard имеет следующие вещи

  1. Компонент списка задач
  2. Компонент задачи
  3. Компонент фильтра задач
  4. Служба задач

Компонент Taskitem необходим только внутри списка задач, а список задач зависит от компонента Taskitem. Taskfilter не нуждается в компоненте Taskitem. Теперь у меня нет Taskitem в качестве зависимости в списке задач. Следующим шагом является создание модуля TaskSearch. Я добавляю следующие вещи.

  1. Компонент списка задач
  2. Компонент поиска задач
  3. Служба задач

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

Хорошо, продолжая читать руководство по модулям, я нашел эту строку

Компоненты, директивы и каналы должны принадлежать ровно одному модулю.

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

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

@DaSchTour в вашем примере Taskitem должен быть частью модуля списка задач ... так что логически это будет два компонента в одном модуле, а не по одному для каждого.

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

@qdouble @DaSchTour Это правда, что новая архитектура не обязательно означает, что вы перечисляете все свои компоненты в одном файле, но, глядя на приложение, которое мы создаем, я в настоящее время в значительной степени согласен с этим утверждением @DaSchTour

У меня такое ощущение, что здесь есть какое-то несоответствие между замыслом и реальностью.

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

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

@DaSchTour , компонент кнопки в material2 привязан к модулю, чтобы сделать его автономным. Те, кому нужно использовать кнопку, могут импортировать ButtonsModule . Кроме того, если вы видите код модуля, он содержит два компонента MdButton и MdAnchor , затем обертывание в ButtonsModule упрощает использование.

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

@choeller Я согласен, что наличие модулей - хорошее дополнение, но удаление зависимостей на уровне компонентов кажется неправильным.

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

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

Это очень хорошо описано @kylecordes. NgModules помогает в хорошей композиции приложения. Небольшие повторно используемые модули составляют целое приложение.
Другое преимущество включает доступность директив в окружающей среде. Раньше мы добавляли ROUTER_DIRECTIVES во все приложение. Теперь RouterModule.forRoot() делает это за нас.
BrowserModule, CommonModule, FormsModule имеет больше смысла, чем включение директив в каждый компонент.

С другой стороны, MaterialModule предоставляет все, и если вам нужно более точное управление, нам помогут ButtonsModule и т. д.
В этом красота композиции. Примите это и создайте свою симфонию

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

@kylecordes

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

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

@sirajc

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

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

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

Есть кое-что, что можно сказать о возможности открыть любой данный компонент, взглянуть на его массив директив и точно узнать, от каких компонентов/директив он зависит. Будет ли более подробным импортировать компонент кнопки во все многочисленные компоненты, которые его используют? Да, но я бы предпочел иметь какой-то дополнительный шаблон и чтобы все было явным и сразу сканируемым, чем искать дерево компонентов/модулей, чтобы увидеть, как, черт возьми, компонент Y использует компонент X в своем шаблоне, даже не импортируя его.

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

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

Частью «жесткой продажи», которую команда ng2 должна была сделать сообществу из ng1, было «да, вам придется импортировать и объявлять свои директивы для каждого компонента, но поверьте нам, вы оцените более четкое по мере роста вашего приложения». Я большой сторонник того, чтобы страдать от небольшого повторения ради удобочитаемости и сканируемости в крупномасштабной командной среде, где член команды может работать только над очень небольшим подмножеством компонентов в любой момент времени.

По крайней мере, я не вижу причин, по которым ngModule и свойство directives/pipes не могут сосуществовать. Альтернативой является то, что каждый отдельный компонент в каждом отдельном приложении, написанном для ng2, вплоть до RC5, теперь использует устаревший код, который требует нетривиального рефакторинга. На самом деле это не те изменения, которых я ожидал на столь позднем этапе разработки... это, честно говоря, сбивает с толку.

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

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

Большинство приложений должны требовать от вас создания модуля для каждого отдельного компонента = недействительно (особенно если вы используете умные/глупые шаблоны компонентов и шаблоны функций)

Впервые сегодня я почувствовал усталость на стороне клиента/JavaScript, о которой мне рассказали некоторые коллеги. За последние несколько дней я потерял бессчетное количество часов, пытаясь реорганизовать наше приложение RC4 для использования новых модулей RC5.

Я определенно согласен с рядом мнений в этой ветке, особенно с тем, что разработчикам предоставляется выбор с точки зрения того, как они хотят структурировать зависимости своих компонентов. Мне не нравится, что более крупный ngModule разбавляет четкий график зависимостей между компонентами, а меньшие ngModules добавляют дополнительный шаблонный код к каждому компоненту. При анализе модуля все, что я знаю, это то, что по крайней мере один из компонентов, на которые ссылаются, нуждается в материалах из импорта модуля или одноуровневых объявлений. Если я разбиваю модуль на несколько других модулей, мне, по сути, приходится методом проб и ошибок определять, какие зависимости требуются для новых модулей (отчасти помогает тщательная проверка шаблона компонента).

Наконец, если я «забуду» экспортировать компоненты, мой компонент просто не отобразится, никаких ошибок не будет. Его легко найти, если у вас очень плоский модульный граф, и почти невозможно, когда у вас есть несколько уровней!

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

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

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

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

Каким будет следующее кардинальное изменение? Даже представить не могу, но боюсь, что кто-нибудь найдет способ внести очередное критическое изменение.

Из сообщения в блоге RC5:

Если вы вообще когда-либо писали код для Angular 2, вы, вероятно, спрашивали себя: «НО ПОЧЕМУ я должен перечислять все эти вещи!?» — особенно если вы заметили, что некоторые директивы и пайпы в Angular 2 являются «особыми» — они доступны для всего вашего приложения без каких-либо действий (например, *ngFor / *ngIf / *ngSwitch).

Лично я давно не видел, чтобы кто-то задавал этот вопрос. Вплоть до RC5 команда Angular, онлайн-ресурсы для обучения, книги и т. д. — все довольно ясно давали понять, зачем нужны эти декларации — и кажется, что все приняли (а некоторые приняли) этот факт давным-давно.

Что касается вопросов о том, почему некоторые из них являются «особыми» и не нуждаются в объявлении, я не думаю, что кто-то будет возражать против наличия списка критических, «низкоуровневых» директив, которые настолько вездесущи, что заслуживают «благословения». как глобально доступный держателем платформы (команда Angular).

Если код для обработки переноса директив в один модуль ngModule уже существует, и этот код работает незаметно для конечного пользователя, какой вред в разрешении обоих подходов? Это подлинный вопрос, поскольку я могу не знать о некоторых тонкостях, связанных с тем, что может произойти, если разработчик смешивает и сочетает подход. В Angular 2 есть много других «раздельных вариантов» — модель против форм, управляемых шаблоном, 3 разных варианта языка, декораторы ввода/вывода/хоста против подхода свойств — какой вред в другом на данный момент?

Я мог бы продолжать, но я хочу подчеркнуть, что команда и сообщество Angular потратили довольно много времени, чтобы донести мысль о том, что быть более явным — это _хорошо_, только для того, чтобы вмешаться — в _release. кандидат 5_ всех времен -- чтобы представить нам решение, которое не было проблемой в течение достаточно долгого времени.

Есть желающие присоединиться к команде? Я не хочу, чтобы это превратилось в эхо-камеру — я хотел бы услышать другую сторону аргумента. Просто кажется, что что-то настолько большое появилось из ниоткуда, не принимая во внимание такие вещи, как инструменты, обучение или то, насколько мы близки к финальному релизу.

Это обсуждение подняло очень большую проблему для многих разработчиков, которые хотели начать разработку как можно раньше с долгожданным Angular 2: критические изменения. Я сделал кучу доказательств концепции, основанной на angular 2, начиная с бета-версии 17, и заставил важные компании и организации принять ее. Я не жалею, но и не уверен, что поступил хорошо. Одним из самых последних проектов был POC, и битва велась против Vue.js. Angular 2 явно выиграл этот бой. Но сегодня, со всем переписыванием кода, критическими изменениями, выпуском не совсем RC, люди начинают преследовать меня, и это становится довольно серьезно. Это было бы не так, если бы я предложил разработку Vue или React, и это очень расстраивает из-за дискредитации, которую Angular 2 может поставить людям.

Мне очень кажется, что я не разделяю то же определение релиз-кандидата, что и команда Angular.

Что касается темы, NgModule, я полностью поддерживаю @jpsfs , если вам нужно перечислить все ваши компоненты и микрокомпоненты в объявлении вашего модуля, вам лучше иметь где-нибудь функцию prune или быть король моделирования, потому что он может быть мощным, но слишком чувствительным для крупномасштабных проектов...

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

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

(Конечно, я также разделяю разочарование с другими здесь такими значительными изменениями на этапе «RC» ... Я уверен, что основная команда также, если бы им пришлось все переделывать, атаковала бы на высоком уровне модульность и движущие силы (ленивая загрузка, предварительная компиляция) гораздо ближе к началу проекта, а не к стадии релиз-кандидата.Но такова жизнь, всегда легко оглянуться назад и подумать: «Ну, если мы знали тогда то, что мы знаем сейчас...")

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

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

Я мог бы возразить, что вместо использования модулей мы могли бы использовать компоненты как единицы приложения. Это, вероятно, то, что люди делали до rc-5 в любом случае.

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

Когда я впервые увидел angular2, я подумал: «Эй, с этим они идут в правильном направлении, похоже, они чему-то научились у angular 1». Вы убрали внутренние модули из angular 1 и вместо них использовали модули ES, другие изменения также приветствовались (компоненты, машинописный текст и т. д.)

Но чем больше я жду, пока это станет стабильным, тем больше я съеживаюсь из-за критических изменений, отсутствия документации и плохих сообщений об ошибках. Теперь вы приходите с этим NgModules и в основном отменяете по крайней мере одну замечательную вещь, которую вы изменили с момента angular 1.

Еще хуже, если у меня есть приложение, которое начиналось с rc-2 или 3 (которые теоретически были почти стабильны), мне теперь нужно проделать большую работу, чтобы создать хорошее приложение angular2 rc-5, и нужно как-то объяснить клиенту и другим разработчики это. И даже если я это сделаю, Бог знает, что вы измените дальше, и моя работа могла быть напрасной.

Я знаю, что angular 2 уже некоторое время находится на ранней стадии, но мы RC-5, у людей уже есть довольно солидные проекты, использующие Angular 2, и вы все еще вносите изменения, не только ломая с точки зрения API, но ломая как способ мышления в Angular.

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

В любом случае, как видите, многие люди согласны с тем, что я должен сказать, а некоторые еще злее. У вас есть огромный фреймворк, которому люди доверяют (в основном, потому что Google), но вы не можете поставить на него все, иначе у вас может быть сюрприз, поскольку у каждого есть выбор (а когда речь идет о JS, их МНОГО).

Если новый модуль будет иметь шаблон, это может быть компонент. Подумай об этом.

Следующим шагом будет перемещение всех переменных и функций из компонентов в класс модуля. Шутки в сторону. Затем у нас была огромная центральная библиотека _всех возможных_ действий в нашем блестящем модуле. Это было бы здорово! Я не знаю, почему вы остановились на централизации объявлений и зависимостей. Там гораздо больше децентрализованных, структурированных строк кода!

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

@mhevery

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

  • Мне пришлось изменить селектор компонента с класса на элемент, потому что в совершенно не связанном компоненте этот класс используется для стиля и внезапно начал создавать экземпляр компонента.
  • Я почти уверен, что #10850 существует только потому, что у меня было два компонента с именами SpectrumComponent (одна целая страница для перехода без селектора и один «общий» компонент, используемый в нескольких компонентах для визуализации с селектором). Подъем, вероятно, запутается из-за этого - объявления directives: - нет.

Для моих компонентов SVG это теперь становится более серьезной проблемой, потому что я не могу использовать там пользовательский элемент. Я еще не знаю, как определить их область видимости, чтобы убедиться, что их селекторы классов не запускают создание экземпляра компонента где-либо еще (!) в приложении.

Кажется, в наши дни стало модным игнорировать значения «бета» и «релиз-кандидат» (другим известным примером является ASP.NET Core) в крупных проектах. Но столкновение с критическими изменениями, которые могут незаметно сломать приложение буквально в любом месте, расстраивает больше, чем должно быть. Я действительно надеюсь, что обещания, связанные с этими изменениями, скоро принесут свои плоды.

ngModules имеет смысл. Удаление возможности объявлять/предоставлять на уровне компонентов не работает.

Небольшой пример

У меня есть приложение, содержащее несколько разных диалогов (несколько простых — назовем их простыми-1 и простыми-2, и одно сложное, содержащее другие компоненты — назовем его сложным 3).

На данный момент у меня простая структура папок (очевидно, что приложение находится вне этого)

- dialogs
   - simple-1 (containing single component and template for simple-1 dialog)
   - simple-2 (containing single component and template for simple-2 dialog)
   - complex-3 (contains the main complex-3 component plus a number of other internal components)
      - internal-component-1
      - internal-component-2
      - internal-service-3

Для меня это идеальный набор функций для включения в изолированный функциональный модуль. Поэтому я добавляю

   dialogs.module.ts
   - simple-1
   - simple-2
   - complex-3
      - internal-component-1
      - internal-component-2
      - internal-service-3

И я добавляю Simple1Component, Simple2Component и Complex3Component в качестве объявлений в DialogsModule. Идеально, работает хорошо и имеет смысл.

Но...

А как насчет всех этих внутренних компонентов в комплексе-3. теперь у меня есть два варианта

  • Добавьте все внешние сложные компоненты и сервисы в DialogsModule. Это плохое решение, потому что оно нарушает инкапсуляцию комплекса-3, потому что теперь все в модуле диалогов знает о его внутренностях (внутренний-компонент-1, внутренний-компонент-2, внутренний-сервис-3)
  • Сделайте комплекс-3 самостоятельным модулем. Это устраняет проблему с областью действия (и я считаю, что могу экспортировать модули из другого модуля, поэтому клиенту нужно только импортировать модуль-оболочку), но теперь у меня остается смесь компонентов и модулей для похожих групп (диалогов).

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

Единственным разумным/очевидным/обслуживаемым решением для меня было бы использовать модуль для экспорта компонентов верхнего уровня (простой-1, простой-2, сложный-3), но пусть сложный-3 _component_ сам определяет свои собственные внутренние компоненты.

/ копия: @robwormald

Я думал о том, что @kylecordes сказал ранее об использовании существующей системы модулей Typescript для определения коллекций кода Courser Grain, а не о добавлении новой вещи ngModules. Я хотел бы представить на рассмотрение пример, в котором модули Typescript используются для определения ngModules в режиме 1-к-1. Комментарии и мысли приветствуются.

https://github.com/jbalbes/autoNgModule

10901

Возможно, я что-то упустил, но то, как внедрение зависимостей работает с модулями без ленивой загрузки, может стать большой проблемой для «крупных проектов» (мой — нет, и он уже страдает).

это интересно. у нас уже есть корпоративное приложение на Angular1. и мы используем requirejs для определения пакетов для различных модулей (каждый модуль содержит 10-20 директив/сервисов/фильтров). мы объединяем эти пакеты в один файл для производства (кроме основных директив). директивы лениво загружаются в приложение, когда они используются (у нас есть основная директива, которая лениво загружает необходимые директивы).

наши шаблоны страниц маршрутизации приложений размещены в приложении cms, и пользователи cms могут перетаскивать виджеты пользовательского интерфейса на основе основной директивы между различными шаблонами страниц (именно поэтому нам нужна поддержка ленивой загрузки для директивы, чтобы уменьшить размер основного файла сценария при загрузке браузера как большая часть нашего приложения основана на виджетах, основанных на директивах)

Angular1 позволяет лениво загружать директивы в модуль, получая ссылку на регистрацию провайдеров.
возможен ли такой тип ленивой загрузки компонентов в модуль и их компиляция в Angular2?

Я согласен с тем, что другие предположили, что ngModules - это решение проблемы. Потенциальная польза от LazyLoading, на мой взгляд, не оправдывает принудительное устаревание зависимостей директив/каналов компонентов. Возможно, я ошибаюсь здесь, но я чувствую, что большинство приложений не увидят никакой реализованной выгоды от отложенной загрузки, которая для меня является единственным реальным преимуществом, предоставляемым ngModules вообще.

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

Кроме того, действительно ли нам нужна еще одна модульная система?

Никто не может спорить с тем, что NgModule добавляет новые вещи, с которыми нам раньше не приходилось иметь дело. И я, как и все остальные, ценю простоту до RC5, особенно очень маленьких программ, которые были утеряны. Я также очень скучаю по возможности рассказать людям, что в Angular 1 была собственная модульная система, но в Angular 2 мы просто используем модульную систему базового языка. Упс.

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

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

Проблема @kylecordes с именем https://github.com/angular/angular/issues/10087

Не будет ли представленная там логика также исключать использование слова «модуль», поскольку оно противоречит такому же количеству, если не большему количеству понятий?

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

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

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

Когда я впервые увидел angular2, я подумал: «Эй, с этим они идут в правильном направлении, похоже, они чему-то научились у angular 1». Вы убрали внутренние модули из angular 1 и вместо них использовали модули ES, другие изменения также приветствовались (компоненты, машинописный текст и т. д.)

Но чем больше я жду, пока это станет стабильным, тем больше я съеживаюсь из-за критических изменений, отсутствия документации и плохих сообщений об ошибках. Теперь вы приходите с этим NgModules и в основном отменяете по крайней мере одну замечательную вещь, которую вы изменили с момента angular 1.

Действительно, предполагалось, что Angular 2 будет использовать богатый развивающийся стек веб-технологий, который не был доступен, когда разрабатывался AngularJS. Тем не менее, несмотря на то, что многие дизайнерские решения, принятые для Angular 2, объяснялись тем, что «веб-компоненты должны поддерживаться», по иронии судьбы, фреймворк все больше отклоняется от стандартов. Теперь есть веские причины отклоняться от стандарта, когда стандарты плохие.

Я чувствую, что фреймворк не использует свои основные инструменты в полной мере. Например, объявления TypeScript не совсем идиоматичны и изобилуют any и any[] . Они также игнорируют мощные языковые функции, которые улучшают удобство использования и инструментальность API. Они также содержат отвратительные вещи, такие как export declare type Type = Function .

Интересно, что довольно большое количество решений оказалось связанным с Dart. Dart — это не то, что волнует большинство пользователей Angular. У него совершенно другое представление о типах и способах их использования по сравнению с TypeScript. Взаимодействие Dart <-> JavaScript часто не является стартовым.

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

Это изменение значительно усложнило как общий LOC, так и мысленное моделирование зависимостей компонентов. Мои файлы компонентов немного чище, но за счет явного и определения зависимостей на месте, и к ним добавлены избыточные файлы .module.

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

Я думаю, что angular стремится к более сложным и сложным быстрым стартам. Уже есть с чем разобраться в плане настройки цепочки инструментов, и список файлов и вещей, которые необходимо понимать (если кто-то хочет придерживаться лучших практик) даже для самого простого приложения, растет.

. @jbalbes спасибо, приятно это слышать.

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

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

Я не думаю, что все последствия для разработки приложений по сравнению с «заставить другие обещанные функции работать» были на повестке дня, когда они были добавлены, но по мере того, как все больше и больше приложений конвертируются в RC5, они начинают становиться яснее.

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

Gang, NgModule вызывает раздражение, как красноречиво объяснили многие. Но практически это не так уж и важно. Здесь (Oasis Digital / Angular Boot Camp) мы уже обновили множество мелких вещей и несколько не очень мелких до RC5, и это было сделано за короткое время (после долгого изучения и понимания).

Приложение каждого будет затронуто по-разному. Кроме того, я думаю, что ваше отношение к оттоку и изменениям в Angular 2, возможно, будет другим, если вы сосредоточены на выпуске приложения, по сравнению с тем, если вы также продаете обучение и поддержку для Angular 2. Для меня вся работа по обновлению до RC5 будет быть полностью мертвым и потраченным впустую усилием - это на самом деле принесло бы отрицательные выгоды (большие пакеты), поэтому его трудно оправдать.

Просто решил изложить свои мысли об обратной стороне пятидневной работы над нашей платформой, чтобы добраться до RC6* (у нас ночные клубы, RC6 технически еще не упал на момент написания статьи). Я чувствую, что, хотя мои первоначальные комментарии все еще актуальны, я чувствую облегчение от того, что достиг этой вехи. Самые большие проблемы по-прежнему связаны с использованием нового синтаксиса маршрутизации — слишком много пустых правил path: '' ! (Я отвлекся), но это то, что мы, вероятно, абстрагируемся.

Что касается NgModules на ночных сборах, я должен сказать, что сообщения об ошибках становятся лучше, что делает весь процесс немного проще в работе. Компоненты и директивы обычно вызываются, когда они неправильно настроены с достаточным количеством информации, чтобы вы не просматривали массивное дерево зависимостей NgModule, чтобы найти проблему. Основная проблема, с которой мы столкнулись сейчас, — это просто отсутствие функциональности на страницах без очевидных сообщений об ошибках. Обычно это происходит из-за неправильного объявления или импорта/экспорта компонента. Это немного сложно, но с образованием с этим достаточно легко справиться. Тестирование — теперь наш следующий шаг, он полностью мертв в воде. Но, как и в случае с функциональным толчком, мы доберемся до него в конце концов.

Мы глубоко вздохнули, несколько дней занимались чем-то другим, а потом сломали его. Мы держимся за следующую поездку, какой бы она ни была! Удачи всем, кого это коснулось в той или иной степени. Было бы неплохо получить какой-то диалог от команды Angular по этому поводу. Самой сложной проблемой, с которой мы столкнулись, было отсутствие связи. Мы до сих пор не знаем, что ждет NgModules. Заметки о собрании на прошлой неделе не дали никакой информации. Посмотрим, что будет на этой неделе!

@SaltyDH Я думаю, что это ценный отзыв.
Считаю претензии к общению не совсем уместными.

Специалисты по реализации создают новую версию, а специалисты по документации обновляют документы.
Документы обычно несколько отстают по понятным причинам, потому что они могут документировать только после того, как он уже был закодирован. Написание документов также является тяжелой и трудоемкой работой.

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

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

Я полностью согласен с тем, что это проще в мастер-сборке (почти RC6), поскольку последний год+ устаревания наконец-то уходит.

@kylecordes как с мастером становится легче работать?

Дизайн-документ для NgModules (ранее известный как AppModules, когда был написан дизайн-документ) был выпущен более месяца назад до выпуска RC5, и я был как бы готов к его появлению.
Более того, поскольку NgModule был более новой концепцией, было трудно полностью охватить его и перенести ваше среднее приложение в большое.
Вместо этого я сначала полностью понял нюансы NgModules и как думать в NgModules для разработки приложения Angular 2. Затем создал самообучающееся приложение с применением NgModules.
Второй шаг — подумайте, как текущее приложение можно разбить на модули, а затем перенести их сверху вниз. создание одного модуля за раз, начиная с AppModule. Это действительно помогло, и окончательное приложение выглядит более организованным.
image

И да, Gitter действительно помог, предоставив помощь по NgModule еще до того, как был выпущен RC5. После RC5 у нас есть документы и блоги, чтобы мы могли лучше учиться.

@zoechi Не слишком отвлекая эту дискуссию, я чувствую, что должен пояснить свои комментарии. Я вообще не имел в виду документацию, большую часть своего понимания я получил, просматривая коммиты и проблемы здесь, на GitHub, меня это устраивает. Мое разочарование вызвано отсутствием представительства здесь, в этом выпуске, у нас 61 комментарий, и их число продолжает расти. Простой: «Мы понимаем, что все обеспокоены этим вопросом, мы искренне верим, что это лучший подход для Angular 2, и мы осознаем трудности, которые он вызовет, но это лучше для будущего продукта». Gitter великолепен, но отдельные сообщения часто теряются в море людей, пытающихся понять различные аспекты Angular 2. Я обращался через эту среду, но из-за разницы в часовых поясах или других приоритетов я не смог получить авторитетный отзыв. может использовать для принятия обоснованного решения. Что действительно помогло, так это подкаст Adventures in angular https://devchat.tv/adv-in-angular/106-aia-angular2-rc5-and-beyond. Это придало мне уверенности в том, что я буду продвигать обновления NgModule.

Всего наилучшего.

Всем спасибо за отзывы, приносим извинения за то, что так долго не могли получить ответ - мы были очень заняты на прошлой неделе (перенос внутренних приложений Google на NgModules, поэтому мы тоже чувствуем боль от рефакторинга)

Позвольте мне посмотреть, смогу ли я прояснить некоторые вопросы и неправильные представления здесь.

Первое, что нужно понять о @NgModule() (а также @Component и любом другом декораторе Angukar), это то, что они являются конструкцией исключительно времени компиляции - они существуют, чтобы позволить компилятору angular обнаруживать граф зависимостей в приложении.

(Упрощенная) версия того, что делают наши декораторы, выглядит так:

//simplified Component decorator
export function Component(componentConfig){
  return function(componentClass){
    Reflect.defineMetadata('annotations', componentConfig, componentClass);
  }
}

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

В режиме JiT это происходит «как раз вовремя» — между вызовом bootstrapModule и рендерингом вашего первого компонента компилятор Angular извлекает метаданные, прикрепленные к классам, с помощью Reflect API:

let metadata = Reflect.getOwnMetadata('annotations', componentClass);

Однако в режиме AoT это работает немного по-другому — во время сборки мы _статически_ (то есть без выполнения вашего кода) извлекаем одни и те же метаданные из исходного кода, сканируя декораторы.

Это работает нормально, когда вы загружаете один компонент, но мы слышали много отзывов от разработчиков, которые делают более сложные вещи — загружают несколько корневых компонентов или загружают разные компоненты на основе статуса аутентификации и т. д.

Таким образом, в то время как декораторы @Component давали нам возможность статически анализировать компонент, у нас не было возможности надежного статического анализа _приложения_.

Вещи, которые попадают под зонтик «приложения»

  • PLATFORM_DIRECTIVES/PIPES/PROVIDERS
  • вещи, которые вы ранее добавили в bootstrap()
  • настройки уровня компилятора
  • несколько корневых компонентов
  • использование на стороне сервера.

NgModules представляет идею статически анализируемого набора функций. Что интересно, в режиме компиляции AoT мы анализируем ваш корневой модуль и _генерируем_ ModuleFactory для каждого модуля в приложении — это предварительно скомпилированная версия модуля, которая содержит _только_ фабрики, на которые вы статически ссылаетесь в шаблонах, и те, которые вы пометить как "entryComponents"

Поскольку мы уже извлекли информацию, необходимую для компиляции заблаговременно, мы можем на самом деле вытряхнуть декораторы из дерева (ngc сделает это автоматически для финала) — и вместо того, чтобы связывать ваше приложение, начиная с вашего корневого модуля, вы начинаете в сгенерированном вами корневом Module_Factory_, который содержит только тот код, который фактически используется в вашем приложении, поэтому вы не платите штраф за модульность, а такие инструменты, как rollup и webpack2, могут работать _более_ эффективно

дальше в следующем ответе...

@robwormald Я не могу выразить смайликом всю признательность за такую ​​справочную информацию.

Спасибо!

Еще одна проблема, с которой мы столкнулись, которую решает NgModules:

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

Исторически вы бы сделали что-то вроде:

@Injectable()
export class MyDialogService {
  //inject the dynamic compiler 
  constructor(private componentResolver:ComponentResolver){}

  //accept a component and a viewContainerRef
  showDialog(component:Type, target:ViewContainerRef){
    //compile the component into a factory, async
    return this.componentResolver.resolveComponent(component)
      .then(componentFactory => {
         //dynamically insert the compiled componentFactory into the view:
        return target.createComponent(componentFactory);
      })
  }
}

... который вы бы использовали как

myDialogService.showDialog(MyRandomDialogComponent).then(...)

На что здесь обратить внимание -

  • компиляция компонента в режиме JiT _должна_ быть асинхронной из-за внешних templateUrls и styleUrls
  • a viewContainer принимает _componentFactory_, поэтому теперь у вашего кода есть проблема: вам либо нужно переписать код для переключения режимов (между JiT и AoT), либо вы всегда должны предполагать, что API вставки компонентов является асинхронным. Это может быть нормально в случае диалога, но если вы создаете сложные пользовательские интерфейсы динамически (например, Dashboard или Grid View или что-то еще), вы подвергаетесь огромному количеству ненужного планирования Promise.
  • Сторонние или общие службы/компоненты (например, SharedDialogService) имеют ту же проблему, что и должны принимать _либо_ компоненты, либо ComponentFactories.

Эта проблема возникает для _любого_ приложения, выполняющего динамическую вставку компонентов (это не обязательно означает ленивую загрузку) - диалоги, маршрутизаторы и т. д., все ожидают взаимодействия с ComponentTypes (классами) вместо селекторов (foo-bar).

Итак, когда вы добавляете компонент в свой массив entryComponents в декораторе NgModule:

@NgModule({
  declarations: [ MyRandomDialogComponent ],
  entryComponents: [ MyRandomDialogComponent ]  
})
export class MyApp {}

Это говорит компилятору: «создайте мне сопоставление между MyRandomDialogComponent и его скомпилированным MyRandomDialogComponentNgFactory» и _сохраните его в NgModuleFactory, в котором он объявлен_

Таким образом, версия вышеприведенного диалогового сервиса, управляемая NgModule, выглядит так:

@Injectable()
export class MyDialogService {
  //inject the component factory resolver 
  constructor(private componentFactoryResolver:ComponentFactoryResolver){}

  //accept a component and a viewContainerRef
  showDialog(component:Type, target:ViewContainerRef){
    //*retrieve* the componentFactory by component, sync
   let componentFactory = this.componentFactoryResolver.resolveComponentFactory(component)
   //add the componentFactory to the view, sync
   return target.createComponent(componentFactory);
  }
}

Теперь любой компонент, который вы добавили в entryModules, может быть синхронно извлечен и динамически вставлен в представление, и ваш код _не_ должен изменяться в зависимости от того, в каком режиме вы находитесь, и при этом сторонние/общие библиотеки не должны беспокоиться о компиляции. логика.

Спасибо за объяснение @robwormald

Один вопрос: требует ли это удаления объявлений директив/каналов? Есть ли причина, по которой они не могут сосуществовать с NgModule?

Я чувствую, что люди, в том числе и я, разочарованы не «новичком в блоке» NgModule или каким-либо непониманием его, а тем, что «старый способ» ведения дел, который, кажется, _работает хорошо_ со многими людьми, принудительно удалены, особенно на этой поздней стадии RC. Я думаю, что это важное отличие от любого сопротивления самому NgModule, которого я не видел, и которое еще не было рассмотрено напрямую.

Я также вижу, что запрос на удаление объявлений директив/каналов запущен (https://github.com/angular/angular/pull/10912). Я надеюсь, что мы сможем получить ответ по этому вопросу до того, как что-либо будет установлено. камень.

Заранее спасибо. С Angular, несомненно, было приятно работать, и я очень ценю тяжелую работу команды за последний год+.

Здесь есть несколько комментариев относительно "глобальной области действия" - это неправильно понимает механику компилятора и модулей (что вполне понятно, это сложный материал).

Сброс всего вашего приложения в один NgModule — это «хорошо», так же как сброс всего состояния вашего приложения на $ rootScope был «хорошим» в Angular1 (читай: это работает, но его плохой дизайн приложения)

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

В Angular2 у NgModues есть несколько очень мощных механизмов области видимости, которые позволяют компоновать без загрязнения. Опять же, это возвращается к компилятору.

Когда Angular просматривает и компилирует ваше приложение, каждый компонент, с которым он сталкивается, _компилируется в том контексте, в котором он был объявлен_

Например, представьте, что у вас есть SharedModule с некоторыми функциями, которыми вы хотите поделиться в приложении.

@Component({
  selector: 'shared-component-one',
  template: `
    <div>Shared Component One</div>
    <shared-component-two>
  `
})
export class SharedComponentOne {}

@Component({
  selector: 'shared-component-two',
  template: `
    <div>Shared Component Two</div>
  `
})
export class SharedComponentTwo {}

@NgModule({
  declarations: [ SharedComponentOne, SharedComponentTwo ],
  exports: [ SharedComponentOne ]
})
export class SharedModule {}

И SharedComponentOne, и SharedComponentTwo _объявлены_ в SharedModule — объявления подразумевают _ownership_ — поэтому оба этих компонента принадлежат SharedModule. Однако _только_ SharedComponentOne _экспортируется_ из модуля, а SharedComponentTwo остается _приватным_ для SharedModule.

Если бы вы ввели SharedModule и использовали его в другом модуле, например:

@Component({
  selector: 'some-component',
  template: `
    <div>hello from some component</div>
    <shared-component-one></shared-component-one>
  `
})
export class SomeComponent {}

@NgModule({
  imports: [ SharedModule ],
  declarations: [ SomeComponent ]
})
export class SomeModule {}

... когда компилятор начинает компилировать SomeComponent , он обнаруживает селектор shared-component-one , и поскольку SharedModule (который экспортирует SharedComponentOne ) импортируется в SomeModule , он знает, что shared-component-one === SharedComponentOne.

Интересно, что когда компилятор на самом деле компилирует SharedComponentOne, он делает это «внутри» SharedModule, что позволяет ему использовать внутри SharedModule то, что недоступно внешнему миру.

Это очень похоже на то, как это работало с Component.directives, и в этом случае они равны.

Подумайте, если бы у вас было что-то вроде функции вкладок:

@Component({
  selector: 'my-tabs',
  template: '...'
})
export class TabsComponent {}

@Component({
  selector: 'my-tab',
  template: '...'
})
export class TabComponent {}

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

export const TAB_DIRECTIVES = [ TabsComponent, TabComponent ]

Более сложная функция вкладок может иметь службу, которая управляет несколькими экземплярами вкладок, поэтому вам также нужно обработать этот случай...

export const TAB_PROVIDERS = [ ... ]

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

import {TAB_DIRECTIVES, TAB_PROVIDERS}

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

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

Для таких библиотек, как Material Design, которые могут иметь ряд функций, распределенных по нескольким модулям, вы можете использовать ту же семантику импорта/экспорта, чтобы сделать ее еще более переносимой:

@NgModule({
  exports: [ TabsModule, NavbarModule ]
})
export class MaterialSharedModule {}

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

Что касается того, почему мы удалили Component.directives/pipe, мы слышали много отзывов в обоих направлениях. Нам кажется, что наличие двух способов выполнения одной и той же задачи, как правило, является плохим шаблоном, поэтому мы сделали выбор в пользу того, чтобы люди могли писать меньше кода, а те, кому нужна явная область видимости, ранее предлагаемая Component.directives, могут выполнить _same_ функциональность с помощью определение области видимости на уровне модуля.

В RC5 мы сделали что-то вроде автоматического подъема Component.directives в «глобальную» область. Это была попытка сгладить переход, и, хотя это сработало для большинства людей, смешанное старое и новое поведение вызвало некоторые странные ошибки и поведение, которое, хотя и разочаровывает, носит временный характер. Это исчезло в RC6 (и сообщения об ошибках были улучшены).

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

Спасибо всем за терпение. Я оставлю это открытым, если есть другие вопросы, которые я здесь не затронул.

Роб

Хорошая работа, @robwormald

Хочу добавить еще несколько наблюдений:

Провайдеры

Роб сосредоточился на _декларациях_, _импорте_ и _экспорте_. Модуль _Providers_ отличается.

@Component.providers жизней! Уходят только @Component.directives и @Component.pipes .

Вы можете использовать как @NgModules.providers , так и @Component.providers . У них разное назначение:

a) @NgModules.providers _расширяет_ приложение, добавляя провайдеров к "главному" инжектору (корневому инжектору приложения для быстро загружаемых модулей). Вот как RouterModule добавляет службу маршрутизации в ваше приложение без необходимости ее предоставления.

b) @Component.providers _инкапсулирует_ предоставление услуг в рамках экземпляра компонента (и его поддерева компонентов).

Оба подхода удовлетворяют различные потребности.

Мой общий совет: _если у вас сегодня есть провайдер на @Component , оставьте его там_

Модули функций

Это мощный способ организовать ваше приложение. В главе «Модуль Angular» есть небольшой раздел о рефакторинге монолитного модуля Angular в функциональный модуль . Это довольно легко (по крайней мере, это было для меня несколько раз, когда я это делал).

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

Причина, по которой Material Design делает это, заключается в том, что они пытаются облегчить нам использование того, что мы хотим, в тонком виде.

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

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

Обнаружение зависимостей объявлений

Теперь компилятор намного лучше сообщает вам, когда чего-то не хватает. Если вы будете следовать рекомендуемой практике и _всегда, всегда, всегда писать через дефис_ имена селекторов компонентов, компилятор сообщит вам, когда у вас есть необъявленный компонент. Он также собирает необъявленные/нераспознанные привязки данных и директивы.

Миграция с версии pre-RC5 вызывает чувство потери. Нам предстоит проделать утомительную работу по обнаружению зависимостей в наших предыдущих списках directives и pipes . И мы должны де-обманывать. Это существенная неприятность жизни на грани.

RC не должен так сильно меняться

Ага. Вы не получите аргумент от команды по этому поводу. Это было непреднамеренно. Если бы мы знали, что нам нужно NgModule , у нас была бы бета-версия.

Но IMO, лучше поставить правильный продукт, чем рабски следовать некоторым представлениям о том, каким должен быть RC, и поставить неправильный продукт. Кроме того... и это не очень удобно говорить... но если вы недавно наблюдали за некоторыми другими крупными компаниями-разработчиками программного обеспечения, вы, возможно, заметили столь же гибкое понятие "кандидат на выпуск". По какой-то причине наша индустрия идет именно так.

Сейчас я преобразовал несколько приложений и помог другим сделать это. После того, как этап «_они перенесли мой сыр (снова)_», это довольно механическая миграция, и все, кажется, думают, что они в лучшем месте. Может быть, они просто добры ко мне. ОТО, я не тусуюсь с такими милыми людьми ;-)

(также, относительно: имя)
Мы забраковали имена до смерти. Первоначально они назывались AppModules (поскольку они описывают нечто более высокого уровня, чем компонент, «приложение»), но это был недостаточно широкий термин. Пакеты, связки, бочки, шарики и т.д.

Имейте в виду, что это не замена модулям ES — это дополнение, которое позволит встряхиванию дерева и модулям ES работать лучше для всех разработчиков angular, и семантически они похожи на то, как работают модули ES (импорт, экспорт, объявления).

Итак, назвать сложно. NgModule это.

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

Искренне благодарим @robwormald @wardbell за очень проницательные комментарии. Я думаю, что для меня самое большое облегчение

«Мы закончили разработку API для версии 2.0.0, и поэтому мы будем наблюдать в течение следующих нескольких месяцев после выпуска, чтобы увидеть, какие закономерности развиваются, и где мы можем подсластить и сделать более точные выводы для версии 2.1».

Это то, что мы уже слышали несколько недель назад, но теперь это конкретно в контексте NgModules вместе со всеми этими отзывами. Мне нужна была уверенность, чтобы пойти к совету и сказать. На этом мы закончили, пора закончить создание нашего приложения. Я также хочу поздравить всю команду и сообщество ng2 с достижением этого рубежа! Захватывающие времена впереди.

Я искренне верю, что вы можете сказать, что @SaltyDH. Отток Angular 2 завершен.

Это не означает, что Angular 2 закончил развиваться. Будут выпуски в будущем. Но отток, ведущий к 2.0... закончился!

Большое спасибо за честность и явные варианты использования, ребята. Это действительно помогает.

Просто кратко об именовании и дублировании в API для NgModule, что мне кажется немного громоздким.

ИМО это:

@NgModule({
  declarations: [ SharedComponentOne, SharedComponentTwo ],
  exports: [ SharedComponentOne ]
})
export class SharedModule {}

... может быть более ясным и кратким, как:

@NgModule({
  private: [ SharedComponentTwo ],
  public: [ SharedComponentOne ]
})
export class SharedModule {}

1) WRT к именованию (общедоступное и приватное против объявлений и экспорта), по сути, это то, как @robwormald выше, и я уверен, что многие другие объясняют это.

2) (игнорируя имена) зачем повторять SharedComponentOne ? Конечно, вы могли бы сказать, что если это «экспорт», то это должна быть «декларация», поэтому его можно было бы просто обезжирить таким образом?

Просто мои два цента на что-то очень субъективное 😄 - еще раз спасибо за подробные объяснения!

@robwormald @wardbell Спасибо за подробные объяснения.

И, как я уже говорил ранее в этой теме, NgModules помогают нам лучше организоваться. Недавний пример — создание директив валидатора для форм на основе шаблонов. До RC5 нам приходилось импортировать каждую директиву в компонент, где мы создаем форму. Теперь мы просто упаковываем его в VaildatorModule и импортируем модуль куда нужно. Любой валидатор, который мы добавим позже, автоматически станет доступным для модулей, в которые я импортировал ValidatorModule . Мне просто нужно обновить шаблон, не беспокоясь о зависимостях.

@JamesHenry declarations , imports и exports используются для того, чтобы NgModules соответствовали модулям ES6, как мы import , export и declare в модулях ES6.
Я согласен с засахариванием, вещи, которые экспортируются, могут быть автоматически волшебным образом де-засахарены в декларации.

@ДжеймсГенри

1), мы остановились на импорте/экспорте, потому что ментальная модель ближе к тому, как работают модули es (по крайней мере, с точки зрения области видимости) — вы объявляете вещи в модуле, импортируете вещи из других модулей и экспортируете вещи, чтобы сделать их доступными для другие.

2) if it is an "export" it must be a declaration, so it could just be desugared that way? -> это работает до тех пор, пока вы не используете ngModule для реэкспорта, как в приведенном выше примере MaterialModule — есть много случаев, когда вы можете использовать ngModule для реэкспорта чего-либо, объявленного в другом модуле, и тогда выводы как бы разваливаются.

@robwormald Отличные комментарии! определенно заслуживают записи в блоге.

У меня есть диалоговая библиотека , которая теперь использует @NgModule , и я могу сказать, что вижу, как пользователи борются, пытаясь добавить пользовательские компоненты, поскольку они забывают зарегистрировать их в entryComponents , это, по-видимому, недостаточно ясно, но понятно, так как это расширенная функция...

Я уверен, что это утонет со временем

@shlomiassaf спасибо!

Следует также упомянуть, для таких случаев, как ваш:

Обратите внимание, что когда вы используете маршрутизатор angular, вы добавляете компоненты в объявления и конфигурацию маршрута, но _не_ в entryComponents, несмотря на то, что маршрутизатор является самим определением entryComponents. (помните - entryComponent === вещь, на которую вы хотите ссылаться по классу, а не по селектору)

Есть крутой трюк, которым может воспользоваться любая библиотека — есть волшебный токен под названием ANALYZE_FOR_ENTRY_COMPONENTS — см. https://github.com/angular/angular/blob/master/modules/%40angular/router/src/ router_module.ts#L117 для того, как его использует маршрутизатор.

Итак, для библиотек, которые имеют дело с динамически вставляемыми компонентами, вы можете сделать что-то вроде:

@NgModule({
  providers: [ DialogService ]
})
export class DialogModule {
  static withComponents(componentList): NgModuleWithProviders {
    return {
      ngModule: DialogModule,
      providers : [
         { provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: componentList, multi: true }
      ]
     }
  }
}

используется как

@NgModule({
  declarations: [ MyConfirmDialog, MyQuestionDialog ],
  imports: [
    DialogModule.withComponents([ MyConfirmDialog, MyQuestionDialog ])
  ]
})
export class MyAppModule {}

Может работать для вашего варианта использования, а может и нет.

@JamesHenry Очень важно, чтобы declarations не путали с private . Вы говорите, что _Этот модуль объявляет этот компонент_. Вы не делаете никаких заявлений о публичном или частном. Вы претендуете на право собственности.

Это действительно похоже на то, что происходит в модулях ES6. Все, что вы определяете внутри файла, «принадлежит» модулю, определенному в этом файле. Является ли он общедоступным или нет, зависит от того, используете ли вы ключевое слово export .

Как и в случае с модулями ES6, вы _можете реэкспортировать_ то, что импортировали.

Мне нравится думать о declarations как об «уловке», которая избавляет меня от необходимости физически размещать все мои компоненты, директивы и каналы в одном и том же физическом файле (как вам пришлось бы поступить с модулями ES6, если вы намеревались все эти классы принадлежат одному и тому же модулю ES6).

Итак, для меня declarations — это замена для вставки этих файлов в один ужасный большой файл. В любом случае, это _моя_ ментальная модель.

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

Провайдеры и компоненты объявляются в одном и том же месте ( NgModuleMetadataType ), поэтому разработчик может интуитивно почувствовать, что провайдеры ведут себя как компоненты... что предполагает, что провайдер в модуле приведет к созданию экземпляра для этого модуля. .

Поскольку провайдеры управляются DI, это, конечно, неверно, они на самом деле находятся на уровне приложений.
Компоненты в модуле являются частными, если они не экспортируются, это может привести к путанице.

Мне нравится концепция модулей, IMO единственная проблема в API заключается в том, что провайдеры и компоненты объявлены в одном и том же месте внутри модуля... для новичков это сложно понять.

@wardbell Спасибо, Уорд, это действительно здорово! Просто чтобы уточнить, поскольку это только что обсуждалось, когда мы говорим, что Angular 2 является полным API, о каких пространствах имен мы говорим здесь? @угловой/???

@robwormald Спасибо! Отличный совет!!!
Со вкусом сахара! будет реализовывать.

Я не сотрудник Google и, возможно, сотрудник Google не может сказать. Я могу сообщить только то, что вижу своими глазами: очень серьезное зависание API в наборе @angular/ библиотек.

Есть хорошие идеи, которые лежат на полке, потому что они недостаточно хороши или недостаточно глубоки, чтобы оправдать задержку релиза. Так должно быть. Хорошие идеи никогда не прекращаются. Но пришло время сказать: «Это ваш Angular 2.0_».

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

@wardbell Я повторяю то, что вы говорите об экспорте.
Когда-то index.ts был заполнен

export * from 'a.component'
export * from 'b.component'
export * from 'c.component'
export * from 'p.directive'
export * from 'x.service'
export * from 'z.pipe'

теперь сокращен до export * from my.module
остальное все чистое находится в экспорте NgModule как
exports: [ AComponent, BComponent, CComponent, PDirective ] и так далее

@wardbell Я думаю, что @NgModules.providers должно было быть @NgModules.rootProviders или @NgModules.appProviders .

Я чувствую, что это четко описывает контекст поставщиков.

@shlomiassaf Это было бы заблуждением. Эффект @NgModules.providers различен для нетерпеливых и ленивых модулей. Модули с ленивой загрузкой получают свой собственный дочерний инжектор, что означает, что _их провайдеры_ добавляются к _дочернему_ инжектору, а не к _корневому_ инжектору. И так бывает, если ленивый загрузил ленивый загрузил ленивый.

Возможно, могло быть и другое имя. Ты знаешь, как это бывает. Но rootProviders не было бы улучшением по причинам, которые я только что привел.

@wardbell согласился, не думал об этом сценарии.

Просто хотел добавить к чувству, что подробные ответы и общение очень ценятся. Если это действительно последняя из болезней роста перед финалом, то мы отправимся в гонки. Спасибо!

Как уже отмечали другие, отзывы от команды приветствуются. Однако такого рода изменения на этом этапе разработки наводят на мысль о фундаментальных ошибках проектирования.
Давайте будем честными с самими собой, мы все совершали такого рода ошибки, поэтому нет смысла осуждать, но когда я совершаю ошибку, это унижает меня и, надеюсь, впоследствии делает меня более благоразумным. У меня не складывается впечатление, что это оказывает такое же влияние на команду Anagular.

Мне нравится думать об объявлениях как об «уловке», которая избавляет меня от необходимости физически помещать все мои компоненты, директивы и каналы в один и тот же физический файл (как вам пришлось бы поступить с модулями ES6, если бы вы хотели, чтобы все эти классы принадлежат одному и тому же модулю ES6).

Так что для меня объявления — это замена вставки этих файлов в один ужасный большой файл. Во всяком случае, это моя ментальная модель.

@wardbell Может быть, я упускаю что-то фундаментальное, но я не вижу, чем использование NgModule.declarations принципиально отличается от импорта всех, а только реэкспорта некоторых ваших ESModules. По иронии судьбы, основным ограничением ESModules является то, что они обеспечивают только концепцию физических модулей, а не логических. Я не вижу, как NgModule улучшает это. Это просто другой синтаксис агрегации, но он не повышает уровень абстракции до значимой степени.

Кроме того, NgModules полностью не решает серьезную проблему:

Весь шаблон Function[] непрозрачен во всех смыслах. Это снижает обнаруживаемость до нуля. Нужно прочитать источник, чтобы определить, что находится в массиве поставщиков. То же самое верно и для NgModule.exports .

Но IMO, лучше поставить правильный продукт, чем рабски следовать некоторым представлениям о том, каким должен быть RC, и поставить неправильный продукт. Кроме того... и это не очень удобно говорить... но если вы недавно наблюдали за некоторыми другими крупными компаниями-разработчиками программного обеспечения, вы, возможно, заметили столь же гибкое понятие "кандидат на выпуск". По какой-то причине наша индустрия идет именно так.

@wardbell Самое большое разочарование по поводу RC для меня — это впечатление, что бета-версия только что была переведена в RC из-за ng-conf и ввода-вывода Google. Чтобы добиться прогресса, нужно четко указать причину: это был _маркетинг_, и как технологи мы должны бороться с тенденцией этих гибких представлений о зрелости. Возможно, вы знаете популярного производителя автомобилей в долине, где ведется дискуссия о том, правильно ли продавать бета-версию продукта, потому что он может забрать жизнь. Я не хочу преувеличивать, но как технологи мы должны заявить о том, что наша отрасль движется именно так, потому что тогда она движется в неправильном направлении.

Мне нравится подход ngmodule, но у меня есть вопрос @robwormald :

У меня есть общая служба, в которой нет компонентов, директив и каналов. Он имеет только сервисы ( forRoot ) и содержит все классы бизнес-модели. app.module импортирует ServerApiModule.forRoot() , поэтому службы доступны для всего приложения. Должны ли функциональные модули, использующие сервисы и классы бизнес-моделей, импортировать этот общий модуль? Технически это не обязательно (без ошибок), но с семантической точки зрения это имеет смысл (также без ошибок). Что нам делать с такими модулями? Импортировать их или нет? Мне лично нравится второй вариант, потому что он говорит: «Эй, я функциональный модуль, и мне нужны эти услуги, и мне нужны эти классы бизнес-модели».

Спасибо за ответ!

Так что я могу чувствовать боль с библиотеками/модульными библиотеками приложений и ngModule.

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

Таким образом, правильным подходом было бы объявить ngModule для каждого компонента.
Но поскольку это делает кодирование котлов для каждого компонента намного более сложным, этот способ также не работает в больших масштабах.

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

Вот так? Если я вижу компонент. Я знаю, что это ДОЛЖНО быть частью ngModule. Если у меня есть случай, когда многие компоненты объединяют их вместе, я МОГУ использовать NgModule. Если мне просто нужен автономный компонент, такой как «старые компоненты», я использую ComponentModule, и я ЗНАЮ все зависимости и что он может быть зависимостью модуля для других модулей, но не частью их.

@nathraQ , если правильный подход заключается в использовании NgModule для каждого компонента, а это вполне может быть, то NgModule не нужно было вводить, а компонент нужно было просто улучшить. Что касается шаблонов, Angular 2 настолько тяжел для них, что это вряд ли имеет значение на данный момент.

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

@aluanhaddad извините, я не согласен. У меня были варианты использования только одного модуля в angular 1.x с пользовательским управлением зависимостями (как в стартере этой темы), но у меня также были варианты использования модулей для объединения набора контроллеров, директив и сервисов.

Оба полезны. Теперь осталось придумать, как его интегрировать понятно для всех

Ого, долго читал :smile:

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

@wardbell @robwormald -

Если я использую шаблон SharedModule и импортирую две сторонние библиотеки (ui-bootsrap или angular-strap?), которые используют один и тот же селектор для компонента, скажем, my-selectbox

Я получу ошибку, если попытаюсь импортировать их обоих? правильно?

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

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

Есть ли рекомендуемое решение этой проблемы? или это "модуль-оболочка"?
(Надеюсь, мы не вернемся к использованию префикса для селекторов, это было неинтересно)

Заранее спасибо!

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

@nathraQ Все эти шаблоны могут быть реализованы с помощью модулей ECMAScript. Введение NgModule ни к чему не приводит, и тот факт, что такие библиотеки, как AngularMaterial, превращают компоненты в NgModules только для того, чтобы сохранить ранее предоставленную инкапсуляцию, только подтверждает это.

@aluanhaddad NgModules пытается сделать что-то совсем другое, чем модули ES, и также не заменяет инкапсуляцию компонентов, т. Е. И модули ES, и компоненты не изменили своих основных обязанностей. NgModules — это среда, с помощью которой вы описываете архитектуру во всем приложении, и это помогает Angular лучше понять ваши намерения и соответствующим образом оптимизировать, позволяя такие вещи, как предварительная компиляция определенных частей вашего приложения, обслуживание динамически разрешаемых модулей с сервера и т. д., все из которых не может быть достигнуто с модулями ES. По тем же причинам один NgModule для каждого компонента не является эмпирическим правилом.

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

@emilio-martinez, как писал @aluanhaddad , ES6 и «старый угловой способ 2» дали нам необходимое пространство имен.

Я работал над очень большими проектами с Angular 1, и селектор с именем: mb-product-list может очень быстро столкнуться с другими, если это большой проект (даже в команде из 5+ разработчиков).

Пытаясь решить эту проблему с помощью большего пространства имен, вы получите: mb-somefeature-product-list , из-за чего шаблоны выглядят грязными.

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

У ngModules есть свои преимущества, это точно, он помогает с асинхронной загрузкой фрагментов, а также помогает нам писать меньше импортов и повышает производительность.

Но использование шаблона SharedModule вводит глобальное пространство имен, как это было в ng1.

По крайней мере, у провайдеров пространство имен определяется токеном ES6, расположением файла.

С компонентами из-за селекторов будет кричать, что есть два компонента с одним и тем же селектором.

Хотелось бы, чтобы у нас был простой способ настроить специальное пространство имен для случаев использования коллизий со сторонними или локальными общими компонентами.

Что-то вроде "переопределения селектора".

Это то, о чем я спрашивал

Спасибо @robwormald за ваше подробное понимание, но кое-что от новичков, таких как я (в основном, я бэкэнд-разработчик). Я изучаю Angular 2 и машинопись. Итак, концепция модуля ES6 для меня размыта.
У нас сложная структура приложения. Это аналитическое приложение, в котором количество компонентов составляет почти 60.
И я думаю, что он хорошо структурирован под RC4. Кроме входа в систему мы не использовали никакой маршрутизации, потому что routern воссоздает весь компонент целиком. Итак, мы планируем приложение на основе вкладок. Две основные вкладки (1. Анализ 2. Панель инструментов).
Вкладка «Аналитика» будет иметь несколько вкладок, каждая из которых содержит один анализ. Приборная панель также будет иметь
несколько вкладок, но каждая вкладка будет состоять из нескольких анализов, которые были сохранены в
раздел аналитики. Таким образом, переходя туда и обратно с нескольких вкладок (как на панели инструментов, так и в разделе анализа)
а также переключение между вкладкой Dashboard и вкладкой Analytics, мы считаем, что маршрутизация не будет работать
наша цель (поправьте меня, если я говорю глупость).
Теперь RC5 NgModule как бы ломает наше приложение. Мы действительно не знаем, как
переделайте наше приложение. Можем ли мы действительно использовать компиляцию AoT в нашем приложении? Разве это не
вся вещь AoT основана на маршрутизации?

@shairez NgModules обеспечивают именно такое пространство имен. Позвольте мне попытаться прояснить это немного дальше...

Здесь важно понимать, что компонент скомпилирован более или менее "внутри" модуля, в котором он объявлен - см. https://plnkr.co/edit/9w10b1Y8Bjr5DDIxOwnC?p=preview для примера.

Обратите внимание, что есть два конфликтующих селектора ( my-generic-selector ) — каждый из функциональных модулей импортирует один из них, может использовать его внутри этого модуля, не загрязняя какие-либо «глобальные» пространства имен.

Так используется как

<my-app>
  <!-- belongs to FeatureModuleOne -->
  <feature-one></feature-one>
  <!-- belongs to FeatureModuleTwo -->
  <feature-two></feature-two>
</my-app>

расширяется до

<my-app>
  <!-- belongs to FeatureModuleOne -->
  <feature-one>
    <!-- the generic imported in FeatureModuleOne -->
     <my-generic-selector></my-generic-selector>
  </feature-one>
  <!-- belongs to FeatureModuleTwo -->
  <feature-two>
    <!-- the generic imported in FeatureModuleTwo -->
    <my-generic-selector></my-generic-selector>
  </feature-two>
</my-app>

без каких-либо конфликтов, потому что, когда компилятор компилирует функцию-1 и функцию-2, он делает это _в контексте модуля, которому они принадлежат_, что позволяет избежать загрязнения глобальной области видимости.

@robwormald Конечно, это круто и в этом смысле лучше, чем Angular 1.

Вариант использования, о котором я писал, относится к шаблону использования глобального SharedModule, как это предлагается в документации .

Если я попытаюсь объявить GenericSelectorFeatureOne и GenericSelectorFeatureTwo внутри SharedModule , я получу ошибку, верно?

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

Если в моем функциональном модуле есть конфликтующий селектор, или у какой-то третьей стороны есть конфликтующий селектор с одной из существующих библиотек, экспортированных в SharedModule , он выдаст ошибку, верно?

@shairez Я думаю, что большинство приложений в конечном итоге будут иметь несколько «SharedModules», и вероятность коллизий низка - модули дешевы, поэтому наличие большого количества не требует больших затрат.

Если у вас есть идеи, как улучшить документацию, буду рад PR.

Спасибо, это ответ, который я искал, я проверю его.

У меня пока нет лучших идей о том, как решить эту проблему с помощью нового способа написания модулей, поэтому я задал этот вопрос здесь, но как только я протестирую решение с несколькими общими модулями, у меня будет больше материала для обсуждения с @ wardbell и представить PR.

Спасибо за помощь @robwormald !

Из последних документов, доступных на https://angular.io , есть _много_ предупреждений об анти-шаблонах и ошибках, которые могут легко появиться, если NgModule составлены неправильно. Например

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

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

Другая, по-видимому, более серьезная проблема возникает при сопоставлении следующих разделов документации.

Предположим, для модуля требуется настроенный HttpBackend, добавляющий специальный заголовок для всех запросов Http. Если другой модуль в другом месте приложения также настраивает HttpBackend или просто импортирует HttpModule, он может переопределить поставщика HttpBackend этого модуля, потеряв специальный заголовок. Сервер будет отклонять http-запросы от этого модуля.
Избегайте этой проблемы, импортируя HttpModule только в AppModule, корневой модуль приложения.

Могу ли я реэкспортировать классы и модули?
Абсолютно!
Модули — это отличный способ выборочно агрегировать классы из других модулей и реэкспортировать их в консолидированный удобный модуль.
Модуль может реэкспортировать целые модули, что эффективно реэкспортирует все их экспортированные классы. Собственный BrowserModule Angular экспортирует пару таких модулей:
экспортирует: [CommonModule, ApplicationModule]
Модуль может экспортировать комбинацию собственных объявлений, выбранных импортированных классов и импортированных модулей.

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

Понятие реэкспорта NgModule аналогично реэкспорту модуля ES, за исключением того, что у вас меньше контроля. JavaScript имеет статическую область видимости (да, я знаю, что this — нет), и это одна из его самых сильных сторон, позволяющая создавать чрезвычайно гибкую композицию и скрывать информацию. JavaScript также поддерживает затенение, поэтому у вас всегда есть способ переопределить область действия.

Однако самая большая проблема заключается в том, что все примеры в рекомендациях вращаются вокруг того, как импортировать модули фреймворка @angular/*. Они естественным образом делятся таким образом, чтобы можно было интуитивно предотвратить конфликты. Это связано с тем, что они существуют для предоставления услуг уровня инфраструктуры, которые обычно не пересекаются. Определяемые пользователем модули могут пересекаться со многими слоями и могут улучшать или изменять различные виды поведения. Например, модулю ведения журнала может потребоваться доступ к службам Router и Http, в то же время предоставляя несколько компонентов для отображения информации пользователям с правами администратора и используя один из модулей форм для их определения.

Документы ничего не говорят о том, является ли реэкспорт транзитивным... Модуль A реэкспортирует CommonModule. Модуль B повторно экспортирует модуль A. Модуль C импортирует модуль B. Значит ли это, что модуль C теперь может использовать директивы из CommonModule?

@Martin-Wegner Они транзитивны, как описано здесь https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#! #q-реэкспорт

@aluanhaddad где? Я не могу найти ни слова о транзитивном реэкспорте с более чем одним прыжком...

Читая то, что @aluanhaddad взял из документов angular, я чувствую, что должен пересмотреть все, что я узнал об Angular 2, и, возможно, даже если нет фреймворка, который бы лучше обрабатывал зависимости.

Я так понимаю. Если у меня есть модуль приложения, импортирующий HttpModule, и у меня есть модуль функций со службой, которая использует службу Http, я должен импортировать HttpModule не на уровне модуля функций, а на уровне модуля приложения. А что, если я создам функциональный модуль, который будет использоваться многими модулями приложений? Я действительно должен импортировать HttpModule в модуль приложения. Я не могу сказать, что мой Feature Module зависит от HttpModule. Это действительно уродливо и означает, что в определении NgModule отсутствует множество функций, таких как, например, PeerDependecies.
О, парень. Такое ощущение, что angular 2 разваливается. Боюсь, пришло время начать все сначала, отказаться от angular 2 и начать с angular 3.

На самом деле в том, что вы только что сказали, так много смысла. я начал это
angular2 путешествует с прошлого года, и у него не было причин чувствовать себя избитым
несмотря на все критические изменения, которые мы видели до сих пор (от альфы до беты,
и РК). Это понятно на тех этапах и так как он религиозно застрял
к философии, которую он использовал, чтобы избавиться от моих минималистских Backbonejs.
Вся идея этого ngModules для меня оказалась несколько противоречащей
продуктивный. И грустно наблюдать за тем, сколько времени я трачу на евангелизацию
богатое совершенство минималистичных и свободных от раздувания «Компонентов» перейти к
абсолютно отходы.
29 августа 2016 г., 9:44, «Дэниел Шуба» [email protected] написал:

Читаю то, что @aluanhaddad https://github.com/aluanhaddad взял из
документы angular Я чувствую, что должен пересмотреть все, что у меня есть
узнал об Angular 2 и, возможно, даже если нет фреймворка, который
лучше справляется с зависимостями.

Я так понимаю. Если у меня есть модуль приложения, импортирующий HttpModule, и я
есть функциональный модуль со службой, которая использует службу Http, я не должен
импортировать HttpModule на уровне функционального модуля, но на уровне модуля приложения. Ну и что
если я создам функциональный модуль, который используется многими модулями приложений? у меня есть
на самом деле HttpModule импортируется в модуль приложения. я не могу сказать,
что мой Feature Module зависит от HttpModule. Это действительно некрасиво и
означает, что в определении NgModule отсутствует множество функций, например,
PeerDependecies.
О, парень. Такое ощущение, что angular 2 разваливается. боюсь пора
начните сначала, откажитесь от углового 2 и начните с углового 3.


Вы получаете это, потому что подписаны на эту тему.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/angular/angular/issues/10552#issuecomment-243066961 ,
или заглушить тему
https://github.com/notifications/unsubscribe-auth/AF675h8_np9i5cHgL8mMOOu8vMMQmWKkks5qkpv8gaJpZM4Jee-о
.

Может ли кто-нибудь поправить меня, если я ошибаюсь.

Я думаю об организации приложения следующим образом.

приложение
|--Закон/
|----МногиеКомпоненты.
|----LawNGModule.
|--Пользователь/
|----МногиеКомпоненты
|----UserNGModule
|--AppNGModule
|--SomeFirstLeveComponents

Допустим, я хочу работать с Angular Material. Раньше я как бы ненавидел, что у меня было слишком много шаблонов, импортирующих каждый элемент в каждый компонент. Теперь я бы добавил его в модуль NG. Но поскольку я решил использовать один модуль ng для каждой функции, мне нужно выполнить импорт для каждого модуля ng, который я рассматриваю. Не только корневой. Это правильно?

Или, может быть, это тот случай, когда вы создаете модуль x для реэкспорта y(Material) другого модуля, а импортируете его в нужные вам модули?

@ReneVallecillo Вы правы. Вы должны импортировать его в каждый функциональный модуль. Или вы добавляете его вместе с другими модулями в общий модуль (скрывая зависимость), который реэкспортирует его, а затем использует этот общий модуль. И если вы повторно экспортируете его в другой модуль, вы можете даже иметь дублированный импорт, не зная и не видя этого сразу.

@robwormald В ответ на ваш комментарий выше :

Однако в режиме AoT это работает немного по-другому — во время сборки мы статически (то есть без выполнения вашего кода) извлекаем одни и те же метаданные из исходного кода, сканируя декораторы.

Означает ли это, что вы статически извлекаете модули из исходного кода, и поэтому мы фактически не можем создавать модули динамически?

Чтобы упростить миграцию, я подумал о создании функции, которая динамически создавала бы модули; что-то вроде этого:

function createModule (entryComponent: Type, dependencies: Type[]) {
    @NgModule({
        imports: [CommonModule, FormsModule],
        declarations: [entryComponent, ...dependencies],
        exports: [entyComponent]
    })
    class FeatureComponent {}
    return FeatureComponent;
}

Таким образом, хотя это (вероятно?) будет работать с компиляцией JIT, это не будет работать с AoT, потому что AoT статически анализирует исходный код в поисках декораторов?

Эта ненужная сложность в эпоху ES@next.... @aluanhaddad делает несколько очень хороших замечаний.

При нынешнем положении вещей я не могу представить, чтобы моя команда/я продвигались вперед с Angular 2, если это предполагаемое направление. И кажется, что это так, поскольку это было «закрыто».

Возможно, мне придется поступить так, как @DaSchTour , и изучить другие интерфейсные фреймворки. Очень жаль, потому что несколько месяцев назад с NG2 было очень приятно работать, и я явно выбрал его из помёта.

@iyobo, кроме первоначальной боли при переходе, _подавляющее_ большинство (и я разговариваю с _lot_ разработчиками) отзывов о NgModules были положительными.

Если рассматривать приложение hello world по отдельности, можно утверждать, что оно «сложное» («бесполезное» на самом деле неверно, согласно приведенному выше объяснению), но в реальном приложении они действительно проявляются сами по себе — организующие функции, ленивая маршрутизация и Все AoT стало намного проще с NgModules. Учитывая выбор сегодня, я бы все же выбрал добавление NgModules в структуру.

Я здесь с @robwormald , первоначальная боль при переходе с RC4/5 на NgModules была управляемой после того, как я увидел преимущества отсутствия необходимости импортировать каждый отдельный компонент/канал на вновь созданную страницу.
NgModules начинают сиять после того, как становятся немного более сложными и имеют много общих компонентов.

Намного проще просто импортировать SharedModule и покончить с этим.

Привет, @robwormald , мнение о том, что кто-то не согласен с текущим направлением Ng2, никоим образом не является фактическим утверждением, что они работают только с приложениями уровня «привет, мир».

В этом «разделении функций», о котором вы говорите, нет ничего нового. Это то, что всегда разрабатывалось по мере необходимости, чтобы соответствовать каждому отдельному продукту/решению с использованием компонентов.
Тем не менее, на самом деле нет большего разделения, чем компонент, объявляющий, что ему нужно, сам по себе.

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

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

Я думаю, что время покажет, было ли внедрение NgModules хорошей идеей. У меня сложилось впечатление, что Angular 2 в настоящее время просто создан для достижения определенных целей дизайна. Никто не задумывался о таких вещах, как команды с разным уровнем навыков, код, который стареет и передается из поколения в поколение разработчиков. В идеальном мире это может выглядеть как отличная идея. Но на самом деле NgModules привносит множество ловушек и обфускаций, которые доставят немало хлопот на этапе обучения и внедрения в новый проект. Это просто не так просто и интуитивно понятно, как было с объявлением на уровне компонентов. Зависимости скрыты в модулях, и это всего лишь вопрос времени, когда вы должны начать исследовать модуль, в котором находится ваш компонент.

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

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

Я был бы очень признателен, если бы был механизм _в дополнение_ к NgModules, который позволял бы компонентам определять другие компоненты или директивы как локальные зависимости, которые применяются только внутри этого конкретного компонента (точно так же, как листинг directives работал до модулей).

Мне нравится предложение @poke иметь альтернативу для тех, кто не хочет использовать Full NgModules.

NgModules были добавлены в RC5 для решения проблем с компиляцией и отложенной загрузкой для работы — так что вряд ли они являются частью исходного генерального плана, поэтому они не очень подходят для некоторых случаев использования (особенно если вы создавали приложение на основе оригинальный дизайн «компоненты — король»).

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

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

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

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

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

@for all Автор Angular2: не могли бы вы честно рассказать нам, каковы отрицательные стороны NgModules? Я знаю, что ты можешь написать книгу обо всем хорошем. Все в порядке. Но мне всегда нужно иметь дело со скрытыми плохими вещами, которые не будут ясны, если о них не говорить.

Может ли кто-нибудь показать мне, как NgModules работает в действительно сложном приложении, где для нескольких компонентов требуется несколько других на нескольких уровнях?

Один из способов сделать это — создать модуль зависимостей только для этих компонентов: предположим, у вас есть три набора компонентов A , B и C , которые содержат несколько компонентов. в каждом наборе есть те, которые в чем-то связаны. Таким образом, эти три набора хорошо подойдут для трех отдельных модулей.

Теперь для компонентов в каждом из этих наборов требуется несколько компонентов из набора D . Эти компоненты в D используются только для компонентов в этих трех наборах. Поскольку они используются во всех из них, вы не можете просто добавить компоненты в эти модули (поскольку компоненты могут быть только частью одного модуля). На этом этапе вы можете объединить A , B , C и D в гигантский модуль, чтобы все зависимости были там. Но это, конечно, очень грязно. Вместо этого вы просто создаете новый модуль для D , который просто содержит эти зависимости. Этот модуль не делает ничего, кроме предоставления доступа к этим модулям. Теперь вы можете импортировать этот модуль в каждый из этих трех других модулей и можете использовать компоненты. Но поскольку компоненты по-прежнему являются «личными», вы не можете повторно экспортировать модуль или импортировать модуль D в какой-либо другой модуль.

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

Могу поделиться текущими настройками. Я использовал 3 модуля в приложении: CommonModule, AppModule и TestModule.

  • CommonModule импортирует и экспортирует наиболее распространенные вещи, такие как HttpModule, FormsModule, MdInputModule и т. д.
  • AppModule импортирует BrowserModule, CommonModule, app.routing и отдельные компоненты.
  • TestModule импортирует и экспортирует BaseModule, но перезаписывает некоторые провайдеры, такие как XHRBackend с MockBackend.

Я представил эту настройку для упрощения TestBed.configureTestingModule,
так что мне нужно импортировать TestModule, а затем только один компонент, например:

TestBed.configureTestingModule({
  imports: [ TestModule ],
  declarations: [ MyFormComponent ]
});

Еще один недостаток, который стал очевиден, когда я перешел с RC-4 на релизную версию, заключался в том, что NgModules налагают большие штрафы за простой рефакторинг, когда компонент просто нужно разделить. С NgModules вам нужно изменить содержащий модуль, который может быть на несколько уровней выше концептуального дерева компонентов, или продвигать компонент, завернув его в NgModule, а затем удалив его из его родительского NgModule. Рефакторинг компонентов имеет важное значение.

Это напрямую связано с точкой зрения @poke

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

Я категорически не согласен. Модульную архитектуру, предложенную Angular 2, легче масштабировать, настраивать и рефакторить, где это необходимо. Конечно, от RC4 до RC5 пришлось немного подстраиваться, но, во всяком случае, мне показало, что NgModules позволяют создавать гораздо более гибкие приложения.

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

@emilio-martinez: На мой взгляд, NgModule никогда бы не был представлен, если бы Angular 2 не был таким медленным при начальной загрузке при использовании JiT. Все другие «улучшения», такие как «масштабирование, настройка и рефакторинг», спорны, как показывает это обсуждение.

Прошло довольно много времени, и у многих из нас было время полностью включить NgModule в свою работу. Я думаю, теперь ясно, что, как описали довольно много людей, как только вы преодолеете скачок скорости при переходе на новую модульную систему, она позволит вам сделать несколько замечательных вещей. Всем, у кого есть проблемы с освоением NgModule, я предлагаю пролистать все до конца и прочитать все, особенно от @robwormald и @wardbell .

Я верю, что через год мы все обнаружим, что многие приложения Angular 2+ широко используют модули, отложенную загрузку и AOT. Я считаю, что для большинства или почти всех приложений будет совершенно обычным делом использовать эти вещи для реализации видения «прогрессивного приложения», когда даже большие сложные приложения имеют почти мгновенное время начальной загрузки, а затем лениво загружают (или оптимистично лениво предварительно загружают) функциональность, которую они необходимость. Результат на самом деле удивительно гладкий и достигается с удивительно низкими затратами для отдельного разработчика приложений: NgModule в основном является той стоимостью, и это раздражающий переход, но тогда только очень скромный объем текущей работы для использования.

@kylecordes Надеюсь, ты прав, и я думаю, что это правильное отношение.

@iurii-kyrylenko это правда.

У меня есть проблема с угловой компиляцией моего JavaScript, поскольку предполагается, что TypeScript компилирует мой JavaScript, но это отдельная проблема.

@kylecordes Я думаю, что нужно учитывать гораздо больше, чем просто переход. Модули вносят большую сложность и множество дополнительных возможностей для добавления ошибок в собственное приложение. Самая большая проблема — это обфускация зависимостей. Что вызовет много проблем в ближайшие годы разработки с angular 2.

@aluanhaddad Я считаю, что Angular использует для компиляции оболочку tsc. Это хорошо, потому что вы даже можете внедрить его, например, в рабочий процесс запуска задач.

Скорость начальной загрузки @iurii-kyrylenko также трудно определить на основе RC4. Большая часть работы, которая была проделана с тех пор до финального релиза, заключалась в очистке и оптимизации. По моему опыту, JIT, скомпилированный с помощью Angular, в любом случае работает быстрее, чем RC4.

@DaSchTour , можете ли вы рассказать об ошибках, которые вы обнаружили при работе с NgModule?

@emilio-martinez это не ошибки в NgModule, а ошибки, которые возникнут из-за отсутствия импорта или дублирования экземпляров службы, которые были бы пропущены или обнаружены на более ранней стадии разработки. Речь идет об импорте вещей в то место, где я их использую, а не туда, где я не вижу, нужно ли это или используется, и в каком месте это нужно и используется.

Просто подумайте о том, как работает TypeScript. У меня есть базовый файл для моего модуля, назовем его _index.ts_, он выглядит так.

import {foo} from bar;
import {StartComp} from start;

StartComp.boot();

Затем у нас есть файл с именем start.ts, который выглядит так.

export class StartComp {
   public static boot() {
      foo()
   }
}

Это то, что Angular делает с NgModules. С некоторой магией я импортировал что-то в модуль, и оно появляется на другом конце моего приложения. Вы должны знать, что foo импортируется в index.ts, и запустив StartComp из индекса, импорт можно использовать в компоненте.

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

@emilio-martinez

По моему опыту, JIT, скомпилированный с помощью Angular, в любом случае работает быстрее, чем RC4.

У меня есть проект средней сложности, основанный на стеке MEAN и Angular 2 final. Для завершения начальной загрузки в режиме JIT на моем устройстве Android требуется около 10 секунд . Я считаю это значительной задержкой. В настоящее время я не могу использовать компиляцию AOT без изменения моего исходного кода (проблемы с закрытыми членами, оператором elvis...).

Есть ли у кого-нибудь информация о производительности AOT+lazy load для реальных проектов?

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

@emilio-martinez это именно то, чего я не хочу. Я хочу скомпилировать свой код, используя любую версию TypeScript, какую мне заблагорассудится, например 2.1.0-dev, в которой для async/await используется нижний уровень. Я не хочу, чтобы Angular отвечал за компиляцию моих файлов TypeScript, это не следует делегировать фреймворку, это роль языка. Не отходя от темы, я бы не стал трогать @Script десятифутовым шестом, слава богу, он мертв.
Что касается рабочего процесса, я использую JSPM, а иногда и Webpack, а не традиционное средство запуска задач, и позволяю своей IDE обрабатывать мои линтеры.

Другая проблема заключается в том, что я написал декораторы, которые абстрагируются от угловых декораторов, и теперь я понимаю, что многие будут их игнорировать. Учитывая, насколько тяжелыми являются декораторы angular, я был очень разочарован, узнав, что фреймворк не будет полностью поддерживать декораторы, рассматривая их во время AOT как статические аннотации, хотя на самом деле они являются конструкцией времени выполнения на базовом языке.

@aluanhaddad важно понимать, что во время компиляции AoT происходят два отдельных шага: первый генерирует _new_ typescript код, второй транспилирует этот код в ES5/6. ngc делает и то, и другое для удобства, но в AoT нет ничего, что требовало бы этого. Внутри Google мы делаем и то, и другое, поэтому этот случай является приоритетным. Любой может реализовать хост компилятора для поддержки генерации кода в любой среде, которую он хочет.

Мы (пока) не поддерживаем абстрагирование поверх встроенных декораторов angular, но если вы хотите использовать что-то вроде https://www.npmjs.com/package/core-decorators , это будет нормально.

@iurii-kyrylenko предлагает вам посмотреть основной доклад AngularConnect в первый день, где LucidCharts рассказали о своем опыте работы с AoT. См. https://youtu.be/xQdV7q3e_2w?t=1411

ИМХО - цель №1 для всех должна заключаться в том, чтобы как можно скорее получить компиляцию AoT. Спектакль просто бесподобен.

@robwormald Я не смотрел, какие параметры доступны при вызове ngc , так что это может быть уже рассмотрено. Я думаю, что эти варианты могли бы ослабить опасения, подобные тем, которые озвучены здесь, если они сделают очевидным, что NGC выполняет первую цель как основную причину существования во второй цели как удобство/оптимизация. Если в документации или справке показано, как отдельно запускать готовые tsc для тех, кто предпочитает это делать, это может еще больше облегчить проблемы?

@kylecordes Я не думаю, что в документации будет описано, как реализовать собственный хост-компилятор в ближайшее время. Это расширенный вариант использования, поэтому для его реализации потребуется некоторое самостоятельное обучение. Мы реализовали аналогичную вещь для CLI здесь https://github.com/angular/angular-cli/tree/master/packages/webpack .

@robwormald Ах, я не имею в виду реализацию собственного хоста компилятора. Я просто имел в виду двухстрочный «процесс сборки» — сначала вызывая ngc для создания сгенерированного машинописного текста, а затем вызывая tsc самостоятельно, чтобы скомпилировать весь машинописный текст (ваш источник плюс сгенерированный источник) для JavaScript. Это обеспечивает быструю уверенность в том, что код машинописного текста просто компилируется в JS готовым компилятором машинописного текста.

@robwormald Спасибо за ваш ответ.
Что касается NGC, я хочу знать, могу ли я контролировать версию и настройки компилятора TypeScript в проходе TS -> TS . Могу ли я передать TypeScript в NGC или мне нужно использовать определенную версию, обертывающую конкретную версию TypeScript? Насколько они связаны?

Что касается декораторов, есть ли поддержка отслеживания проблем для определяемых пользователем декораторов, которые абстрагируются от декораторов Angular? https://www.npmjs.com/package/core-decorators — это ортогональный набор декораторов, но у меня есть декораторы, которые применяют шаблоны и соглашения в моих приложениях Angular, обертывая декораторы Angular. Очевидным вариантом использования этого является автоматическое создание и применение префиксов имен компонентов пакета, но есть и другие.

Поскольку NGC не поддерживает это, как он узнает, какие декораторы специфичны для Angular?
Соответствует ли он угловым декораторам по имени?
Я надеюсь, что не потому, что это нарушило бы лексическую область видимости JavaScript.
Простой сценарий
_awesome-component-decorators.ts_

import { Component } from '@angular/core';
import template from './awesome-component.html';
import style from './awesome-component.less';

export const awesomeComponet = <T extends new (...args) => any>(target: T) =>
  Component({template, styles: [style], selector: snakeCase(target.name) })(target);

_consumer.ts_

import { awesomeComponet } 'app/shared/awesome-component-decorators';

<strong i="19">@awesomeComponent</strong> 
export class AnAwesomeComponent { }

<strong i="20">@awesomeComponent</strong> 
export class AnotherAwesomeComponent { }

@jpsfs Нашли ли вы какое-либо решение для динамической загрузки компонентов без добавления объявлений компонентов в корневой модуль приложения? .

Я также являюсь частью проекта миграции angular 1.X на Angular 4. Этот проект имеет большое количество компонентов, которые повторно используются в разных приложениях, которые загружаются отложенно в зависимости от контекста приложения.

Насколько я понимаю в Angular 4

Мы должны добавить зависимости компонентов в корневые объявления @NgModule , как показано ниже.

импортировать {platformBrowserDynamic} из "@angular/platform-browser-dynamic";
импортировать {Component, NgModule} из "@angular/core";
...
...
@NgModule({
imports: [BrowserModule], // импорт BrowserModule Angular
bootstrap: [BootStrapComp], // указываем загрузочный компонент
декларации: [com1, comp2, comp5 ...... Comp n] // регистрируем наш компонент в модуле
})
экспорт класса AppModule {}

платформаBrowserDynamic().BootstrapModule(AppModule);

Но в нашем случае мы не хотели рутировать NgModule, чтобы знать о зависимостях компонентов во время компиляции. Скорее мы хотели, чтобы компоненты загружались динамически во время выполнения.
Нашли ли вы какие-нибудь хорошие решения, которые могут запускать приложение без добавления всех компонентов в корневые объявления NgModule (и мы также не хотели иметь один NgModule для каждого компонента :))

@ДаШТур

Помните времена, когда ваша точка входа в приложение выглядела так?

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

Я ищу что-то похожее и простое решение в angular2.

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

С поддержкой динамического импорта в ECMAScript, а теперь и в TypeScript (с полной проверкой типов, ортогональной загрузке), вариант использования ленивой загрузки довольно произвольный. Конечно, задним числом 20/20, и не было никакого способа узнать, что это произойдет.

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

Узнайте больше о нашей политике автоматической блокировки разговоров .

_Это действие было выполнено автоматически ботом._

Была ли эта страница полезной?
0 / 5 - 0 рейтинги