Angular: NgModule em grandes projetos

Criado em 7 ago. 2016  ·  144Comentários  ·  Fonte: angular/angular

Estou enviando um ... (marque um com "x")

[X] feature request / proposal

Eu tenho lido sobre o NgModule e quero expor alguns casos de uso que não tenho certeza que a proposta atual (https://docs.google.com/document/d/1isijHlib4fnukj-UxX5X1eWdUar6UkiGKPDFlOuNy1U/pub) leva em consideração .

Contexto

Faço parte de uma equipe construindo um Enterprise Framework (baseado em Angular 2). Essa estrutura será a base para outros aplicativos dentro do mesmo ecossistema.

Dividimos o framework em projetos/módulos menores (pense neles como pacotes npm separados). Esses módulos são conjuntos de controles (que são reutilizados em outros módulos) ou páginas que usam esses controles.

Exemplo

Um exemplo rápido pode ser:

Módulo de controles

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

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

}

Módulo Lista de Verificação
// O módulo Checklist depende do módulo Controles. Os controles são tratados como um módulo de terceiros.

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{

}

O Bootstrap não conhece os módulos Controls e Checklist. Eles são carregados com preguiça dependendo da interação do usuário. Neste caso, se o usuário navegar para um Checklist, o componente ChecklistPage será carregado e em seguida o MyComboBox também seguirá (por causa da _import_ feita pelo ChecklistPage)

O módulo Checklist tem outras dezenas de componentes. Cada um dependendo de outras dezenas de componentes de vários módulos.

É impraticável (para não dizer quase impossível) ter todos os componentes importados para a declaração NgModule. Estamos falando de várias centenas de componentes que _poderiam_ ser usados ​​durante o tempo de execução do aplicativo.

Além disso, o aplicativo precisa ser modular e com carga lenta quando possível. Diferentes interações dentro do aplicativo levarão ao carregamento de módulos completamente diferentes.

Comportamento esperado/desejado

A solução atual, com diretivas de escopo de componente, funciona como um encanto para este caso de uso. Não tenho certeza de como isso funcionará com o NgModule.

Mais do que isso, atualmente podemos ver claramente as dependências necessárias para cada componente (neste caso ChecklistPage). Tornando a manutenção muito mais fácil.

Ter todos os componentes necessários importados para um NgModule e usá-los indistintamente em vários componentes parece uma solução fantástica para pequenas aplicações. Eu sinto que em um desenvolvimento de longo prazo, com várias iterações ao longo de vários anos, com rotação de equipe, ... ter cada componente explicitamente declarando do que depende sem olhar para o modelo (e ter erros de compilação quando algo está faltando) é um ótimo vantagem.

Conclusão

Por favor, deixe-me saber se eu fui claro na minha explicação. O objetivo desta edição é aumentar a conscientização sobre essa situação e obter feedback de você sobre como proceder.

Estamos disponíveis para mostrar nosso trabalho atual, temos várias centenas de componentes Angular 2 em 8 projetos desenvolvidos no ano passado (desde alpha 27).

Comentários muito úteis

Obrigado pelo feedback de todos, pedimos desculpas por ter demorado tanto para obter uma resposta - estivemos muito ocupados na última semana (migrando aplicativos internos do Google para NgModules, então também sentimos a dor da refatoração)

Deixe-me ver se consigo esclarecer algumas das dúvidas e equívocos aqui.

A primeira coisa a entender sobre @NgModule() (e @Component e qualquer outro decorador Angukar) é que eles são puramente construção de tempo de compilação - eles existem para permitir que o compilador angular descubra um gráfico de dependência em um aplicativo.

Uma versão (simplificada) do que nossos decoradores fazem:

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

Eles não alteram ou modificam o comportamento da classe decorada de forma alguma - eles simplesmente anexam alguns metadados. Angular usa esses metadados para construir seu aplicativo e compilar modelos.

No modo JiT, isso acontece "Just in Time" - entre você chamar bootstrapModule e sua primeira renderização de componente, o compilador do Angular recupera os metadados anexados às classes usando a API Reflect:

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

No entanto, no modo AoT, isso funciona de maneira um pouco diferente - no momento da compilação, nós _estaticamente_ (ou seja, sem executar seu código) extraímos os mesmos metadados do código-fonte verificando os decoradores.

Isso funciona bem quando você está inicializando um único componente, mas ouvimos muitos comentários de desenvolvedores que estão fazendo coisas mais complexas - inicializando vários componentes raiz ou inicializando componentes diferentes com base no status de autenticação etc.

Portanto, enquanto os decoradores @Component nos deram a capacidade de analisar estaticamente um Component, não tínhamos a capacidade de analisar estaticamente de forma confiável um _Application_

Coisas que caem sob o guarda-chuva de um "aplicativo"

  • PLATAFORMA_DIRETIVAS/TUBOS/PROVADORES
  • coisas que você adicionou anteriormente ao bootstrap()
  • configurações de nível do compilador
  • vários componentes raiz
  • uso do lado do servidor.

NgModules introduz a ideia de um conjunto de recursos estaticamente analisável. O interessante é que no modo de compilação AoT, analisamos seu módulo raiz e _geramos_ um ModuleFactory para cada Módulo no aplicativo - esta é a versão pré-compilada de um módulo, que contém _somente_ as fábricas que você referencia estaticamente nos modelos e aquelas que você marcar como "entryComponents"

Como já extraímos as informações necessárias para a compilação Ahead-of-Time, podemos realmente sacudir os decoradores (o ngc lidará com isso automaticamente para o final) - e em vez de agrupar seu aplicativo começando no módulo raiz, você inicia na sua raiz gerada Module_Factory_, que contém apenas o código que é realmente usado em seu aplicativo, para que você não pague multa pela modularidade, e ferramentas como rollup e webpack2 podem funcionar _mais_ eficientemente

mais a seguir na próxima resposta ...

Todos 144 comentários

Não me parece que o ngModules proíbe a configuração que você está fazendo, você já brincou com isso? Você pode ter vários módulos diferentes e fazer carregamento lento, etc. http://plnkr.co/edit/NAtRQJBy50R19QAl90jg?p=info

Para algo mais parecido com o que você parece estar tentando fazer, fique de olho na transição do material2: https://github.com/angular/material2/pull/950/files

Olá @qdouble ,

Obrigado pela resposta rápida.
Olhando para https://github.com/jelbourn/material2/blob/ecbb4f42e0473899f6ad15d8e4ed8f262ded7a99/src/components/button-toggle/button-toggle.ts , você está dizendo que, para obter a mesma funcionalidade que temos agora, precisamos declarar um NgModule em cada componente? (isso é o que foi adicionado no final do arquivo certo?)

Além disso, não cobre o problema de manutenção que mencionei na minha declaração inicial. Ter as dependências de cada componente/diretiva declaradas em seu decorador é, para mim, uma grande vantagem que gostaria de manter.

@jpsfs se você quisesse criar escopo individual para cada componente, suponho que você teria que criar ngModules diferentes para cada um. Embora isso possa criar mais código no seu caso, suponho que criará menos código para a grande maioria das outras pessoas, delimitando meu módulo em vez de por componente.

No que diz respeito ao segundo problema, você pode declarar o ngModule e o componente um ao lado do outro, então, embora adicione 3 ou 4 linhas extras de código aos seus arquivos, não acho que isso crie um grande problema.

Eu diria que a grande maioria dos casos de uso não requer diretivas com escopo por componente, mas no caso de isso, ngModules ainda suporta isso por mais algumas linhas de código.

@qdouble Obrigado.

Não tenho certeza se esta é uma situação ou/ou, posso ver os dois cenários trabalhando juntos, não há necessidade de remover a funcionalidade que já temos. Se alguém quiser usar módulos, posso ver isso como um ótimo complemento. Enquanto isso, o framework pode funcionar sem módulos (como está funcionando hoje). Acredito que até mesmo o problema de compilação offline pode ser resolvido com as coisas como estão atualmente.

Estou deixando isso aberto para ver se alguém tem algo a acrescentar ao assunto.

@jpsfs entendeu, se eu estivesse na sua situação, definitivamente preferiria que deixassem as duas opções em aberto :)

Eles escreveram o motivo para depreciar as diretivas de componentes no documento que você postou, no que diz respeito à criação de dois escopos, eles pensam que o escopo do ngModule é pequeno o suficiente e que está mais alinhado com o modelo ES6.

Um membro da equipe também mencionou antes que geralmente é problemático ter duas maneiras diferentes de fazer as coisas ... e a longo prazo, eu poderia ver o problema aqui .... se você tiver alguns projetos em que as pessoas estão usando ngModules e outros projetos onde não há, isso cria mais problemas de manutenção, treinamento e compatibilidade.

Nunca se sabe em que direção este projeto irá até que seja finalizado, então veremos se eles levam em consideração o que você está dizendo.

Até eu estou atualmente trabalhando no design da arquitetura para um grande aplicativo corporativo.
Ao contrário da sua situação @jpsfs , estou empolgado com o NgModules e praticamente baseei minha arquitetura de aplicativo em torno do NgModule.

Cada Módulo terá seu próprio conjunto de rotas e dependências de componentes. Nós nunca podemos criar uma funcionalidade com apenas um componente, ele precisa de Rotas, pelo menos um Smart Component e poucos Dumb Components e Services para acompanhá-lo. Conecte tudo isso em um módulo e você está pronto para ir.

Chegando ao carregamento lento, em vez de carregar código para cada componente, parece bom que cada código NgModule seja carregado de uma só vez, para que sua funcionalidade seja totalmente utilizável uma vez baixada.

A criação de hierarquia de módulos também é muito mais simples e fornece um ótimo recurso Plug and Play gratuitamente.

Também estamos trabalhando atualmente em um aplicativo com muitos componentes (não centenas, mas dezenas). Não há necessidade arquitetônica de dividirmos esse aplicativo em vários módulos (carregados lentamente), mas agora importar todos esses componentes para o arquivo bootstrap e passá-los para declarations de alguma forma parece errado e quebra o encapsulamento do componente . Como o @jpsfs disse, antes estava bem claro quais componentes e diretivas eram usados ​​por outro componente. Então, eu também gostaria de ter a escolha:

  • Se for uma diretiva bastante usada, declare-a no módulo
  • Se for algo como TaskListItem basta importá-lo em TaskList .

Talvez algum membro do núcleo possa contar mais sobre a decisão de descontinuar a segunda abordagem. Tendo trabalhado com ele por vários meses agora, é muito bom;)

Para ecoar o ponto de @choeller , parece estranho se afastar da capacidade de fornecer encapsulamento de componentes.

Minha preocupação específica é que agora os nomes/seletores de componentes vazam em todo o aplicativo, enquanto antes você poderia reutilizar seletores para diferentes componentes incluindo diretivas específicas conforme apropriado.

Agora todos os seletores precisariam ser únicos por componente, certo? Ou estou entendendo errado como isso funciona?

Senti que a funcionalidade original correspondia aos benefícios semelhantes fornecidos pela emulação CSS shadow-DOM, pois poderíamos nos preocupar menos com colisões de seletores etc. em aplicativos grandes. Essa foi uma grande vantagem IMO.

Meu primeiro pensamento sobre ngModule foi "Oh, isso é como em angular 1". Por melhor que o angular 1 já fosse, o angular 2 é muito melhor em muitos pontos. O melhor ponto para mim foi que os Componentes criam algum tipo de árvore de dependência. Eu tenho um componente principal com um roteador que define vários pontos de entrada com seu próprio componente. E cada componente sabe o que precisa, não há razão para o componente principal saber o que qualquer um dos componentes no final da árvore precisa.
Agora estamos de volta aos bons e velhos tempos do angular 1, onde temos uma definição de módulo gigante.
Você se lembra das vezes em que o ponto de entrada do seu aplicativo ficou assim?

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("…")

Achei que isso pertencia ao passado. Comecei a trabalhar com ng-metadata para melhorar projetos antigos do angular 1 e me preparar para a migração. Eu realmente amo o fato de que ele tem uma árvore de dependência e não uma lista global "o que pode aparecer neste aplicativo".

Isso torna os componentes reutilizáveis ​​mais difíceis. Não entendo como isso melhora as coisas com tudo em um escopo global/módulo, acho que a equipe ng2 cedeu aos usuários ng1 que não querem mudar.

@DaSchTour @damiandennis Eu entendo as críticas a essa arquitetura, no entanto, referindo-se a ela como algum tipo de escopo global é impreciso, a metodologia que eles estão sugerindo é ter módulos de recursos: https://angular.io/docs/ts /latest/guide/ngmodule.html#! #feature-modules

@qdouble Bem, no final, está apenas mudando todos os componentes para módulos. Embora isso seja anunciado como uma mudança para reduzir o código clichê, ele introduz uma grande quantidade de necessidade de clichê.

Enquanto até o RC4 bastava um componente para cada "página"/view da aplicação, saiba que terei que criar um módulo, um componente e roteamento para cada view. Eu entendo a intenção. Mas, de alguma forma, tenho a impressão de que ele foi projetado para facilitar algumas coisas, sem se preocupar com muitos outros pontos. E mesmo com o padrão do módulo de recursos eu tenho que cortá-los bem pequenos para evitar o inferno da dependência, adicionando tudo o que pode ser necessário porque não consigo ver qual parte do meu aplicativo precisa de quais componentes.

No final, os módulos são tão pequenos que têm as mesmas listas de dependências repetitivas como os componentes atuais.

No final, não resolve para o que foi projetado e só adiciona muito trabalho. Tenho a sensação de que há aqui um descompasso entre o design e a realidade.

os desenvolvedores são preguiçosos/com pouco tempo e usam atalhos. Isso incentiva os desenvolvedores a seguir o caminho rápido de incluir tudo no bootstrap. Pelo menos com componentes, há algum requisito para incluir suas dependências. Sim, eles também podem ser preguiçosos e criar um único componente para todo o aplicativo, mas isso seria mais fácil de corrigir, pois as dependências estão todas nesse componente não misturadas entre o arquivo de bootstrap e cada arquivo de componente dentro do aplicativo.

@DaSchTour, se cada componente precisar de seu próprio escopo, sim, ele criará mais clichês ... é suficiente e alguns componentes seriam capazes de viver em cada espaço de recurso.

Agora, obviamente, não existe uma solução única e ter diretivas de nível de componente pode ser mais simples para algumas pessoas. No entanto, parece que muitos dos comentários aqui estão sugerindo que eles querem que você crie apenas um aplicativo com uma enorme árvore ngModule ...

Eu acho que é mais produtivo se a crítica for baseada em suas sugestões de design reais, em vez de um padrão de design de espantalho que eles não estão sugerindo (ou seja, criar um aplicativo corporativo que seja apenas um enorme ngModule)

@qdouble o padrão de design é simples. É usar uma árvore de dependência em vez de mover dependências para um escopo global de módulo. Acho que o ponto principal é que os componentes reutilizáveis ​​agora precisam ser módulos, mesmo que sejam muito pequenos e tenham pouca funcionalidade. Angular material2 é um exemplo muito bom. Um Button é um módulo, incluindo um componente. Talvez seja um equívoco geral de muitos desenvolvedores, que um módulo é algo que contém mais do que apenas um botão. E agora vamos pensar um passo adiante. Apenas seguindo as idéias deste artigo https://angularjs.blogspot.com/2016/08/angular-2-rc5-ngmodules-lazy-loading.html me encontro no ponto, que tenho muitos módulos que importe uma lista de módulos de material2 angulares e cada um destes módulos consistindo em um único componente.
Na verdade, isso é exatamente o que o material2 angular faz.

Ninguém realmente entendeu, por que agora temos que envolver "todos" os nossos componentes em módulos. Ou talvez tenhamos que ver isso como uma divisão de declaração. As dependências de componentes agora são um módulo e a definição de componentes é como antes.

Acho que o ponto é que ngModules não são apenas uma boa adição para facilitar as coisas, mas somos forçados a mudar tudo. Talvez alguém deva explicar claramente por que nem ambos podem coexistir.

@DaSchTour bem, sim, concordo que, se cada componente que você cria precisar de seu próprio módulo, o uso de ngModules cria mais clichê ... componente.

Eu me encontro no ponto, que tenho muitos módulos que importam uma lista de módulos de material2 angular e cada um desses módulos consiste em um único componente.

Você usaria módulos compartilhados para isso: https://angular.io/docs/ts/latest/guide/ngmodule.html#! #módulo compartilhado

Agora, eu não tenho certeza por que eles acham que é necessário remover totalmente a capacidade de ter um escopo de componente, mas para mim, algumas das críticas estão tornando o uso de ngModules mais difícil do que realmente é ou fazendo o design parecer mais desleixado do que realmente é.

Eu acho que a crítica à remoção de diretivas/tubos no escopo do componente é perfeitamente válida. No entanto, não acho necessário fazer parecer que não existem bons padrões de design para ngModules.

@qdouble Acho que ninguém duvida que existem bons padrões de design para ngModules. Mas pelo que entendi os módulos são apenas um wrapper em torno de um conjunto de componentes, diretivas e serviços para expô-los são uma unidade para o aplicativo. Isso é válido e uma ótima ideia. Mas por que eu tenho que definir as dependências (que só podem existir dentro do módulo) para o módulo e não para o componente.

Tomando o exemplo do @choeller
O módulo TaskDashboard tem as seguintes coisas

  1. Componente da lista de tarefas
  2. Componente de item de tarefa
  3. Componente de filtro de tarefas
  4. Serviço de Tarefa

O componente Taskitem só é necessário dentro da Tasklist e a Tasklist depende do Taskitem Component. O Taskfilter não precisa do componente Taskitem. Agora não tenho o Taskitem como dependência na Tasklist. O próximo passo é criar um módulo TaskSearch. Eu adiciono as seguintes coisas.

  1. Componente da lista de tarefas
  2. Componente de pesquisa de tarefas
  3. Serviço de Tarefa

Bem, eu perdi o componente Taskitem e está quebrado. A lista de tarefas sempre depende do Taskitem, mas essa dependência está oculta no módulo. A reutilização de componentes torna-se mais difícil e cria uma fonte adicional de erros.

Ok, enquanto lia o guia de módulos, encontrei esta linha

Componentes, diretivas e tubos devem pertencer a exatamente um módulo.

Assim, o exemplo mostra exatamente a preocupação que é levantada aqui. Não pode haver nenhum componente compartilhado. Então, do meu exemplo, eu teria que dividir tudo em módulos.

Enquanto trabalhava nos erros estranhos e não indescritíveis que surgem ao usar o ngModule, também descobri que os componentes de extensão agora não funcionam tão bem quanto antes. Eu tinha um conjunto de componentes com as dependências necessárias que eu poderia simplesmente estender. Agora eu tenho que cuidar de importar as dependências no módulo em que incluo meu componente estendido.

@DaSchTour em seu exemplo, Taskitem deve fazer parte do módulo Tasklist ... então seriam dois componentes em um módulo logicamente, não um para cada.

Como @sirajc apontou, um padrão de design típico seria ter um componente inteligente superior, seguido por componentes burros adicionais... padrão de componente ou por padrão de recurso relacionado), não apenas um componente por módulo, a menos que você esteja apenas construindo componentes de terceiros ou algo assim.

@qdouble @DaSchTour É verdade que a nova arquitetura não significa necessariamente que você liste todos os seus componentes em um arquivo, mas olhando para o aplicativo que estamos construindo, eu atualmente iria com esta declaração de @DaSchTour

Tenho a sensação de que há aqui um descompasso entre o design e a realidade.

Portanto, temos vários componentes representando pequenas unidades na página, como TaskListItem que são 100% vinculadas a uma visualização especial. Criar módulos para cada uma dessas páginas seria um exagero total. No nosso caso, há muito poucas razões para dividir em vários módulos, mas muito mais razões para encapsular componentes.

tl; dr
É legal poder definir algumas dependências em nível de módulo, mas é muito triste que não possamos mais definir dependências em nível de componente

@DaSchTour , No componente do botão material2 , está vinculado ao módulo para torná-lo independente. Quem precisar usar o botão pode importar ButtonsModule . Além disso, se você vir o código do módulo, ele contém dois componentes MdButton e MdAnchor , embrulhar em ButtonsModule torna as coisas mais fáceis de usar

Eu estou querendo saber se é possível criar algum objeto híbrido de componente/módulo que mescle os dois conceitos em um para evitar a duplicação de arquivos. Essencialmente, ser capaz de declarar um componente como um módulo uma vez e importá-lo como um módulo, conforme necessário. Isso honraria a abordagem atual, mas minimizaria o clichê.

@choeller Concordo que ter módulos é uma boa adição, removendo dependências no nível do componente, mas parece errado.

Continuando com o que outros escreveram acima, acho que a ideia central aqui não é experimentar a miséria de um projeto enorme com um módulo enorme com centenas de componentes. Em vez disso, é construir um aplicativo a partir de um número razoável de NgModules de tamanho médio. Grande o suficiente para que não sejam triviais, pequeno o suficiente para que você não tenha um grande número deles; divididos ao longo de linhas de falha que tenderiam a facilitar a reutilização e a modularidade no sentido antiquado da ciência da computação de alta coesão e baixo acoplamento.

Ao fazer isso, os módulos devem se tornar um conceito bastante útil para serem usados ​​em grandes projetos.

Isso está muito bem resumido @kylecordes. NgModules ajuda na boa composição do Application. Pequenos módulos reutilizáveis ​​compõem toda a aplicação.
Outro benefício inclui a disponibilidade ambiental das diretivas. Anteriormente, costumávamos adicionar ROUTER_DIRECTIVES em todo o aplicativo. Agora RouterModule.forRoot() faz isso por nós.
BrowserModule, CommonModule, FormsModule faz mais sentido do que incluir diretivas em cada componente.

O MaterialModule, por outro lado, fornece tudo e, se você precisar de um controle mais preciso, o ButtonsModule etc. nos ajudará.
Essa é a beleza da composição. Abrace-o e crie seu Symphony

Além disso, está o LazyLoading. Se não for NgModules, como se pode definir o número de componentes e serviços que precisam ir juntos para criar uma unidade roteável. Você não pode baixar arquivos soltos, pois isso levará a um grande número de solicitações de rede. Caso contrário, você precisa criar um bundler onde lista todos os arquivos dependentes para criar um bundle. O NgModule faz isso com uma sintaxe intuitiva.

@kylecordes

Continuando com o que outros escreveram acima, acho que a ideia central aqui não é experimentar a miséria de um projeto enorme com um módulo enorme com centenas de componentes. Em vez disso, é construir um aplicativo a partir de um número razoável de NgModules de tamanho médio. Grande o suficiente para que não sejam triviais, pequeno o suficiente para que você não tenha um grande número deles; divididos ao longo de linhas de falha que tenderiam a facilitar a reutilização e a modularidade no sentido antiquado da ciência da computação de alta coesão e baixo acoplamento.

Essas linhas de falha não seriam muito diferentes para desenvolvedores de aplicativos versus desenvolvedores de bibliotecas. Os desenvolvedores de bibliotecas deveriam estar em minoria, mas essa parece ser a principal reclamação. Ao construir uma estrutura reutilizável, o objetivo de querer minimizar o tamanho do módulo leva a muito ruído extra.

@sirajc

Além disso, está o LazyLoading. Se não for NgModules, como se pode definir o número de componentes e serviços que precisam ir juntos para criar uma unidade roteável. Você não pode baixar arquivos soltos, pois isso levará a um grande número de solicitações de rede. Caso contrário, você precisa criar um bundler onde lista todos os arquivos dependentes para criar um bundle. O NgModule faz isso com uma sintaxe intuitiva.

Consegui fazer isso facilmente com o roteador antigo simplesmente usando um componente que funcionava como um contêiner para uma seção do meu aplicativo. Este módulo trouxe apenas os componentes diretos necessários, que trariam suas próprias dependências. Qualquer carregador de módulo decente seria capaz de carregar a cadeia de dependência (via importações) desse componente sem incluir todas as subdependências no componente de nível superior. O mesmo vale para os empacotadores que devem usar algum tipo de lógica de resolução de módulo. Resumindo: não há razão, de uma perspectiva de carregamento lento, para que um desenvolvedor precise declarar todas as dependências contidas no componente de nível superior.

Realmente parece que o ngModule é uma solução em busca de um problema ...

Há algo a ser dito sobre ser capaz de abrir qualquer componente, olhar para sua matriz de diretivas e saber exatamente de quais componentes/diretivas depende. É mais detalhado ter que importar um componente de botão entre os vários componentes que o usam? Sim, mas eu prefiro ter algum clichê extra e ter as coisas explícitas e imediatamente escaneáveis ​​do que pesquisar na árvore de componentes/módulos para ver como o componente Y está usando o componente X em seu modelo sem nunca importá-lo.

O argumento que está sendo feito acima é que, se alguém desejar manter os componentes isolados uns dos outros, eles poderiam criar um módulo para cada componente - mas nesse ponto você está escrevendo ainda mais clichê do que o componente original já teve.

Obviamente, existem outros benefícios no ngModule que eu não abordei e, embora haja benefícios em poder agrupar seções de um aplicativo em módulos de recursos, realmente parece um retrocesso quando se trata de clareza e de ter componentes encapsulados em pedaços de código que não vaza escopo em todo o lugar.

Parte da "venda difícil" que a equipe do ng2 teve que fazer para a comunidade do ng1 foi "sim, você terá que importar e declarar suas diretivas para cada componente, mas confie em nós, você apreciará ser mais explícito conforme seu aplicativo cresce". Eu acredito muito em sofrer com um pouco de repetição por uma questão de legibilidade e escaneabilidade em um ambiente de equipe de grande escala, onde um membro da equipe pode estar trabalhando apenas em um subconjunto muito pequeno de componentes em um determinado momento.

No mínimo, não vejo nenhuma razão pela qual ngModule e a propriedade Directives/pipes não possam coexistir. A alternativa é que cada componente em cada aplicativo escrito para ng2, até RC5, agora está usando código obsoleto que precisa ser refatorado de forma não trivial. Essas não são realmente o tipo de mudanças que eu esperaria tão tarde no desenvolvimento... é bem desconcertante honestamente.

O ngModules requer essencialmente uma reescrita da maioria dos aplicativos para que eles sejam estruturados corretamente ... mas o maior equívoco é que eles estão forçando um nível de escopo específico quando a realidade é que seus módulos podem ser tão grandes ou tão pequenos quanto você deseja ser.

Se você absolutamente precisar criar um novo módulo para cada componente, isso resultará em mais clichê = válido.

A maioria dos aplicativos deve exigir que você crie um módulo para cada componente = inválido (especialmente se você estiver usando padrões de componentes inteligentes/burros e padrões de recursos)

Pela primeira vez hoje, senti a fadiga do lado cliente / JavaScript que vários colegas me transmitiram. Perdi inúmeras horas nos últimos dias tentando refatorar nosso aplicativo RC4 para usar os novos módulos RC5.

Eu definitivamente concordo com vários sentimentos neste tópico, particularmente sobre dar aos desenvolvedores uma escolha em termos de como eles desejam estruturar suas dependências de componentes. Não gosto que um ngModule maior dilua o gráfico de dependência claro entre componentes e que ngModules menores adicionem código clichê adicional a cada componente. Ao analisar um módulo, tudo o que sei é que pelo menos um dos componentes referenciados precisa de coisas das importações do módulo ou declarações de irmãos. Se eu dividir um módulo em vários outros módulos, basicamente fico com tentativa e erro para determinar quais dependências os novos módulos exigem (a inspeção cuidadosa do modelo de componente ajuda, de certa forma).

Finalmente, se eu "esquecer" de exportar componentes, meu componente simplesmente não renderiza, sem erros. É fácil de encontrar se você tiver um gráfico de módulo muito plano, quase impossível quando você tiver vários níveis!

Nesta fase estou desanimado, desapontado e desanimado. Juntei uma equipe de desenvolvedores e partes interessadas nos negócios com uma tecnologia que agora não sei se posso levar adiante. Eu realmente espero que um equilíbrio melhor possa ser encontrado.

Nesta fase estou desanimado, desapontado e desanimado. Juntei uma equipe de desenvolvedores e partes interessadas nos negócios com uma tecnologia que agora não sei se posso levar adiante. Eu realmente espero que um equilíbrio melhor possa ser encontrado.

Acho que o ponto aqui é que há um número gigante de desenvolvedores esperando que essa tecnologia esteja pronta para produção e, embora seja chamada de Release Candidate, cada novo candidato traz mudanças radicais e parece mais um alfa.

Tenho certeza de que muitas equipes passaram horas na arquitetura de seus novos aplicativos e agora está tudo maluco.

Qual será a próxima mudança de ruptura? Eu não posso nem imaginar, mas temo que alguém encontre uma maneira de introduzir a próxima mudança de ruptura.

Da postagem do blog RC5:

Se você escreveu algum código Angular 2, provavelmente já se perguntou "mas por que eu tenho que listar todas essas coisas!?" - especialmente se você notou que certas diretivas e pipes no Angular 2 são "especiais" - eles estão disponíveis para todo o seu aplicativo sem que você faça nada ( *ngFor / *ngIf / *ngSwitch, por exemplo).

Eu pessoalmente não vejo essa pergunta feita por ninguém há algum tempo. Até o RC5, a equipe Angular, recursos de aprendizado on-line, livros etc. deixaram bem claro por que essas declarações são necessárias - e parece que todos aceitaram (e alguns abraçaram) esse fato há muito tempo.

Quanto às perguntas sobre por que alguns são "especiais" e não precisam ser declarados, não acho que alguém argumentaria contra a existência de uma lista de diretivas críticas de "baixo nível" que são tão onipresentes para garantir serem "abençoadas" como disponível globalmente pelo titular da plataforma (equipe Angular).

Se o código já está presente para lidar com a elevação das diretivas em um único ngModule, e esse código funciona invisível para o usuário final, qual é o mal em permitir ambas as abordagens? Essa é uma pergunta genuína, pois posso não estar ciente de algumas das complexidades em torno do que pode acontecer se um desenvolvedor combinar a abordagem. Existem muitas outras "escolhas divididas" em Angular 2 - formulários orientados por modelo versus modelo, 3 opções de idioma diferentes, decoradores de entrada / saída / host versus abordagem de propriedade - qual é o dano em outro neste momento?

Eu poderia continuar, mas o ponto que estou tentando fazer é que a equipe e a comunidade do Angular investiram um pouco de tempo para martelar a mensagem de que ser mais explícito é uma coisa _boa_, apenas para entrar em _lançamento candidato 5_ de todos os tempos -- para nos apresentar uma solução que não tem sido um problema há algum tempo.

Alguém da equipe está com vontade de participar? Eu não quero que isso se torne uma câmara de eco – eu adoraria ouvir o outro lado do argumento. Parece que algo tão grande surgiu do nada, sem considerar coisas como ferramentas, treinamento ou quão perto da versão final aparentemente estamos.

Esta discussão levantou um problema muito grande para muitos desenvolvedores que queriam começar a desenvolver cedo com o altamente esperado angular 2 : mudanças radicais. Fiz várias provas de conceito baseadas no angular 2 desde o beta 17 e fiz com que empresas e organizações importantes o adotassem. Não me arrependo, mas também não tenho certeza se fui bem. Alguns dos projetos mais recentes foram um POC e a batalha foi contra o Vue.js. Angular 2 claramente venceu essa luta. Mas hoje, com toda a reescrita de código, mudanças de última hora, lançamento não muito RC, as pessoas começam a me perseguir e fica bem sério. Não teria sido o caso se eu oferecesse um desenvolvimento Vue ou React e isso é muito frustrante por causa do descrédito que o Angular 2 pode colocar as pessoas.

Parece-me que não compartilho da mesma definição de Release Candidate que o Angular Team.

Quanto ao tópico, o NgModule, eu assino totalmente @jpsfs , se você tiver que listar todos os seus componentes e micro-componentes dentro da sua declaração de módulo, é melhor você ter uma função prune em algum lugar ou ser o rei da modelagem porque por mais poderoso que seja, é muito sensível para projetos de grande escala...

Acho que esse nível adicional de modularidade era quase inevitável; e que vários frameworks concorrentes acabarão com algo análogo.

Eu me pergunto, porém, se era realmente necessário tornar este novo sistema de módulos de granulação grossa completamente ortogonal ao sistema de módulos subjacente, ou se poderia ter sido possível fazer cada diretório de nível superior e todos os módulos Es6 contidos nele, implicitamente compreendem um NgModule de granulação grossa. Talvez esse mecanismo orientado por convenção possa ser adicionado ao mecanismo atual e, portanto, remova o clichê do NgModule para projetos dispostos a seguir tal convenção.

(Claro que também compartilho a frustração com os outros aqui, de mudanças tão significativas no estágio "RC" ... modularidade, e as forças que o impulsionam (carregamento lento, pré-compilação) muito mais perto do início do projeto em vez do estágio de lançamento. sabia então o que sabemos agora...")

Se o suporte à compilação for a principal razão por trás da aparência do ngModule, ele definitivamente não deve substituir o escopo existente baseado em componentes para diretivas e pipes.
Por outro lado, baseando-se na configuração e dependências da rota, o compilador angular poderia, teoricamente, dividir o código do aplicativo nas unidades de compilação apropriadas (módulos).

Pessoalmente, sinto que essa mudança está trazendo um baixo padrão sem muita vantagem.

Eu poderia argumentar que, em vez de usar módulos, poderíamos ter usado componentes como unidades do aplicativo. Isso é provavelmente o que as pessoas estavam fazendo antes do rc-5.

Se os módulos forem necessários para propósitos internos desta estrutura (como carregamento lento e coisas relacionadas), eles devem ser ocultados do desenvolvedor de alguma forma para não poluir o código e piorar a experiência de codificação. E nem estou falando de manutenção...

A primeira vez que vi o angular2 pensei: 'Ei, eles estão indo na direção certa com isso, parece que aprenderam algo com o angular 1'. Você abandonou os módulos internos do angular 1 e, em vez disso, usou os módulos ES, outras alterações também foram bem-vindas (componentes, texto datilografado e assim por diante)

Mas quanto mais eu espero que isso fique estável, mais isso me faz estremecer por causa de mudanças bruscas, falta de documentação e mensagens de erro ruins. Agora você vem com este NgModules e basicamente desfaz pelo menos uma grande coisa que você muda desde o angular 1.

Pior ainda, se eu tiver um aplicativo que começou com rc-2 ou 3 (que eram teoricamente quase estáveis), agora tenho que fazer muito trabalho para criar um bom aplicativo angular2 rc-5 e preciso explicar de alguma forma o cliente e outros desenvolvedores isso. E mesmo se eu fizer isso, Deus sabe o que você vai mudar em seguida e meu trabalho pode ter sido perdido.

Eu sei que o angular 2 está em estágio inicial há um tempo, mas somos RC-5, as pessoas têm projetos bastante sólidos usando o Angular 2 agora e você ainda está fazendo alterações não apenas no ponto de vista da API, mas também no caminho de pensar em Angular.

Não é bom ngFor e algumas importações mudam ou que a injeção de componentes muda dinamicamente 3 vezes em 5 lançamentos, mas isso eu posso aceitar e entender. Trazer mudanças que quebram não apenas os aplicativos, mas a maneira como os desenvolvedores pensam nesse framework tão tarde no ciclo de desenvolvimento, infelizmente não posso aceitar.

De qualquer forma, como você pode ver, muita gente concorda com o que eu tenho a dizer e alguns ficam ainda mais irritados. Você tem um framework enorme no qual as pessoas confiam (porque o Google principalmente), mas você não pode apostar tudo nele ou pode ter uma surpresa, pois todo mundo tem escolhas (e quando se fala em JS, existem MUITOS).

Se o novo Módulo tivesse um modelo, poderia ser o Componente. Pense nisso.

O próximo passo seria mover todas as variáveis ​​e funções de Componentes para a classe Module. A sério. Então tínhamos uma enorme biblioteca central de _todas as ações possíveis_ dentro do nosso módulo brilhante. Isso seria incrível! Não sei por que você parou na centralização de declarações e dependências. Há muito mais linhas de código estruturadas e descentralizadas lá!

Alguém da equipe principal pode opinar sobre tudo isso? A partir das notas da última reunião semanal, a equipe está avançando com a remoção das APIs obsoletas.

@mhevery

Toda essa coisa de içamento quebrou meu aplicativo muito sutilmente quando atualizei hoje.

  • Eu tive que mudar o seletor de um componente de classe para elemento, porque em um componente totalmente não relacionado, essa classe é usada para estilizar e de repente começou a instanciar o componente.
  • Tenho certeza de que #10850 só existe, porque eu tinha dois componentes chamados SpectrumComponent (uma página inteira para navegar sem um seletor e um componente "compartilhado" usado em vários componentes para visualização com seletor). O içamento provavelmente fica confuso com isso - as declarações directives: não.

Para meus componentes SVG, isso agora se torna um problema maior, porque não posso usar um elemento personalizado lá. Ainda não sei como definir o escopo deles para garantir que seus seletores de classe não acionem uma instanciação de componente em nenhum outro lugar (!) no aplicativo.

Parece estar em voga nos dias de hoje ignorar o significado de "Beta" e "Release Candidate" (o ASP.NET Core é outro exemplo de alto perfil) em grandes projetos. Mas ser confrontado com mudanças que têm o potencial de quebrar silenciosamente um aplicativo literalmente em qualquer lugar é mais frustrante do que deveria ser. Eu realmente espero que as promessas que vêm com essas mudanças dêem frutos em breve.

ngModules faz sentido. Remover a capacidade de declarar/fornecer no nível do componente não.

Pequeno exemplo

Eu tenho um aplicativo que contém vários diálogos diferentes (alguns simples - vamos chamá-los de simples-1 e simples-2, e um complexo que contém outros componentes - vamos chamá-los de complexo 3).

No momento, tenho uma estrutura de pastas simples (obviamente, o aplicativo fica de fora disso)

- 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

Para mim, este é um conjunto de recursos perfeito para colocar em um módulo de recursos isolado. Então eu adiciono

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

E eu adiciono Simple1Component, Simple2Component e Complex3Component como declarações ao DialogsModule. Perfeito, funciona bem e faz todo o sentido.

Mas...

E quanto a todos esses componentes internos no complexo-3. agora tenho duas opções

  • Adicione todos os componentes e serviços complexos externos ao DialogsModule. Esta é uma decisão ruim porque quebra o encapsulamento do complexo-3 porque agora tudo no módulo de diálogos sabe sobre seus componentes internos (internal-component-1, internal-component-2, internal-service-3)
  • Faça do complex-3 um módulo por si só. Isso corrige o problema de escopo (e acredito que posso exportar módulos de outro módulo para que o cliente só precise importar o módulo wrapper), mas agora me deixa com uma mistura de componentes e módulos para grupos semelhantes (diálogos).

Nenhum deles realmente faz sentido e, à medida que o aplicativo aumenta, o conflito entre os dois só aumenta.

A única solução sensata/óbvia/sustentável para mim seria usar o módulo para exportar os componentes de nível superior (simples-1, simples-2, complexo-3), mas deixar o complexo-3 _component_ definir seus próprios componentes internos.

/cc: @robwormald

Eu estive pensando sobre o que @kylecordes disse anteriormente sobre usar o sistema de módulo Typescript existente para definir coleções de código de grãos do curso, em vez de adicionar a nova coisa ngModules. Gostaria de apresentar um exemplo para consideração, que usa módulos Typescript para definir ngModules de forma 1-para-1. Comentários e pensamentos são bem-vindos.

https://github.com/jbalbes/autoNgModule

10901

Eu posso ter perdido alguma coisa, mas a maneira como a injeção de dependência funciona com módulos não carregados lentamente pode se tornar um grande problema para "Grandes Projetos" (o meu não é e já está sofrendo).

isto é interessante. já temos um aplicativo corporativo em Angular1. e estamos usando requirejs para definir pacote(s) para vários módulos (cada módulo contém 10-20 diretivas/serviços/filtros). agrupamos esses pacotes em um único arquivo para produção (exceto as diretivas principais). as diretivas são carregadas com preguiça no aplicativo quando são usadas (temos uma diretiva principal que carrega com preguiça as diretivas necessárias).

nossos modelos de página de roteamento de aplicativos estão hospedados no aplicativo cms, e os usuários do cms podem arrastar/soltar widgets de interface do usuário baseados na diretiva principal entre diferentes modelos de página (é por isso que precisávamos de um suporte de carregamento lento para diretiva para reduzir o tamanho do arquivo de script principal no carregamento do navegador como a maior parte de nossa aplicação é baseada em widgets baseados em diretivas)

Angular1 permite o carregamento lento de diretivas para um módulo, obtendo referência aos provedores de registro.
é este tipo de componentes de carregamento lento para um módulo e compilá-los para dom possível em Angular2?

Concordo com o que outros sugeriram que ngModules é uma solução à procura de um problema. O benefício potencial do LazyLoading em minha mente não justifica a depreciação forçada de dependências de diretivas/pipes de componentes. Talvez eu esteja errado aqui, mas sinto que a maioria dos aplicativos não verá nenhum benefício real do Lazy Loading, que para mim é o único benefício verdadeiro fornecido pelo ngModules.

Talvez o ngModules esteja tentando (e talvez tenha sucesso) tornar a estrutura/padrões de desenvolvimento mais agradáveis, mas com base no pouco que analisei e discuti sobre a API até agora, está se movendo em uma direção que é apenas mais complicada para seguir e manter.

Além disso, realmente precisamos de outro sistema de módulos?

Ninguém pode contestar que o NgModule adiciona um novo tipo de coisa com a qual não tínhamos que lidar antes. E eu, tanto quanto qualquer um, aprecio muito a simplicidade pré-RC5, especialmente de programas muito pequenos, que foram perdidos. Eu também sinto muita falta de poder dizer às pessoas que o Angular 1 tinha seu próprio sistema de módulos, mas com o Angular 2 nós apenas usamos o sistema de módulos da linguagem subjacente. Ops.

No entanto, na verdade, existem muitas pessoas, incluindo muitos líderes técnicos e outros tomadores de decisão em grandes empresas tentando construir grandes coisas, que estão extremamente interessados ​​em carregamento lento e pré-compilação de modelos... Ambos estão substancialmente habilitados por NgModule.

Mais uma coisa. A parte que menos gosto nos novos módulos Angular é o nome. A palavra módulo, é tão sobrecarregado. Eu estava falando sobre isso para alguns outros desenvolvedores aqui ontem, e nós meio que gostamos da palavra "pacote", ela meio que captura uma ideia semelhante bem e não tem um monte de coisas concorrentes com o mesmo nome, pelo menos não no ecossistema JavaScript.

@kylecordes questão sobre o nome https://github.com/angular/angular/issues/10087

A lógica ali apresentada não desqualificaria também o uso da palavra 'módulo', uma vez que conflita com tantos, se não mais, conceitos?

@Barryrowe não poderia ter dito melhor - realmente parece que a maioria dos aplicativos não se beneficiará disso - acaba sendo uma complexidade adicional? Espero que não.

Eu me pergunto, porém, se era realmente necessário tornar este novo sistema de módulos de granulação grossa completamente ortogonal ao sistema de módulos subjacente, ou se poderia ter sido possível fazer cada diretório de nível superior e todos os módulos Es6 contidos nele, implicitamente compreendem um NgModule de granulação grossa. Talvez esse mecanismo orientado por convenção possa ser adicionado ao mecanismo atual e, portanto, remova o clichê do NgModule para projetos dispostos a seguir tal convenção.

Este é um ponto chave. Os ESModules funcionam muito bem para estruturar um aplicativo se você estruturar seu aplicativo corretamente. Por exemplo, você pode disponibilizar facilmente uma exportação profundamente aninhada no nível superior de sua API simplesmente exportando-a novamente em um nível superior. Também sou a favor de adicionar mais convenções opcionais ao quadro em geral.

A primeira vez que vi o angular2 pensei: 'Ei, eles estão indo na direção certa com isso, parece que aprenderam algo com o angular 1'. Você abandonou os módulos internos do angular 1 e, em vez disso, usou os módulos ES, outras alterações também foram bem-vindas (componentes, texto datilografado e assim por diante)

Mas quanto mais eu espero que isso fique estável, mais isso me faz estremecer por causa de mudanças bruscas, falta de documentação e mensagens de erro ruins. Agora você vem com este NgModules e basicamente desfaz pelo menos uma grande coisa que você muda desde o angular 1.

De fato, o Angular 2 deveria alavancar a rica pilha de tecnologia da Web emergente que não estava disponível quando o AngularJS foi desenvolvido. No entanto, embora a justificativa para muitas das decisões de design feitas para o Angular 2 tenha sido "os componentes da Web devem ser suportados", ironicamente, a estrutura está divergindo dos padrões de maneiras cada vez maiores. Agora, existem boas razões para divergir do padrão, quando os padrões são ruins.

Eu sinto que o framework não está usando suas ferramentas principais para seu pleno efeito. Por exemplo, as declarações TypeScript não são exatamente idiomáticas e estão repletas de any e any[] . Eles também ignoram recursos poderosos de linguagem que melhoram a usabilidade e a capacidade de ferramentas das APIs. Eles também contêm coisas abomináveis ​​como export declare type Type = Function .

Curiosamente, parece que um bom número de decisões acabou por ser relacionado ao Dart. Dart não é algo com o qual a maioria dos usuários do Angular se importa. Ele tem uma noção muito diferente de quais são os tipos e como eles são usados ​​em comparação com o TypeScript. A interoperabilidade do Dart <-> JavaScript geralmente não é inicial.

@aluanhaddad , a implementação do dart foi bifurcada em um projeto separado recentemente, então esperamos que algumas de suas preocupações sejam resolvidas em breve.

Essa mudança adicionou um grau significativo de complexidade, tanto em termos de LOC geral quanto de modelagem mental de dependências de componentes. Meus arquivos de componentes são um pouco mais limpos, mas às custas da definição de dependência explícita e in-loco e vem com a adição de arquivos .module de sentimento redundante.

Reduzir o clichê parece uma coisa boa, mas eu diria que pode ser exagerado. Além disso, parece que esse esforço específico de redução do clichê é melhor descrito como um movimento do clichê em oposição a uma redução total.

Acho que o angular está tendendo a um início rápido mais difícil e complexo. Já há muito o que lidar em termos de configuração da cadeia de ferramentas e a lista de arquivos e coisas que devem ser compreendidas (se for para aderir às práticas recomendadas) até mesmo para o aplicativo mais básico que está crescendo.

. @jbalbes obrigado, é bom ouvir isso.

@radusuciu você está absolutamente correto, isso não é uma redução no clichê, mas uma transferência desse clichê para outra área do aplicativo. Como já foi dito por outros, não há aqui conflito entre o escopo do nível de componente e o escopo do nível do NGModule. O que precisamos é de um escopo granular para que possamos escolher quais componentes, diretivas, pipes e serviços devem estar disponíveis para diminuir os rasgos do aplicativo com base em seu uso e semântica específicos do aplicativo

Não é de se admirar que os módulos acrescentem ainda mais complexidade de valor real duvidoso ao autor do aplicativo. Eles não faziam parte do design original e parecem uma adição tardia, apenas adicionada porque outras coisas atingiram uma parede e não puderam ser feitas para funcionar (carregamento lento, compilação etc...) sem que outra grande mudança fosse feita.

Eu não acho que todas as implicações para o desenvolvimento de aplicativos versus "fazer os outros recursos prometidos funcionarem" estavam no topo da agenda quando foram adicionados, mas à medida que mais e maiores aplicativos são convertidos para RC5, eles estão começando a ficar mais claros.

Eu nem comecei a tentar converter meu aplicativo para módulos, provavelmente ele morrerá no RC4. Eu sei que muitas partes precisarão ser completamente retrabalhadas e tudo que eu conseguiria com todo esse esforço é estar mais perto da próxima mudança de ruptura RC com pacotes de tempo de execução ainda maiores porque a minificação, certamente algo bastante básico e fundamental, está quebrada . Os RCs devem ficar mais estáveis ​​e se sentirem mais acabados à medida que progridem, isso simplesmente não acontece.

Gang, NgModule é uma irritação, como muitos explicaram com eloquência. Mas na prática não é tão grande assim. Por aqui (Oasis Digital / Angular Boot Camp) já atualizamos inúmeras pequenas coisas, e algumas não tão pequenas, para o RC5, e isso foi feito em pouco tempo (depois de muito tempo de estudo e compreensão).

O aplicativo de todos será afetado de maneira diferente. Além disso, acho que sua atitude para mudar e mudar no Angular 2 possivelmente será diferente se você estiver focado em entregar um aplicativo versus se você também estiver vendendo treinamento e suporte para o Angular 2. Para mim, todo o trabalho para atualizar para o RC5 seria seria um esforço completamente morto e desperdiçado - ele realmente entregaria benefícios negativos (pacotes maiores), então é difícil justificar.

Apenas pensei em dar meus pensamentos sobre o outro lado de um empurrão de cinco dias em nossa plataforma para chegar ao RC6 * (estamos nas noites, RC6 tecnicamente ainda não caiu no momento da redação). Sinto que, embora meus comentários originais ainda sejam válidos, há uma sensação de alívio por ter alcançado esse marco. As maiores dificuldades continuam usando a nova sintaxe de roteamento - muitas regras vazias de path: '' ! (Eu discordo), mas isso é algo que provavelmente vamos abstrair.

Para NgModules nas noites, devo dizer que as mensagens de erro estão melhorando, tornando todo o processo um pouco mais fácil de trabalhar. Componentes e Diretivas são normalmente chamados quando não estão configurados corretamente com informações suficientes para que você não esteja percorrendo uma enorme árvore de dependência do NgModule para encontrar o problema. O principal problema que encontramos agora é apenas a falta de funcionalidade em páginas sem mensagens de erro óbvias. Isso geralmente ocorre porque um componente não foi declarado ou importado/exportado corretamente. É um pouco complicado, mas com educação é fácil de lidar. O teste é agora nosso próximo impulso, está completamente morto na água. Mas, como o impulso de funcionalidade, chegaremos lá no final.

Respiramos fundo, fizemos outra coisa por alguns dias e depois destruímos. Estamos nos segurando firme para o próximo passeio, seja lá o que for! Boa sorte a todos que são afetados por isso de uma maneira pequena ou grande. Teria sido bom ter algum tipo de diálogo da equipe Angular sobre isso. O problema mais difícil que enfrentamos foi a falta de comunicação. Ainda não sabemos o que está nos cartões para NgModules As notas da reunião da semana passada não ofereceram informações. Vamos ver o que acontece essa semana!

@SaltyDH Acho que este é um feedback valioso.
Acho que as reclamações sobre comunicação não são muito apropriadas.

O pessoal de implementação cria a nova versão e o pessoal de documentação atualiza os documentos.
Os documentos geralmente estão um pouco atrasados ​​por motivos óbvios, porque eles só podem documentar depois de já terem sido codificados. Escrever documentos também é um trabalho árduo e demorado.

Se você mudar para o próximo lançamento no dia em que foi lançado ou até mesmo usar nightlies, é um pouco injusto reclamar que nem tudo foi comunicado ainda.
A equipe do Angular também não pode saber de antemão o que pode causar dificuldades para o usuário em todos os casos.

Sempre há membros da equipe Angular fornecendo suporte no Gitter e nos problemas.
Você também deve estar ciente de que a carga de comunicação é bastante assimétrica, com alguns membros da equipe Angular para milhares de desenvolvedores.

Concordo completamente que isso é mais fácil na compilação mestre (quase-RC6) com o último ano + de depreciações finalmente desaparecendo.

@kylecordes de que maneira fica mais fácil trabalhar no master?

O documento de design para NgModules (anteriormente conhecido como AppModules quando o documento de design foi escrito) foi lançado há mais de um mês antes do lançamento do RC5, e eu estava meio preparado para isso.
Além disso, como o NgModule era um conceito mais novo, era difícil agarrá-lo completamente e migrar seu aplicativo médio para grande.
O que eu fiz foi primeiro entender completamente as nuances de NgModules e como pensar em NgModules para projetar um aplicativo Angular 2. Em seguida, criei um aplicativo de autoaprendizagem com aplicação de NgModules.
A segunda etapa é - pense em como o aplicativo atual pode ser dividido em módulos e, em seguida, migre-os de cima para baixo. criando um módulo por vez começando com AppModule. Isso realmente ajudou e o App final parece mais organizado.
image

E sim, o Gitter foi realmente útil em fornecer ajuda no NgModule mesmo antes do lançamento do RC5. Post RC5 temos docs e blogs disponíveis para aprendermos muito melhor.

@zoechi Sem atrapalhar muito essa discussão, sinto que devo esclarecer meus comentários. Eu não estava me referindo à documentação, a maioria dos meus entendimentos vieram da revisão de commits e problemas aqui no GitHub, estou bem com isso. Minhas frustrações vêm da falta de representação aqui nesta edição, estamos com 61 comentários e contando. Um simples: "Estamos cientes das preocupações de todos aqui nesta edição, acreditamos realmente que esta é a melhor abordagem para o Angular 2 e reconhecemos as dificuldades que isso causará, mas é melhor para o futuro do produto". O Gitter é ótimo, mas as mensagens individuais geralmente se perdem em um mar de pessoas tentando entender diferentes aspectos do Angular 2. Eu entrei em contato por meio desse meio, mas devido a diferenças de fuso horário ou outras prioridades, não consegui obter o feedback oficial que recebi poderia usar para tomar uma decisão informada. O que ajudou foi este podcast Adventures in angular https://devchat.tv/adv-in-angular/106-aia-angular2-rc5-and-beyond. Isso me deu confiança para avançar com as atualizações do NgModule.

Tudo de bom.

Obrigado pelo feedback de todos, pedimos desculpas por ter demorado tanto para obter uma resposta - estivemos muito ocupados na última semana (migrando aplicativos internos do Google para NgModules, então também sentimos a dor da refatoração)

Deixe-me ver se consigo esclarecer algumas das dúvidas e equívocos aqui.

A primeira coisa a entender sobre @NgModule() (e @Component e qualquer outro decorador Angukar) é que eles são puramente construção de tempo de compilação - eles existem para permitir que o compilador angular descubra um gráfico de dependência em um aplicativo.

Uma versão (simplificada) do que nossos decoradores fazem:

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

Eles não alteram ou modificam o comportamento da classe decorada de forma alguma - eles simplesmente anexam alguns metadados. Angular usa esses metadados para construir seu aplicativo e compilar modelos.

No modo JiT, isso acontece "Just in Time" - entre você chamar bootstrapModule e sua primeira renderização de componente, o compilador do Angular recupera os metadados anexados às classes usando a API Reflect:

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

No entanto, no modo AoT, isso funciona de maneira um pouco diferente - no momento da compilação, nós _estaticamente_ (ou seja, sem executar seu código) extraímos os mesmos metadados do código-fonte verificando os decoradores.

Isso funciona bem quando você está inicializando um único componente, mas ouvimos muitos comentários de desenvolvedores que estão fazendo coisas mais complexas - inicializando vários componentes raiz ou inicializando componentes diferentes com base no status de autenticação etc.

Portanto, enquanto os decoradores @Component nos deram a capacidade de analisar estaticamente um Component, não tínhamos a capacidade de analisar estaticamente de forma confiável um _Application_

Coisas que caem sob o guarda-chuva de um "aplicativo"

  • PLATAFORMA_DIRETIVAS/TUBOS/PROVADORES
  • coisas que você adicionou anteriormente ao bootstrap()
  • configurações de nível do compilador
  • vários componentes raiz
  • uso do lado do servidor.

NgModules introduz a ideia de um conjunto de recursos estaticamente analisável. O interessante é que no modo de compilação AoT, analisamos seu módulo raiz e _geramos_ um ModuleFactory para cada Módulo no aplicativo - esta é a versão pré-compilada de um módulo, que contém _somente_ as fábricas que você referencia estaticamente nos modelos e aquelas que você marcar como "entryComponents"

Como já extraímos as informações necessárias para a compilação Ahead-of-Time, podemos realmente sacudir os decoradores (o ngc lidará com isso automaticamente para o final) - e em vez de agrupar seu aplicativo começando no módulo raiz, você inicia na sua raiz gerada Module_Factory_, que contém apenas o código que é realmente usado em seu aplicativo, para que você não pague multa pela modularidade, e ferramentas como rollup e webpack2 podem funcionar _mais_ eficientemente

mais a seguir na próxima resposta ...

@robwormald Não consigo colocar em um emoji a quantidade de apreço por esse tipo de informação de fundo.

Obrigada!

Outro problema que encontramos que o NgModules resolve:

Considere um caso em que você deseja construir um DialogService ou similar.

Historicamente, você faria algo como:

@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);
      })
  }
}

...que você usaria como

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

Coisas para notar aqui -

  • compilação de componentes no modo JiT _deve_ ser assíncrona, por causa de templateUrls e styleUrls externos
  • um viewContainer aceita um _componentFactory_ - então agora seu código tem um problema: você precisa reescrever o código para alternar os modos (entre JiT e AoT), _ou_ você sempre deve assumir que a API de inserção de componentes é assíncrona. Isso pode ser bom no caso de uma caixa de diálogo, mas se você estiver construindo UIs complexas dinamicamente (pense em um Dashboard ou em uma exibição de grade ou qualquer outra coisa), você incorrerá em uma enorme quantidade de agendamento de promessas desnecessário.
  • Serviços/componentes de terceiros ou compartilhados (como SharedDialogService) têm o mesmo problema, tendo que aceitar _ou seja_ Componentes ou ComponentFactories

Esse problema surge para _qualquer_ aplicativo que está fazendo inserção dinâmica de componentes (que não significa necessariamente carregamento lento) - diálogos, roteadores, etc., todos esperam interagir com ComponentTypes (as classes) em vez de seletores (foo-bar).

Então, quando você adiciona um Component ao seu array entryComponents em um decorador NgModule:

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

O que isso diz ao compilador é "gerar um mapeamento entre MyRandomDialogComponent e seu MyRandomDialogComponentNgFactory compilado" e _armazená-lo no NgModuleFactory em que é declarado_

Assim, uma versão orientada por NgModule do dialogService acima se parece com:

@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);
  }
}

Agora, qualquer componente que você adicionou ao entryModules pode ser recuperado de forma síncrona e inserido dinamicamente na visualização, e seu código _não_ precisa mudar dependendo do modo em que você está, nem bibliotecas de terceiros/compartilhadas precisam se preocupar com a compilação lógica.

Obrigado pela explicação @robwormald

Uma pergunta é: isso exige a remoção de declarações de diretiva/pipe? Existe uma razão pela qual eles não podem coexistir com o NgModule?

Eu sinto que as pessoas, inclusive eu, estão frustradas não com o "novo garoto no quarteirão" NgModule ou qualquer mal-entendido dele, mas porque a "maneira antiga" de fazer as coisas, que parece estar _funcionando bem_ com muitas pessoas, está sendo removidos à força, especialmente nesta fase tardia de RC. Acho que essa é uma distinção importante de qualquer resistência ao próprio NgModule, que não vi muito, que ainda não foi abordada diretamente.

Também vejo que a solicitação pull para remover declarações de diretiva/pipe está ativa (https://github.com/angular/angular/pull/10912) - espero que possamos obter uma resposta sobre este ponto antes que qualquer coisa seja definida pedra.

Desde já, obrigado. Angular foi, sem dúvida, uma alegria trabalhar com e eu aprecio muito o trabalho duro da equipe no ano passado +

Há alguns comentários aqui sobre "escopo global" - isso não entende a mecânica do compilador e dos módulos (o que é totalmente compreensível, isso é algo complexo).

Despejar todo o seu aplicativo em um único NgModule é "bom" da mesma forma que despejar todo o estado do aplicativo em $ rootScope era "bom" no Angular1 (leia-se: funciona, mas o design do aplicativo é ruim)

Em Angular 1, trazer um módulo para um aplicativo mais ou menos "poluía" todo o seu aplicativo, pois tudo era despejado em um único saco injetor.

Em Angular2, NgModues tem alguns mecanismos de escopo muito poderosos que permitem composição sem poluição. Novamente, ele volta para o compilador.

Quando o Angular está percorrendo e compilando seu aplicativo, cada componente que ele encontra é _compilado no contexto em que foi declarado_

Por exemplo - imagine que você tenha um SharedModule com alguma funcionalidade que deseja compartilhar em um aplicativo

@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 {}

Ambos SharedComponentOne e SharedComponentTwo são _declarados_ no SharedModule - as declarações implicam _ownership_ - então ambos os Componentes são de propriedade do SharedModule. No entanto, _only_ SharedComponentOne é _exportado_ do módulo - SharedComponentTwo permanece _private_ para SharedModule.

Se você trouxer SharedModule e usá-lo em outro módulo, assim:

@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 {}

...quando o compilador começa a compilar SomeComponent , ele descobre o seletor shared-component-one , e porque SharedModule (que exporta SharedComponentOne ) é importado para SomeModule , ele sabe que shared-component-one === SharedComponentOne.

Curiosamente, quando o compilador realmente compila o SharedComponentOne, ele o faz "dentro" do SharedModule, o que permite usar coisas dentro do SharedModule que não são expostas ao mundo exterior.

Isso é muito semelhante a como costumava funcionar com Component.directives e, neste caso, eles são iguais.

Considere, no entanto, se você tivesse algo como um recurso de guias:

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

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

Ambos os componentes são de nível superior, não há relacionamento hierárquico no qual confiar. Isso levou à explosão de uma espécie de convenção de pessoas fazendo

export const TAB_DIRECTIVES = [ TabsComponent, TabComponent ]

Um recurso de guias mais complicado pode ter um serviço que gerenciava várias instâncias de guias, então você também precisa lidar com esse caso...

export const TAB_PROVIDERS = [ ... ]

e usá-lo se torna um exercício de lembrar de todas as coisas que você precisa exportar e importar...

import {TAB_DIRECTIVES, TAB_PROVIDERS}

e, em seguida, fornecer todas essas coisas no local certo _em todos os lugares_ que você deseja usá-lo. Também é muito fácil neste ponto esquecer de importar TODAS as coisas que você precisa para um recurso e acabar com falhas silenciosas estranhas ou componentes sendo compilados sem todo o contexto necessário.

Com um NgModule, você pode simplesmente empacotá-los em uma única unidade e passá-la ao redor de seu aplicativo e importá-lo onde for relevante.

Para bibliotecas como o Material Design, que podem ter vários recursos espalhados por vários módulos, você pode aproveitar a mesma semântica de importação/exportação para torná-la ainda mais portátil:

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

puxar esse único módulo permite que todo o seu aplicativo use componentes e, novamente, no momento da AoT, apenas aqueles que você usa serão importados para o código gerado.

Quanto ao motivo pelo qual removemos Component.directives / pipes, ouvimos muitos comentários em ambas as direções. Sentimos que ter duas maneiras de realizar a mesma coisa geralmente é um padrão ruim, então optamos por permitir que as pessoas geralmente escrevam menos código, e aqueles que desejam o escopo explícito oferecido anteriormente pelo Component.directives podem realizar a _mesma_ funcionalidade por escopo no nível do módulo.

No RC5, fizemos uma espécie de içamento automático de Component.directives para o escopo "global". Esta foi uma tentativa de suavizar a transição e, embora tenha funcionado para a maioria das pessoas, o comportamento misto de antigo e novo causou alguns erros estranhos e comportamentos que, embora frustrantes, são temporários. Isso desaparece no RC6 (e as mensagens de erro foram melhoradas)

Por que isso mudou tão tarde no jogo - só podemos nos desculpar. Nós não gostamos de fazer alterações de última hora mais do que qualquer um de vocês. No final do dia, estamos literalmente construindo uma estrutura de uma maneira que nunca foi feita no front-end antes e, portanto, nos depararemos com problemas imprevistos e problemas de design. Este foi um desses casos, e foi fortemente debatido e investigado entre a equipe principal antes de tomarmos a decisão. Novamente, pedimos desculpas pelo problema, mas estamos confiantes de que o resultado líquido é uma maneira muito melhor de construir _aplicativos_, e é por isso que estamos todos aqui.

Obrigado pela paciência de todos. Vou deixar isso em aberto se houver outras questões que não abordei aqui.

Roubar

Belo trabalho, @robwormald

Gostaria de acrescentar mais algumas observações:

Provedores

Rob se concentrou em _declarations_, _imports_ e _exports_. Módulo _Providers_ são diferentes.

@Component.providers vidas! Apenas @Component.directives e @Component.pipes vão embora.

Você pode usar @NgModules.providers e @Component.providers . Eles têm finalidades diferentes:

a) @NgModules.providers _estende_ o aplicativo adicionando provedores ao injetor "principal" (o injetor raiz do aplicativo para módulos carregados avidamente). É assim que o RouterModule adiciona um serviço de roteamento ao seu aplicativo sem que você precise fornecê-lo.

b) provisão de serviço @Component.providers _encapsulates_ dentro do escopo da instância do componente (e sua subárvore do componente).

Ambas as abordagens atendem a necessidades diferentes.

Meu conselho geral: _se você tem um provedor em @Component hoje, deixe lá_

Módulos de recursos

Eles são uma maneira poderosa de organizar seu aplicativo. O capítulo Módulo Angular tem uma seção curta sobre a refatoração de um Módulo Angular monolítico para um módulo de recursos . É bem fácil (pelo menos foi para mim as várias vezes que fiz isso.).

Procuro costuras naturais no meu aplicativo. Eu não enlouqueço. Eu não modularizo todos os componentes.

A razão pela qual o Material Design parece fazer isso é que eles estão tentando tornar mais fácil para nós usarmos o que queremos de uma maneira fina.

Eles terão um módulo de pia de cozinha que simplesmente reexporta tudo. Você poderia simplesmente importar isso e pronto. Mas se estou ajustando meu próprio aplicativo, crio um _módulo de reexportação_ semelhante que exporta apenas as partes do MD que eu quero.

Esse é um padrão que qualquer fornecedor de biblioteca pode seguir e pode fazer sentido na empresa onde montamos nossos próprios "kits" de gadgets aprovados pela empresa.

Descobrindo dependências de declaração

O compilador faz um trabalho muito melhor agora de dizer quando algo está faltando. Se você seguir a prática recomendada e _sempre, sempre, sempre hifenizar_ os nomes do seletor de componentes, o compilador informará quando você tiver um componente não declarado. Ele também pega ligações e diretivas de dados não declaradas/não reconhecidas.

A migração do pré-RC5 promove uma sensação de perda. Temos que fazer o trabalho tedioso de descobrir dependências em nossas listas anteriores directives e pipes . E temos que desduplicar. Este é o desagrado essencial de viver no limite.

Um RC não deve mudar tanto

Sim. Você não terá um argumento da equipe sobre isso. Não foi intencional. Se soubéssemos que precisávamos NgModule , teríamos na versão beta.

Mas IMO, é melhor enviar o produto certo do que seguir servilmente alguma noção do que um RC deve ser e entregar o produto errado. Além disso ... e não é muito confortável dizer ... mas se você tem observado algumas outras grandes empresas de software recentemente, pode ter notado uma noção equivalentemente flexível de "release candidate". É o caminho que nossa indústria segue por algum motivo.

Eu converti vários aplicativos agora e ajudei outros a fazer isso. Uma vez passada a fase "_eles mudaram meu queijo (de novo)_", é uma migração bastante mecânica e todos parecem pensar que estão em um lugar melhor. Talvez eles estejam apenas sendo legais comigo. OTOH, eu não saio com pessoas que são tão legais ;-)

(também, re: o nome)
Trocamos nomes de bicicleta até a morte. Eles foram inicialmente chamados de AppModules (já que descrevem algo de nível superior a um componente, um "App"), mas não era um termo amplo o suficiente. Pacotes, pacotes, barris, globos, etc.

Lembre-se de que não é um substituto para os módulos ES - é um aumento que permitirá que os módulos ES e os módulos ES funcionem melhor para todos os desenvolvedores angulares e, semanticamente, eles são semelhantes ao funcionamento dos módulos ES (importações, exportações, declarações)

Então, nomear é difícil. NgModule é.

Estamos com a API completa para 2.0.0 e, portanto, observaremos os próximos meses após o lançamento para ver quais padrões se desenvolvem e onde podemos adoçar e fazer melhores inferências para 2.1.

Obrigado sinceramente @robwormald @wardbell pelos comentários muito perspicazes. Acho que para mim o maior alívio é

"Estamos com a API completa para 2.0.0, e por isso vamos assistir nos próximos meses após o lançamento para ver quais padrões se desenvolvem e onde podemos adoçar e fazer melhores inferências para 2.1."

É algo que já ouvimos há algumas semanas, mas agora é especificamente no contexto de NgModules, juntamente com todo esse feedback. É a confiança que eu precisava para ir a um conselho e dizer. Terminamos aqui, hora de terminar de construir nosso aplicativo. Também quero estender meus parabéns a toda a equipe e comunidade do ng2 por alcançar esse marco! Tempos emocionantes pela frente.

Eu honestamente acredito que você pode dizer que @SaltyDH. O churn do Angular 2 acabou.

Isso não significa que o Angular 2 terminou de evoluir. Haverá lançamentos futuros. Mas o churn que leva ao 2.0... acabou... acabou!

Muito obrigado pela honestidade e pelos casos de uso explícitos, pessoal. Isso realmente ajuda.

Apenas uma rápida reflexão sobre a nomenclatura e duplicação na API para NgModule, o que considero um pouco complicado.

OMI isso:

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

...poderia ser mais claro e conciso como:

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

1) WRT para nomeação (público e privado vs declarações e exportações), é essencialmente como @robwormald acima e tenho certeza que muitos outros estão explicando

2) (Ignorando a nomenclatura) por que SharedComponentOne precisaria ser repetido? Certamente você poderia dizer que se é uma "exportação", deve ser uma "declaração", para que possa ser desaçucarado dessa maneira?

Apenas meus dois centavos em algo altamente subjetivo 😄 - obrigado novamente pelas explicações detalhadas!

@robwormald @wardbell Obrigado pelas explicações detalhadas.

E como eu disse anteriormente neste tópico NgModules nos ajuda a nos organizar melhor. Um exemplo recente é a criação de Diretivas de Validação para formulários orientados por modelo. Antes do RC5 tínhamos que importar cada diretiva no componente onde estamos criando um formulário. Agora nós apenas o empacotamos em VaildatorModule e importamos o Módulo onde for necessário. Qualquer Validador que adicionarmos posteriormente estará automaticamente disponível para os módulos onde importei ValidatorModule . Só preciso atualizar o template sem me preocupar com dependências.

@JamesHenry declarations , imports e exports são usados ​​para manter NgModules alinhados com os módulos ES6 como nós import , export e declare coisas em módulos ES6.
Eu concordo com o sugaring, as coisas que são exportadas podem ser de-sucedidas em declarações auto magicamente.

@JamesHenry

1), ficamos com importações/exportações porque o modelo mental está mais próximo de como os módulos es funcionam (pelo menos em termos de escopo) - você declara coisas em um módulo, importa coisas de outros módulos e exporta coisas para disponibilizá-las para outras.

2) if it is an "export" it must be a declaration, so it could just be desugared that way? -> isso funciona até você usar um ngModule para reexportar, como no exemplo MaterialModule acima - há muitos casos em que você pode usar um ngModule para reexportar algo declarado em outro módulo e então as inferências meio que desmoronam.

@robwormald Ótimos comentários! definitivamente merece um post no blog.

Eu tenho uma biblioteca de diálogos que usa @NgModule agora e posso dizer que vejo usuários lutando ao tentar adicionar componentes personalizados, pois esquecem de registrá-los em entryComponents , aparentemente isso não é claro o suficiente, mas compreensível, pois é um recurso avançado ...

Tenho certeza que vai afundar com o tempo

@shlomiassaf obrigado!

Deve mencionar também, para casos como o seu:

Observe que quando você usa o roteador do angular, você adiciona componentes às declarações e à configuração da rota, mas _não_ aos entryComponents, apesar do roteador ser a própria definição de entryComponents. (lembre-se - entryComponent === coisa à qual você deseja se referir por Classe, em vez de seletor)

Há um truque legal que qualquer biblioteca pode aproveitar - há um token mágico chamado ANALYZE_FOR_ENTRY_COMPONENTS - veja https://github.com/angular/angular/blob/master/modules/%40angular/router/src/ router_module.ts#L117 para saber como o roteador o usa.

Então, para bibliotecas que lidam com componentes inseridos dinamicamente, você pode fazer algo como:

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

usado como

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

Pode funcionar para o seu caso de uso, pode não funcionar.

@JamesHenry Muito importante que declarations não seja confundido com private . Você está dizendo _Este módulo declara este componente_. Você não está fazendo nenhuma declaração sobre público ou privado. Você está fazendo uma reivindicação de propriedade.

É realmente como o que acontece nos módulos ES6. Qualquer coisa que você definir dentro do arquivo "pertence" ao módulo definido por esse arquivo. Se é público ou não, depende do uso da palavra-chave export .

E como nos módulos ES6, você pode _reexportar_ coisas que você importou.

Eu gosto de pensar em declarations como o "truque" que me impede de ter que colocar fisicamente todos os meus componentes, diretivas e pipes no mesmo arquivo físico (como você teria que fazer com módulos ES6 se você pretendesse todas essas classes pertençam ao mesmo módulo ES6).

Então, para mim, declarations é um substituto para colar esses arquivos em um arquivo enorme. Esse é o _meu_ modelo mental de qualquer maneira.

Uma coisa a notar é a diferença lógica entre provedores e componentes no contexto de um módulo.

Provedores e Componentes são declarados no mesmo lugar ( NgModuleMetadataType ) para que um desenvolvedor sinta intuitivamente que os provedores se comportam como componentes... o que é pensar que um provedor em um módulo resultará em uma instância para esse módulo. .

Como os provedores são gerenciados pelo DI, isso obviamente não é verdade, eles são, na verdade, no nível do aplicativo.
Componentes em um módulo são privados se não forem exportados, isso pode causar confusão.

Eu amo o conceito de módulos, IMO o único problema na API é ter provedores e componentes declarados no mesmo lugar dentro de um módulo... para os recém-chegados é uma coisa difícil de entender.

@wardbell Obrigado Ward, isso é realmente ótimo! Apenas para esclarecer, pois isso acabou de surgir nas discussões, quando dizemos que o Angular 2 é a API completa, de quais namespaces estamos falando aqui? @angular/???

@robwormald Obrigado! Uma ótima dica!!!
Um com sabor de açúcar! irá implementar.

Não sou funcionário do Google e talvez um funcionário do Google não saiba dizer. Só posso relatar o que estou vendo com meus próprios olhos: um congelamento de API muito sério no conjunto de bibliotecas @angular/ .

Há boas ideias que estão paradas na prateleira porque não foram suficientemente boas ou profundas o suficiente para justificar a liberação. É assim que deve ser. Boas ideias nunca param. Mas chegou a hora de dizer _Este é o seu Angular 2.0_.

Temos a prometida remoção da API obsoleta entre agora e "final". Isso tem ajustes ... como qualquer um pode ver olhando para o mestre. Eu sinto que terminamos.

@wardbell , eu concordo com o que você diz sobre exportações.
O index.ts já foi preenchido com

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

agora está reduzido para apenas export * from my.module
descansar todas as coisas limpas fica nas exportações do NgModule como
exports: [ AComponent, BComponent, CComponent, PDirective ] e assim por diante

@wardbell Acho que @NgModules.providers deveria ter sido @NgModules.rootProviders ou @NgModules.appProviders .

Eu sinto que descreve claramente o contexto dos provedores.

@shlomiassaf Isso seria enganoso. O efeito de @NgModules.providers é diferente para módulos ansiosos e preguiçosos. Módulos carregados com lentidão obtêm seu próprio injetor filho, o que significa que _seus provedores_ são adicionados ao injetor _child_, não ao injetor _root_. E assim vai se um preguiçoso carregou um preguiçoso carregou um preguiçoso.

Talvez pudesse ter um nome diferente. Você sabe como isso vai. Mas rootProviders não teria sido uma melhoria pelas razões que acabei de dar.

@wardbell concordou, não pensou nesse cenário.

Só queria aumentar o sentimento de que as respostas e a comunicação completas são muito apreciadas. Se esta é realmente a última das dores de crescimento do rc-to-final, então vamos para as corridas. Obrigado!

Como outros observaram, o feedback da equipe é apreciado. No entanto, esse tipo de mudança durante esta fase de desenvolvimento é sugestiva de erros fundamentais de projeto.
Sejamos honestos com nós mesmos, todos nós cometemos esses tipos de erros, então não há valor em ser crítico, mas quando eu cometo um erro isso me humilha, e espero que me torne mais prudente posteriormente. Não tenho a impressão de que esteja a ter o mesmo efeito na equipa Anagular.

Eu gosto de pensar em declarações como o "truque" que me impede de ter que colocar fisicamente todos os meus componentes, diretivas e pipes no mesmo arquivo físico (como você teria que fazer com módulos ES6 se você pretendesse que todas essas classes pertencem ao mesmo módulo ES6).

Então, para mim, as declarações são um substituto para colar esses arquivos em um arquivo enorme. Esse é o meu modelo mental de qualquer maneira.

@wardbell Talvez eu esteja perdendo algo fundamental, mas não vejo como usar NgModule.declarations é fundamentalmente diferente de importar todos, mas apenas reexportar alguns dos seus ESModules. Ironicamente, a principal limitação dos ESModules é que eles fornecem apenas o conceito de módulos físicos, não lógicos. Não vejo como NgModule melhora isso. É apenas uma sintaxe de agregação diferente, mas não eleva o nível de abstração a um grau significativo.

Além disso, os NgModules falham completamente em resolver um grande problema:

Todo o padrão Function[] é opaco de todas as maneiras erradas. Ele reduz a capacidade de descoberta a zero. É preciso ler a fonte para determinar o que está em uma matriz de provedores. O mesmo vale para NgModule.exports .

Mas IMO, é melhor enviar o produto certo do que seguir servilmente alguma noção do que um RC deve ser e entregar o produto errado. Além disso ... e não é muito confortável dizer ... mas se você tem observado algumas outras grandes empresas de software recentemente, pode ter notado uma noção equivalentemente flexível de "release candidate". É o caminho que nossa indústria segue por algum motivo.

@wardbell A maior frustração sobre o RC para mim é a impressão de que um Beta acabou de ser enviado para o RC por causa do ng-conf e do google i/o. Para progredir, a razão deve ser colocada claramente: foi _marketing_ e como tecnólogos devemos combater a tendência dessas noções flexíveis de maturidade. Você pode conhecer um fabricante de carros popular no vale onde a discussão é sobre se foi certo vender um beta para um produto porque pode ter tirado uma vida. Não quero exagerar, mas, como tecnólogos, devemos falar se é assim que nossa indústria está indo, porque então está indo na direção errada.

Eu gosto da abordagem ngmodule, mas tenho uma pergunta @robwormald :

Eu tenho um serviço compartilhado que não possui componentes, diretivas e pipes. Possui apenas serviços ( forRoot ) e contém todas as classes de modelo de negócios. O app.module importa ServerApiModule.forRoot() portanto os serviços estão disponíveis para toda a aplicação. Os módulos de recursos, que usam os serviços e classes de modelo de negócios, devem importar esse módulo compartilhado? Tecnicamente não é necessário (sem erros), mas do ponto de vista semântico faria sentido (também sem erros). O que devemos fazer com esse tipo de módulos? Importá-los ou não? Eu pessoalmente gosto da segunda possibilidade porque ela diz 'Ei, eu sou um módulo de recursos e preciso desses serviços e preciso dessas classes de modelo de negócios'.

Obrigado por uma resposta!

Então eu posso sentir a dor com bibliotecas/bibliotecas de aplicativos modulares e ngModule.

Mas como disse muitas vezes não misture duas formas possíveis. Isso é e será confuso.

Portanto, a abordagem correta seria declarar um ngModule para cada componente.
Mas como isso o torna muito mais codificador de caldeira para cada componente, essa maneira também não funciona em grande escala.

Portanto, não adicione um novo decorador chamado ComponentModule que seja mais ou menos açúcar para evitar declarar componente e módulo como material.

Por aqui? Se eu ver um componente. Eu sei que DEVE ser parte de um ngModule. Se eu tiver um caso para muitos comonentes para agrupá-los, POSSO usar o NgModule. Se eu quero apenas um componente autônomo como os "componentes antigos" eu uso o ComponentModule e CONHEÇO todas as dependências e que pode ser uma dependência de Módulo para outros módulos, mas não faz parte deles

@nathraQ se a abordagem correta for usar NgModule para cada Componente, e pode muito bem ser, então o NgModule não deveria ter sido introduzido e o Component deveria ter sido aprimorado. Em relação ao clichê, o Angular 2 é tão pesado que pouco importa neste momento.

Muitos frameworks que não possuem seu próprio sistema de módulos usaram convenções com muito sucesso para estabelecer padrões padrão para o layout e a visibilidade das construções. Um homem sábio disse uma vez que você não pode definir convenções após o fato; que eles precisam estar lá desde o início. Eu estava cético em relação a essa afirmação, mas esse desastre prova que ele estava certo.

@aluanhaddad desculpe, discordo. Eu tinha meus casos de uso para apenas um módulo em angular 1.x com gerenciamento de dependência personalizado (como o iniciador deste thread), mas também tive casos de uso para módulos para agrupar um conjunto de controladores, diretivas e serviços.

Ambos são úteis. Agora temos que descobrir como integrá-lo de forma compreensível para todos

Uau, foi uma leitura longa :smile:

Posso ver os prós e contras da nova mudança, mas isso me fez pensar em um cenário com o qual tive problemas no Angular 1.

@wardbell @robwormald -

Se eu usar o padrão SharedModule e importar duas bibliotecas de terceiros (ui-bootsrap vs angular-strap qualquer um?) que usam o mesmo seletor para um componente, digamos my-selectbox

Receberei um erro se tentar importar os dois? direito?

Uma solução que li aqui é reexportar uma das bibliotecas em um módulo personalizado
Mas isso significa que eu preciso continuar atualizando o módulo wrapper toda vez que a biblioteca for atualizada, não?

Além disso, pode acontecer que eu tenha meu próprio seletor de componentes com o mesmo nome (e em grandes projetos que podem acontecer mais de uma vez)

Existe uma solução recomendada para este problema? ou é o "módulo wrapper"?
(Espero que não voltemos a usar um prefixo para seletores, isso não foi divertido)

Desde já, obrigado!

O namespace, ou prefixo, como alguns chamam, geralmente é uma boa ideia, não importa o tamanho do seu projeto. Sim, pode ser mais trivial em projetos menores, mas assim que os módulos de terceiros estiverem envolvidos, eu diria que é quase um requisito - no mínimo, fornece tranquilidade sabendo que as colisões não ocorrerão mesmo que outros módulos sejam atualizados , mas também os desenvolvedores podem identificar facilmente o que pertence a cada módulo sem necessariamente ter que seguir a árvore de dependências.

@nathraQ Todos esses padrões podem ser alcançados com módulos ECMAScript. A introdução de NgModule não nos leva a lugar nenhum e o fato de que bibliotecas como AngularMaterial estão transformando Components em NgModules apenas para preservar o encapsulamento fornecido anteriormente apenas prova o ponto.

@aluanhaddad NgModules está tentando fazer algo muito diferente dos módulos ES, e também não está substituindo o encapsulamento de componentes, ou seja, tanto os módulos ES quanto os componentes não mudaram suas responsabilidades principais. NgModules é o meio pelo qual você descreve a arquitetura em todo o seu aplicativo, e isso ajuda o Angular a entender melhor sua intenção e otimizar de acordo, permitindo coisas como compilar certas partes do seu aplicativo antecipadamente, servir módulos resolvidos dinamicamente de um servidor e assim por diante, todos dos quais não podem ser alcançados com módulos ES. Pelas mesmas razões, um NgModule por Componente não é a regra a seguir.

É verdade que aplicativos mais simples podem não se beneficiar tanto desses benefícios, mas nesses casos o NgModules deve ser menos "incômodo" de qualquer maneira.

@emilio-martinez , como @aluanhaddad escreveu, ES6 e o ​​"old angular 2 way" nos deram o namespace que precisávamos.

Trabalhei em projetos muito grandes com Angular 1, tendo um seletor chamado: mb-product-list pode colidir muito rapidamente com outros se for um projeto grande (mesmo em equipe de 5+ desenvolvedores).

Tentando resolvê-lo com mais namespaces você acaba com: mb-somefeature-product-list que faz os templates parecerem sujos.

Fiquei muito feliz em ver que foi resolvido em ng2 por causa dos metadados directives .
Você pode instalar npm qualquer pacote que desejar e importar apenas o que precisa dele por componente.

O ngModules tem seus benefícios, com certeza, ajuda no carregamento de partes assíncronas e também nos ajuda a escrever menos importações e melhora a produtividade.

Mas usar o padrão SharedModule introduz um namespace global, muito parecido com o que tínhamos em ng1.

Pelo menos com provedores, ele é espaçado pelo token ES6, o local do arquivo.

Com componentes, por causa dos seletores, vai gritar que existem dois componentes com o mesmo seletor.

Eu gostaria que tivéssemos uma maneira fácil de configurar um namespace especial para casos de uso de colisões com componentes compartilhados de terceiros ou locais.

Algo como "substituição do seletor".

Isso é o que eu estava perguntando

Obrigado @robwormald por sua visão detalhada, mas uma coisa de novatos como eu (principalmente, sou um desenvolvedor de back-end). Estou aprendendo Angular 2 e com texto datilografado. Então o conceito do módulo ES6 é meio embaçado para mim
Temos uma estrutura de aplicação complexa. É um aplicativo de análise, onde minha contagem de componentes é quase 60.
E acho que está bem estruturado no RC4. Além do Login não usamos nenhum tipo de roteamento, pois o routernrecria todo o componente. Então, estamos planejando como app.Two guia principal baseado em Tab está lá (1.Analysis 2.Dashboard).
A guia Analytics terá várias guias, cada uma com uma análise única. O painel também terá
várias guias, mas cada guia consistirá em várias análises que foram salvas em
a seção de análise. Então, indo e voltando de várias guias (no painel e na análise)
e também alternando entre a guia Dashboard e a guia Analytics, achamos que o roteamento não servirá
nosso propósito (corrija-me se estou dizendo algo idiota).
Agora o RC5 NgModule meio que quebrando nossa aplicação. Nós realmente não sabemos como
redesenhar nosso aplicativo. Podemos realmente usar a compilação AoT em nosso aplicativo? não é
toda a coisa de AoT é baseada em roteamento?

@shairez NgModules fornece exatamente esse tipo de namespace. Deixe-me tentar esclarecer isso um pouco mais...

A principal coisa a perceber aqui é que um componente é compilado, mais ou menos, "dentro" do módulo em que foi declarado - veja https://plnkr.co/edit/9w10b1Y8Bjr5DDIxOwnC?p=preview para um exemplo.

Observe que existem dois seletores conflitantes ( my-generic-selector ) - cada um dos módulos de recursos importa um deles, é capaz de usá-lo interno a esse módulo, sem poluir nenhum namespace "global".

Tão usado como

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

se expande para

<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>

sem nenhum conflito, porque quando o compilador compila o recurso um e o recurso dois, ele o faz _no contexto do módulo ao qual eles pertencem_, o que evita poluir um escopo global.

@robwormald Claro, isso é incrível e é melhor que o Angular 1 nesse sentido.

O caso de uso sobre o qual escrevi estava se referindo ao padrão de uso de um SharedModule global, conforme sugerido nos documentos .

Se eu tentar declarar GenericSelectorFeatureOne e GenericSelectorFeatureTwo dentro de SharedModule , vou ter um erro certo?

Ou se SharedModule tiver um monte de componentes comuns úteis e eu quiser importá-los para todos os módulos de recursos.

Se meu módulo de recurso tiver um seletor de colisão ou algum terceiro tiver um seletor de colisão com uma das bibliotecas existentes exportadas no SharedModule , ele emitirá um erro, certo?

@shairez Acho que a maioria dos aplicativos terminará com vários "SharedModules" e a probabilidade de colisões é baixa - os módulos são baratos, portanto, não há um grande custo para ter muitos.

Se você tiver idéias sobre como melhorar os documentos, um PR será bem-vindo.

Obrigado, era a resposta que eu estava procurando, vou testar.

Ainda não tenho ideias melhores de como resolver isso com a nova forma de escrever módulos, por isso perguntei aqui, mas assim que testar a solução de vários módulos compartilhados terei mais material para discutir com @ wardbell e enviar um PR.

Obrigado pela ajuda @robwormald !

Nos documentos mais recentes disponíveis em https://angular.io , há _muitos_ avisos sobre antipadrões e bugs que podem surgir facilmente se NgModule s forem compostos incorretamente. Por exemplo

Não especifique provedores singleton em todo o aplicativo em um módulo compartilhado. Um módulo carregado lento que importa esse módulo compartilhado fará sua própria cópia do serviço.

Isso é bastante preocupante. Se você seguir a abordagem testada e comprovada de _primeiro faça funcionar, depois faça rápido_, provavelmente precisará ajustar quais módulos são carregados de forma ansiosa ou preguiçosa com base em métricas empíricas e na estrutura emergente desses módulos à medida que seu aplicativo ou biblioteca se expande. Basicamente, por que um módulo deveria se importar se ele é carregado com preguiça ou avidamente?

Outro problema aparentemente mais sério surge da justaposição das seguintes seções dos documentos

Suponha que um módulo exija um HttpBackend personalizado que adicione um cabeçalho especial para todas as solicitações Http. Se outro módulo em outro lugar no aplicativo também personalizar o HttpBackend ou simplesmente importar o HttpModule, ele poderá substituir o provedor HttpBackend desse módulo, perdendo o cabeçalho especial. O servidor rejeitará solicitações http deste módulo.
Evite esse problema importando o HttpModule apenas no AppModule, o módulo raiz do aplicativo.

Posso reexportar aulas e módulos?
Absolutamente!
Os módulos são uma ótima maneira de agregar seletivamente classes de outros módulos e reexportá-las em um módulo de conveniência consolidado.
Um módulo pode reexportar módulos inteiros que efetivamente reexportam todas as suas classes exportadas. O próprio BrowserModule do Angular exporta alguns módulos como este:
exportações: [CommonModule, ApplicationModule]
Um módulo pode exportar uma combinação de suas próprias declarações, classes importadas selecionadas e módulos importados.

Portanto, por um lado, os documentos desencorajam os usuários a reexportar determinados módulos, ao mesmo tempo em que afirmam que isso oferece uma grande conveniência.

A noção de reexportações NgModule é análoga à das reexportações do Módulo ES, exceto que você tem menos controle. JavaScript tem escopo estático (sim, eu sei que this não é) e esse é um de seus maiores pontos fortes, permitindo uma composição extremamente flexível e ocultação de informações. JavaScript também suporta sombreamento para que você sempre tenha uma maneira de substituir um escopo.

O maior problema, porém, é que todos os exemplos nas diretrizes giram em torno de como importar os módulos do framework @angular/*. Estes são naturalmente divisíveis de maneiras que permitem que os conflitos sejam prevenidos intuitivamente. Isso ocorre porque eles existem para fornecer serviços de nível de infraestrutura que geralmente não se sobrepõem. Os módulos definidos pelo usuário podem atravessar muitas camadas e podem querer aprimorar ou alterar uma variedade de comportamentos. Por exemplo, um módulo de registro pode querer acesso aos serviços do roteador e Http e, ao mesmo tempo, fornecer vários componentes para exibir informações aos usuários administrativos e usar um dos módulos de formulários para defini-los.

Os documentos não dizem nada sobre se as reexportações são transitivas... Módulo A reexporta CommonModule. O Módulo B reexporta o Módulo A. O Módulo C importa o Módulo B. Isso significa que o Módulo C agora pode usar diretivas do CommonModule?

@Martin-Wegner Eles são transitivos conforme descrito aqui https://angular.io/docs/ts/latest/cookbook/ngmodule-faq.html#! #q-re-exportação

@aluanhaddad onde? Não consigo encontrar nenhuma palavra sobre reexportações transitivas com mais de um salto ...

Lendo o que @aluanhaddad pegou dos documentos do angular, sinto que tenho que reconsiderar tudo o que aprendi sobre o Angular 2 e talvez até mesmo se não houver uma estrutura que lide com as dependências de uma maneira melhor.

Como eu entendo. Se eu tiver um App Module importando HttpModule e tiver um Feature Module com um serviço, que usa Http Service, não devo importar HttpModule no nível do Feature Module, mas no nível do App Module. E daí se eu criar um Módulo de Recurso que é compartilhado entre muitos Módulos de Aplicativos? Eu tenho que realmente no HttpModule sendo importado no App Module. Não posso dizer que meu Feature Module depende do HttpModule. Isso é realmente feio e significa que a definição do NgModule carece de muitos recursos, como, por exemplo, PeerDependecies.
Oh garoto. Parece que o angular 2 está se separando. Temo que seja hora de recomeçar, abandonar o angular 2 e começar com o angular 3.

Na verdade, há muito sentido no que você acabou de dizer. eu comecei isso
angular2 desde o ano passado e não tive nenhum motivo para se sentir batendo
apesar de todas as mudanças que vimos até agora (de alfa, para beta,
e RC). É compreensível nessas fases e desde que religiosamente preso
à filosofia que usou para me converter dos meus Backbonejs minimalistas.
Toda a ideia deste ngModules para mim provou ser um pouco contrária
produtivo. E é triste ver todo o tempo que dediquei a evangelizar o
rica bondade dos "Componentes" minimalistas e livres de inchaço vá para
absolutamente desperdício.
Em 29 de agosto de 2016 09:44, "Daniel Schuba" [email protected] escreveu:

Lendo o que @aluanhaddad https://github.com/aluanhaddad pegou
os documentos do angular, sinto que tenho que reconsiderar tudo o que tenho
aprendi sobre Angular 2 e talvez até mesmo se não houver um framework que
lida com dependências de uma maneira melhor.

Como eu entendo. Se eu tiver um App Module importando HttpModule e eu
ter um Feature Module com um serviço, que usa Http Service, eu não deveria
import HttpModule no nível do módulo de recurso, mas no nível do módulo do aplicativo. E daí
se eu criar um Módulo de Recurso que seja compartilhado entre muitos Módulos de Aplicativos? Eu tenho
para realmente no HttpModule sendo importado no App Module. Eu não posso dizer,
que meu Feature Module depende do HttpModule. Isso é muito feio e
significa que a definição do NgModule carece de muitos recursos como, por exemplo,
PeerDependecies.
Oh garoto. Parece que o angular 2 está se separando. temo que seja hora de
recomece, abandone o angular 2 e comece com o angular 3.


Você está recebendo isso porque está inscrito neste tópico.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/angular/angular/issues/10552#issuecomment -243066961,
ou silenciar o thread
https://github.com/notifications/unsubscribe-auth/AF675h8_np9i5cHgL8mMOOu8vMMQmWKkks5qkpv8gaJpZM4Jee-o
.

Alguém poderia me corrigir se eu estiver errado.

Estou pensando em organizar um aplicativo da seguinte forma.

aplicativo
|--Direito/
|----MuitosComponentes.
|----LawNGModule.
|--Usuário/
|----MuitosComponentes
|----UserNGModule
|--AppNGModule
|--SomeFirstLeveComponents

Digamos que eu queira trabalhar com Angular Material. Antes eu meio que odiava ter muita placa de caldeira importando cada elemento em cada componente. Agora eu iria adicioná-lo ao módulo NG. Mas como decidi usar um módulo ng por recurso, tenho que fazer as importações para cada módulo ng que considero. Não apenas a raiz. Isso está certo?

Ou talvez este seja um caso em que você cria um módulo x para reexportar y(Material) outro módulo e o importa nos módulos que precisa?

@ReneVallecillo Você está certo. Você precisa importá-lo em cada módulo de recurso. Ou você o adiciona junto com outros módulos em um módulo compartilhado (escondendo a dependência), que o reexporta e então usa este módulo compartilhado. E se você reexportá-lo para outro módulo, poderá até ter importações duplicadas sem conhecê-lo e vê-lo imediatamente.

@robwormald Em resposta ao seu comentário acima :

No entanto, no modo AoT, isso funciona de maneira um pouco diferente - no momento da compilação, estaticamente (ou seja, sem executar seu código) extraímos os mesmos metadados do código-fonte verificando os decoradores.

Isso significa que você está extraindo módulos estaticamente do código-fonte original e, como tal, não podemos criar módulos dinamicamente?

Para facilitar a migração, estava pensando em criar uma função que criasse módulos dinamicamente; algo assim:

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

Então, enquanto isso (provavelmente?) funcionaria com a compilação JIT, não funcionaria com o AoT porque o AoT analisa estaticamente o código-fonte, procurando por decoradores?

Essa complexidade desnecessária em uma era de ES@next... @aluanhaddad faz alguns pontos muito bons.

Do jeito que as coisas estão, não consigo ver meu eu/equipe avançando com o Angular 2 se essa for a direção pretendida. E parece que é, pois este foi "fechado".

Talvez eu tenha que fazer como @DaSchTour e pesquisar outros frameworks de front-end. Uma pena, porque alguns meses atrás, foi uma grande alegria trabalhar com NG2 e minha escolha óbvia da ninhada.

@iyobo além da dor inicial da mudança, a _vast_ maioria (e eu falo com um _lot_ de desenvolvedores) de feedback sobre NgModules tem sido positiva.

Visto isoladamente em um aplicativo hello world, você pode argumentar que é "complexo" ("desnecessário" é factualmente incorreto, de acordo com a explicação acima), mas eles realmente se destacam em um aplicativo real - recursos de organização, roteamento lento e AoT são todos muito mais simples com NgModules. Dada a escolha hoje, eu ainda optaria por adicionar NgModules ao framework.

Estou com @robwormald aqui, a dor inicial de migrar de RC4/5 para NgModules foi gerenciável depois de ver as vantagens de não precisar importar todos os componentes/pipes para uma página recém-criada.
Os NgModules começam a brilhar depois de ficarem um pouco mais complexos e com muitos componentes compartilhados.

Muito mais fácil apenas importar SharedModule e pronto.

Ei @robwormald , A noção de que alguém discorda da direção atual do Ng2 não é de forma alguma uma afirmação factual de que eles só funcionam em aplicativos de nível "hello world".

Essa "compartimentação de recursos" de que você fala não é novidade. É algo que sempre foi projetado conforme necessário para se adequar a cada produto/solução individual usando componentes.
Dito isto, ainda não há maior compartimentação do que um componente declarando o que ele precisa por si só.

Agora, quanto ao carregamento lento, recuando e olhando as coisas da perspectiva de um pássaro, o principal benefício do carregamento lento é melhorar a velocidade de carregamento do aplicativo. Acho que a maioria de nós tem pipelines que fazem isso funcionar. Digite minificação, compactação e vários pontos de entrada de aplicativos ala webpack.

Parece-me apenas que NgModules é uma solução em busca de um problema, do que uma solução para um problema real. Mas, novamente, não posso afirmar que sei tudo...

Acho que o tempo mostrará se a introdução do NgModules foi uma boa ideia. Tenho a impressão de que o Angular 2 atualmente é feito apenas para atingir certos objetivos de design. Ninguém pensou em coisas como equipes com diferentes níveis de habilidade, código que está envelhecendo e que é passado por gerações de desenvolvedores. Em um mundo ideal, pode parecer uma ótima ideia. Mas, na realidade, o NgModules apresenta muitas armadilhas e ofuscação que causarão muitos problemas na fase de treinamento e introdução em um novo projeto. Simplesmente não é tão simples e intuitivo como era com a declaração no nível do componente. As dependências estão escondidas em módulos e é apenas uma questão de tempo para você começar a pesquisar o módulo em que seu componente está.

Tendo feito a transição de um aplicativo maior para NgModules recentemente, acho que eles são principalmente uma coisa boa (agora que terminei com isso, faz certo sentido). Na verdade, acho que o principal problema é que eles exigem uma estrutura de componentes diferente, algo que provavelmente não se encaixava bem na forma como você estruturou seu aplicativo antes (pelo menos foi o meu caso).

No entanto, sinto que eles não deveriam existir como a única solução. Se você observar como os componentes são comumente construídos, perceberá que, muitas vezes, eles são compostos de subcomponentes menores e altamente especializados. Para esses subcomponentes, que não têm nenhum propósito fora desse componente de contêiner, ter que mantê-los no módulo de escopo mais alto é realmente tedioso e pode resultar rapidamente em problemas de escopo.

Eu realmente apreciaria se houvesse um mecanismo _além_ de NgModules que permitisse aos componentes definir outros componentes ou diretivas como dependências de escopo local que se aplicam apenas nesse componente exato (assim como a listagem directives funcionava antes dos módulos).

Eu gosto da sugestão do @poke de ter uma alternativa para aqueles que preferem não usar Full NgModules.

NgModules foram adicionados no RC5 para resolver problemas de compilação e carregamento lento para funcionar - dificilmente faz parte do plano mestre original e é por isso que eles não são adequados para alguns casos de uso (especialmente se você estivesse construindo um aplicativo baseado em o design original "componentes são reis").

É claro que eles consertam ou permitem algumas coisas, mas também trazem suas próprias complicações - mais coisas para as pessoas aprenderem e projetarem, o que é especialmente desafiador quando todas as melhores práticas e abordagens ainda não foram elaboradas. A adoção antecipada pode trazer muita dor, aprendi isso desde o passeio até o RC4.

Eu gostei mais do plano centrado em componentes original e é provavelmente por isso que estou achando que os Componentes de Polímero / Web se encaixam melhor agora. Os módulos parecem meio passo de volta ao Angular 1.

No começo eu era resistente a essa mudança de remover pipes e diretivas, mas me acostumando agora e não parece tão ruim quanto eu pensava.

Alguém pode me mostrar como o NgModules funciona em um aplicativo realmente complexo, onde vários componentes exigem vários outros em vários níveis? Todos os tutoriais, exemplos e repositórios que vi apenas mostram as maneiras fáceis de um módulo encapsular seus próprios materiais e publicar (exportar) alguns deles para outros.

Em projetos reais existem muitas dependências cross-required geralmente com uma cadeia hierárquica. É de alguma forma falso provar um conceito de algo por um exemplo designado exatamente para isso.

@ para todos os autores de Angular2: você pode nos dizer honestamente quais são as partes negativas do NgModules? Eu sei que você pode escrever um livro sobre todas as coisas boas. Está bem. Mas eu sempre preciso lidar com as coisas ruins escondidas que não ficariam claras se você não falasse sobre elas.

Alguém pode me mostrar como o NgModules funciona em um aplicativo realmente complexo, onde vários componentes exigem vários outros em vários níveis?

Uma maneira de fazer isso seria criar um módulo de dependência apenas para esses componentes: vamos supor que você tenha três conjuntos de componentes A , B e C que contêm vários componentes cada conjunto tem aqueles que estão um pouco relacionados. Portanto, esses três conjuntos funcionariam bem para três módulos separados.

Agora, os componentes em cada um desses conjuntos exigem vários componentes de um conjunto D . Esses componentes em D são usados ​​apenas para os componentes nesses três conjuntos. Como eles são usados ​​em todos eles, você não pode simplesmente adicionar os componentes a esses módulos (já que os componentes só podem fazer parte de um único módulo). Neste ponto, você pode mesclar A , B , C e D em um módulo gigantesco, para que todas as dependências estejam lá. Mas é claro que isso é muito confuso. Em vez disso, você apenas cria um novo módulo para D que contém apenas essas dependências. Este módulo não faz nada além de fornecer acesso a esses módulos. Agora você pode importar esse módulo em cada um desses três outros módulos e pode usar os componentes. Mas como os componentes ainda são “privados”, você não reexporta o módulo ou importa o módulo D em algum outro módulo.

Como as importações de módulo afetam apenas o próprio módulo, isso permite algum tipo de escopo sem poluir outros módulos. Claro, requer que você crie mais módulos, mas é assim que funciona.

Posso compartilhar minha configuração atual. Eu usei 3 módulos no aplicativo: CommonModule, AppModule e TestModule.

  • CommonModule importa e exporta as coisas mais comuns como HttpModule, FormsModule, MdInputModule etc
  • AppModule importa BrowserModule, CommonModule, app.routing e componentes individuais
  • TestModule importa e exporta BaseModule, mas substitui alguns provedores, como XHRBackend com MockBackend

Eu introduzi esta configuração para simplificar TestBed.configureTestingModule,
para que eu tenha que importar TestModule e, em seguida, apenas um componente como:

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

Uma desvantagem adicional que ficou muito clara quando migrei do RC-4 para o lançamento foi que os NgModules impõem uma penalidade pesada para refatorações simples em que um componente simplesmente precisa ser dividido. Com NgModules, você precisa alterar o módulo que o contém, que pode estar vários níveis acima da árvore de componentes conceituais, ou promover o componente envolvendo-o em um NgModule e removendo-o de seu NgModule pai. A refatoração de componentes é essencial.

Isso está diretamente relacionado ao ponto de @poke

Eu realmente apreciaria se houvesse um mecanismo além do NgModules que permitisse aos componentes definir outros componentes ou diretivas como dependências de escopo local que se aplicam apenas nesse componente exato (assim como a listagem de diretivas funcionava antes dos módulos).

Eu discordo fortemente. Uma arquitetura modular como é proposta pelo Angular 2 é mais fácil de dimensionar, ajustar e refatorar quando necessário. Claro, do RC4 ao RC5 houve um pouco de ajuste, mas se alguma coisa, para mim, os NgModules provaram permitir uma aplicação muito mais flexível.

Angular é opinativo e certamente pode não ser um tamanho único, mas NgModules certamente não é o ponto de falha para arquitetar um aplicativo inteligente, moderno e de alto desempenho.

@emilio-martinez: Na minha opinião, o NgModule nunca seria introduzido, se o Angular 2 não fosse tão lento no bootstrap, ao envolver o JiT. Todas as outras 'melhorias' como 'escalonamento, ajuste e refatoração' são discutíveis, como mostra esta discussão.

Já faz um bom tempo e muitos de nós tiveram tempo para absorver completamente o NgModule em nosso trabalho. Acho que agora está claro que, como algumas pessoas descreveram, uma vez que você tenha passado do limite de velocidade de passar para o novo sistema de módulos, isso permite algumas coisas muito boas. Para quem acompanha este tópico com problemas para absorver o NgModule, sugiro percorrer todo o caminho e ler tudo de @robwormald e @wardbell especialmente.

Acredito que todos nós descobriremos daqui a um ano que muitos aplicativos Angular 2+ fazem uso generalizado e contínuo de módulos, carregamento lento e AOT. Acredito que será completamente rotineiro para a maioria ou quase todos os aplicativos usarem essas coisas para implementar a visão de "aplicativo progressivo", onde até mesmo aplicativos grandes e complexos têm um tempo de carregamento inicial quase instantâneo e, em seguida, carregam preguiçosamente (ou pré-carregam preguiçosamente otimistas) a funcionalidade que eles necessidade. O resultado é realmente surpreendentemente liso, e alcançado a um custo notavelmente baixo para o desenvolvedor de aplicativos individuais: NgModule basicamente é esse custo, e é uma transição irritante, mas apenas uma quantidade muito modesta de trabalho contínuo para usar.

@kylecordes Espero que você esteja certo e acho que essa é a atitude correta a se ter.

@iurii-kyrylenko isso é muito verdade.

Eu tenho um problema com a compilação angular do meu JavaScript, pois é suposto o TypeScript compilar meu JavaScript, mas esse é um problema separado.

@kylecordes Acho que há muito mais a considerar do que apenas a transição. Os módulos apresentam muita complexidade e muitas possibilidades adicionais para adicionar bugs ao próprio aplicativo. O maior problema é a ofuscação de dependências. O que causará muitos problemas nos próximos anos de desenvolvimento com angular 2.

@aluanhaddad Acredito que o Angular usa um wrapper tsc para compilar. É bom porque você pode até implementá-lo em um fluxo de trabalho do executor de tarefas, por exemplo.

A velocidade de inicialização do @iurii-kyrylenko também é difícil de determinar com base no RC4. Muito do trabalho que foi feito desde então até o lançamento final foi de limpeza e otimizações. Na minha experiência, o JIT compilado pelo Angular é executado mais rápido do que o RC4.

@DaSchTour você pode detalhar os bugs que encontrou ao trabalhar com o NgModule?

@emilio-martinez não são bugs no NgModule, mas bugs que surgirão devido a importações ausentes ou instâncias de serviço duplicadas que teriam sido omitidas ou encontradas em um estágio anterior de desenvolvimento. Trata-se de importar as coisas no lugar em que as uso e não em algum lugar que não vejo se é necessário ou usado e em que lugar é necessário e usado.

Basta pensar no TypeScript funcionando dessa maneira. Eu tenho um arquivo base para o meu módulo, vamos chamá-lo de _index.ts_ ele se parece com isso.

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

StartComp.boot();

Então temos um arquivo chamado start.ts que se parece com isso.

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

É isso que o Angular está fazendo com o NgModules. Com alguma mágica, importei algo para um módulo e ele aparece na outra extremidade do meu aplicativo. Você tem que saber que foo é importado em index.ts e executando StartComp de index as importações podem ser usadas no componente.

As dependências estão ocultas e precisam de investigação adicional para encontrá-las.

@emilio-martinez

Na minha experiência, o JIT compilado pelo Angular é executado mais rápido do que o RC4.

Tenho um projeto de média complexidade, baseado em pilha MEAN e Angular 2 final. Demora cerca de 10 segundos para concluir o bootstrap no modo JIT no meu dispositivo Android. Considero isso um atraso significativo. Atualmente não consigo usar a compilação AOT sem modificar meu código fonte (problemas com membros privados, operador elvis...).

Alguém tem alguma informação sobre o desempenho AOT + carga lenta para projetos da vida real?

Acredito que o Angular usa um wrapper tsc para compilar. É bom porque você pode até implementá-lo em um fluxo de trabalho do executor de tarefas, por exemplo.

@emilio-martinez é exatamente isso que eu não quero. Eu quero compilar meu código usando qualquer versão do TypeScript que eu quiser, por exemplo 2.1.0-dev que tem baixo nível de emissão para async/await. Não quero que o Angular fique encarregado de compilar meus arquivos TypeScript, isso não deve ser delegado a um framework, é o papel de uma linguagem. Sem ir mais longe, eu não teria tocado @Script com um poste de três metros, graças a Deus está morto.
Em termos de fluxo de trabalho, eu uso JSPM e às vezes Webpack, não um executor de tarefas tradicional, e deixo meu IDE lidar com meus linters.

Outro problema é que eu escrevi decoradores que abstraem os decoradores angulares e agora entendo que aot irá ignorá-los. Considerando o quão pesado é o angular dos decoradores, fiquei muito desapontado ao saber que o framework não suportaria totalmente os decoradores, tratando-os, durante a AOT, como anotações estáticas quando na verdade são uma construção de tempo de execução na linguagem subjacente.

@aluanhaddad é importante entender que existem duas etapas distintas ocorrendo durante a compilação AoT - a primeira é gerar _new_ código datilografado, a segunda é transpilar esse código para ES5/6. ngc faz as duas coisas por conveniência, mas não há nada inerente ao AoT que exija isso. Dentro do google, fazemos as duas coisas, então esse caso é a prioridade. Qualquer um poderia implementar um host do compilador para dar suporte à geração de código em qualquer ambiente que quisesse.

Nós (ainda) não suportamos abstração em cima dos decoradores embutidos do angular, mas se você quiser usar algo como https://www.npmjs.com/package/core-decorators , tudo bem.

@iurii-kyrylenko sugere que você assista a palestra do primeiro dia do AngularConnect, onde LucidCharts falou sobre sua experiência com o AoT. Veja https://youtu.be/xQdV7q3e_2w?t=1411

IMHO - o objetivo número 1 de todos deve ser entrar na compilação AoT o mais rápido possível. O desempenho é simplesmente imbatível.

@robwormald Eu não olhei quais opções estão disponíveis ao chamar ngc - então isso já pode estar coberto. Acho que essas opções podem aliviar as preocupações como as aqui expressas, se deixarem claro que o NGC está cumprindo o primeiro propósito como sua principal razão de existir no segundo propósito como conveniência/otimização. Se a documentação ou a ajuda mostrar como executar separadamente tsc para aqueles que preferem fazê-lo, isso pode aliviar ainda mais as preocupações?

@kylecordes , não acho que a documentação abordará como implementar seu próprio host do compilador tão cedo. É um caso de uso avançado e, portanto, exigiria algum aprendizado autodirigido para implementar. Implementamos algo semelhante para a CLI aqui https://github.com/angular/angular-cli/tree/master/packages/webpack

@robwormald Ah, não quero dizer implementar seu próprio host do compilador. Eu quis dizer apenas um "processo de compilação" de duas linhas - primeiro chamando ngc para emitir algum texto datilografado gerado, depois chamando tsc você mesmo para compilar todo o texto datilografado (sua fonte mais a fonte gerada) para JavaScript. Isso fornece uma garantia rápida de que o código datilografado está apenas sendo compilado para JS pelo compilador de script datilografado pronto para uso.

@robwormald Obrigado pela sua resposta.
Em relação ao NGC, o que eu quero saber é se posso controlar a versão e as configurações do compilador TypeScript no passo TS -> TS . Posso passar o TypeScript para o NGC ou preciso usar uma versão específica que envolva uma versão específica do TypeScript? Quão acoplados eles são?

Em relação aos decoradores, existe um suporte de rastreamento de problemas para decoradores definidos pelo usuário que abstraem sobre decoradores Angular? O https://www.npmjs.com/package/core-decorators é um conjunto ortogonal de decoradores, mas tenho decoradores que impõem padrões e convenções em meus aplicativos Angular envolvendo decoradores Angular. Um caso de uso óbvio para isso é criar e aplicar automaticamente prefixos de nomes de componentes em todo o pacote, mas também existem outros.

Como o NGC não suporta isso, como ele sabe quais decoradores são específicos do Angular?
Ele corresponde aos decoradores angulares pelo nome?
Espero que não, porque isso violaria o escopo léxico do JavaScript.
Um cenário simples
_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 Você encontrou alguma solução para carregar componentes dinamicamente sem adicionar declarações de componentes ao módulo do aplicativo raiz? .

Também faço parte de um projeto de migração angular 1.X para Angular 4. Este projeto tem um grande número de componentes que são reutilizados em diferentes aplicativos que são carregados lentamente com base no contexto do aplicativo.

De acordo com o meu entendimento em Angular 4

Temos que adicionar dependências de componentes nas declarações root @NgModule como abaixo.

importe {platformBrowserDynamic} de "@angular/platform-browser-dynamic";
importe {Componente, NgModule} de "@angular/core";
...
...
@NgModule({
imports: [BrowserModule ], // importa o BrowserModule do Angular
bootstrap: [BootStrapComp], // indica o componente bootstrap
declarações: [com1, comp2 , comp5 ...... Comp n ] // registra nosso componente com o módulo
})
exportar classe AppModule {}

plataformaBrowserDynamic().bootstrapModule(AppModule);

Mas no nosso caso não queríamos fazer root no NgModule para saber sobre dependências de componentes em tempo de compilação. Em vez disso, queríamos que os componentes fossem carregados dinamicamente em tempo de execução.
Você encontrou alguma boa solução que possa inicializar o aplicativo sem adicionar todos os componentes às declarações NgModule raiz (E não queríamos ter um NgModule para cada componente também :))

@DaSchTour

Você se lembra das vezes em que o ponto de entrada do seu aplicativo ficou assim?

Bem, para isso, alguns de nós usaram scripts de compilação para exigir automaticamente esses módulos e adicioná-los ao módulo do aplicativo.

Estou procurando algo semelhante e solução fácil em angular2.

@samudrak você não pode carregar com preguiça apenas o componente se quiser usar o suporte Angular aot. Você precisará configurar o módulo lento para cada componente e carregar o módulo lentamente. Usamos uma abordagem semelhante em nossa aplicação...

Com suporte a importações dinâmicas em ECMAScript e agora em TypeScript (com verificação de tipo completa ortogonal ao carregamento), o caso de uso de carregamento lento é bastante arbitrário. Claro que a retrospectiva é 20/20 e não havia como saber que isso aconteceria.

Este problema foi bloqueado automaticamente devido à inatividade.
Registre um novo problema se encontrar um problema semelhante ou relacionado.

Leia mais sobre nossa política de bloqueio automático de conversas .

_Esta ação foi realizada automaticamente por um bot._

Esta página foi útil?
0 / 5 - 0 avaliações