Software · Mapas de Conteúdo & Guias

Angular 15 vs Angular 22: O Guia Definitivo de Modernização

Comparativo arquitetural detalhado entre o Angular 15 e o Angular 22: 40 conceitos práticos, Signals, Zoneless, Control Flow e transição para arquitetura standalone.

Diagrama comparativo da arquitetura clássica do Angular 15 em relação ao framework moderno Angular 22
Neste artigo

Aplicações corporativas construídas sobre as versões intermediárias do Angular, em especial o Angular 15, ainda sustentam operações críticas em diversas empresas. Esse ecossistema consolidou a primeira fase de maturidade dos componentes autônomos, mas mantinha raízes profundas no modelo clássico do framework: forte dependência de módulos (@NgModule), controle de estado assíncrono canalizado pelo RxJS e varredura de alterações em árvore orientada pelo zone.js.

Com o Angular 22, o framework completa o ciclo conhecido na comunidade como Angular Renaissance. A plataforma refinou sua arquitetura para atender aos requisitos atuais de carregamento rápido e consumo enxuto de CPU: componentes Standalone por padrão, reatividade síncrona de alta precisão com Signals, renderização puramente Zoneless sem interceptação global de eventos, controle de fluxo declarativo no compilador (@if, @for), carregamento sob demanda com blocos @defer e empacotamento ultrarrápido com Vite e esbuild.

A transição entre esses dois momentos do Angular vai muito além de atualizar pacotes no package.json ou trocar a sintaxe de diretivas. Trata-se de uma evolução estrutural no modelo mental de desenvolvimento, simplificando o fluxo de dados e eliminando o excesso de camadas intermediárias.

Para documentar e demonstrar essas transformações com código funcional, isolado e testável, organizei o repositório aberto angular-modernization-lab. Este guia reúne os 40 conceitos do projeto, distribuídos em 10 frentes técnicas, analisando as 6 grandes quebras de paradigma e as decisões práticas de engenharia necessárias para modernizar bases corporativas com segurança.

flowchart TD
    subgraph Legado["Ecossistema Clássico (Angular 15)"]
        A1["Arquitetura acoplada a NgModules"]
        A2["Varredura em árvore com Zone.js (Dirty Checking)"]
        A3["Reatividade baseada em RxJS obrigatório"]
        A4["Diretivas estruturais (*ngIf, *ngFor)"]
        A5["Build lento e pesado com Webpack"]
    end

    subgraph Moderno["Framework Moderno (Angular 22)"]
        B1["Standalone por padrão e provedores funcionais"]
        B2["Arquitetura Zoneless com atualizações pontuais"]
        B3["Primitivos reativos: signal, computed, effect"]
        B4["Built-in Control Flow nativo (@if, @for, @switch)"]
        B5["Compilação ultrarrápida com Vite e esbuild"]
    end

    Legado ==>|"Modernização incremental com Schematics"| Moderno

    classDef legacy fill:#1f131a,stroke:#f43f5e,stroke-width:1px,color:#f8fafc;
    classDef modern fill:#0f2724,stroke:#34d399,stroke-width:2px,color:#f8fafc;

    class A1,A2,A3,A4,A5 legacy;
    class B1,B2,B3,B4,B5 modern;

As 6 Grandes Quebras de Paradigma

A migração do modelo clássico para o Angular moderno é sustentada por seis quebras de paradigma que removeram os principais gargalos de manutenção e desempenho enfrentados pelas equipes nos últimos anos.

1. De NgModule para Standalone por Padrão

No Angular 15, o @NgModule ainda representava a unidade central de compilação na maioria das aplicações em produção. Cada componente, diretiva ou pipe precisava ser declarado em um módulo específico. Para compartilhar elementos de interface comuns entre múltiplos módulos, as equipes frequentemente criavam arquivos monolíticos como SharedModule e CoreModule.

  • Pontos de atrito: Erros recorrentes de compilação por falta de declaração explícita, empacotamento de código não utilizado que escapava ao tree-shaking e risco contínuo de dependências circulares entre módulos de funcionalidades.

No Angular 22, componentes, diretivas e pipes são Standalone por padrão. A propriedade standalone: true não precisa mais ser especificada no decorator @Component. Cada componente declara diretamente em seu array imports: [...] apenas os recursos que utiliza em seu próprio template. A inicialização da aplicação dispensa arquivos app.module.ts, sendo conduzida de forma linear por bootstrapApplication(AppComponent, appConfig) com provedores funcionais coesos, como provideRouter e provideHttpClient.

2. De Zone.js Dirty Checking para Zoneless Nativo

Historicamente, a detecção de alterações no Angular dependia da biblioteca zone.js. Essa biblioteca interceptava (monkey-patching) praticamente todas as operações assíncronas do navegador, incluindo temporizadores (setTimeout), promessas, manipuladores de eventos do DOM e requisições de rede.

  • Pontos de atrito: Sempre que qualquer evento assíncrono terminava, o Zone.js disparava uma varredura geral de checagem suja (top-down dirty checking), percorrendo a árvore inteira de componentes para descobrir o que havia mudado. Em interfaces com tabelas densas ou dashboards com dados em tempo real, esse modelo gerava gargalos de CPU, forçando o uso defensivo de ChangeDetectionStrategy.OnPush e chamadas manuais a ChangeDetectorRef.markForCheck().

O Angular 22 consolida a arquitetura Zoneless nativa por meio de provideZonelessChangeDetection(). O framework não precisa interceptar APIs globais do navegador nem navegar recursivamente por árvores de componentes. A sincronização de interface baseia-se em dependências explícitas registradas por Signals: quando um sinal tem seu valor alterado, o motor do framework sabe exatamente quais nós do DOM dependem daquele dado e agenda apenas as instruções de atualização estritamente necessárias, mantendo a taxa de quadros estável mesmo com alto volume de eventos simultâneos.

3. De RxJS Obrigatório para Signal-First

No Angular 15, a reatividade da aplicação dependia de fluxos baseados em RxJS, mesmo quando a necessidade envolvia apenas guardar um contador ou controlar a exibição de um modal. O padrão comum exigia criar instâncias de BehaviorSubject, expô-las externamente como Observable, manipular transformações com operadores como map ou combineLatest e desembrulhar os valores no template com o pipe async.

  • Pontos de atrito: Curva de aprendizado íngreme, complexidade assíncrona desnecessária para dados mantidos de forma síncrona em memória e vazamentos silenciosos quando subscrições manuais não eram canceladas no momento do descarte do componente.

No Angular 22, a reatividade primária adota a abordagem Signal-First:

  • signal(valor): Primitivo reativo básico com leitura síncrona direta via invocação funcional meuSignal() e mutações atômicas com .set() e .update().
  • computed(() => ...): Estado derivado memoizado que recalcula automaticamente sob demanda, apenas quando os sinais dependentes mudam de valor.
  • effect(() => ...): Gatilho automático para efeitos colaterais sincronizados com o ciclo de renderização ou APIs externas do navegador.
  • linkedSignal(): Primitivo dependente cujo estado interno pode ser alterado manualmente, mas que se resincroniza automaticamente quando seu sinal de origem é atualizado.

O RxJS não foi descartado: ele permanece como uma ferramenta poderosa para tratar fluxos contínuos de eventos assíncronos no tempo, como campos de busca com digitação rápida e cancelamento de requisições concorrentes. A diferença é que a interface consome esses dados com facilidade por meio de utilitários como toSignal() e toObservable(), sem a obrigação de espalhar operadores por todos os serviços de domínio.

4. De Decorators de Propriedade para Primitivas Reativas Funcionais

Na abordagem clássica, a parametrização de componentes dependia de decorators de campo acoplados a propriedades mutáveis de classe:

  • @Input(), @Output(), @ViewChild(), @ContentChild(), @HostBinding(), @HostListener().
  • Pontos de atrito: Parâmetros de entrada podiam assumir undefined durante o ciclo de montagem, a verificação estrita de propriedades obrigatórias era frágil e a sincronização bidirecional demandava convenções manuais de eventos com EventEmitter.

O Angular 22 substitui decorators de campo por primitivas funcionais e fortemente tipadas:

  • readonly titulo = input.required<string>();: Entrada somente leitura exposta como Signal.
  • readonly mudou = output<string>();: Canal de saída simplificado, emitido diretamente com .emit().
  • readonly valor = model(0);: Signal bidirecional (two-way binding) que se sincroniza com o componente pai sem necessidade de código de evento adicional.
  • readonly campoRef = viewChild.required<ElementRef>('meuCampo');: Consulta de nó do DOM entregue diretamente como Signal.
  • As interações com o elemento hospedeiro foram consolidadas na propriedade declarativa host: { ... } nos metadados do @Component, eliminando decorators dispersos pelo corpo da classe.

5. De Diretivas Estruturais para Built-in Control Flow

A renderização condicional e a iteração de coleções no Angular 15 utilizavam diretivas estruturais com sintaxe baseada em asterisco: *ngIf, *ngFor e [ngSwitch].

  • Pontos de atrito: Dependiam da importação manual do CommonModule, alocavam nós intermediários no DOM para cada bloco condicional e permitiam esquecer a cláusula trackBy no *ngFor, degradando a performance em listas longas por recriar elementos desnecessariamente.

O Angular 22 incorpora o controle de fluxo diretamente no compilador de templates:

  • @if (condicao()) { ... } @else if { ... } @else { ... }: Sintaxe idêntica a linguagens de programação modernas, sem necessidade de importar módulos auxiliares.
  • @for (item of itens(); track item.id) { ... } @empty { <p>Nenhum registro encontrado.</p> }: A cláusula track é estritamente obrigatória em tempo de compilação, prevenindo erros de desempenho antes da execução. O bloco @empty nativo simplifica a exibição de estados vazios sem exigência de blocos condicionais adicionais.
  • @switch (status()) { @case ('ativo') { ... } @default { ... } }: Estrutura compacta para cenários com múltiplas alternativas visuais.

6. De Webpack para esbuild e Vite

O Angular CLI clássico utilizava o empacotador Webpack por meio do builder @angular-devkit/build-angular:browser. Em projetos corporativos extensos, com centenas de telas e dependências externas, o tempo de inicialização a frio (Cold Start) e os builds de produção podiam levar vários minutos, consumindo muita memória nas esteiras de integração contínua (CI).

O construtor moderno do Angular 22 (@angular/build:application) integra duas tecnologias focadas em velocidade:

  • esbuild: Compilador e empacotador escrito em Go que processa código TypeScript e folhas de estilo CSS com velocidade até oito vezes superior à do Webpack.
  • Vite: Servidor de desenvolvimento com Hot Module Replacement (HMR) instantâneo, aplicando alterações de código no navegador em milissegundos.
  • Geração automática de pacotes divididos por rota (route-based code splitting), tree-shaking aprofundado e remoção do overhead de polyfills legados.

O Mapa Geral dos 40 Conceitos (Módulos A a J)

O repositório angular-modernization-lab divide a transição entre o modelo clássico e o moderno em 10 módulos temáticos, cobrindo 40 conceitos essenciais implementados e comparados lado a lado.

graph TD
    MAP["Angular Modernization Lab (40 Conceitos em 10 Módulos)"]

    MA["Módulo A: Fundamentos do Framework (01-07)"]
    MB["Módulo B: Reatividade e Estado (08-10)"]
    MC["Módulo C: Roteamento e Navegação (11-15)"]
    MD["Módulo D: Formulários e Validação (16-18)"]
    ME["Módulo E: Comunicação HTTP e Resiliência (19-21)"]
    MF["Módulo F: Arquitetura de Componentes (22-26)"]
    MG["Módulo G: Módulos vs Standalone (27)"]
    MH["Módulo H: Animações e Transições (28)"]
    MI["Módulo I: Tópicos Avançados e Performance (29-37)"]
    MJ["Módulo J: Padrões Corporativos e Engenharia (38-40)"]

    MAP --> MA
    MAP --> MB
    MAP --> MC
    MAP --> MD
    MAP --> ME
    MAP --> MF
    MAP --> MG
    MAP --> MH
    MAP --> MI
    MAP --> MJ

    classDef root fill:#0f172a,stroke:#38bdf8,stroke-width:2px,color:#f8fafc;
    classDef mod fill:#1e293b,stroke:#f59e0b,stroke-width:1px,color:#f8fafc;

    class MAP root;
    class MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ mod;

A seguir, analisamos cada um dos 10 módulos com foco nas decisões técnicas e na evolução dos padrões de código.


Módulo A: Fundamentos do Framework

O Módulo A aborda os blocos de construção essenciais de qualquer sistema Angular: inicialização, bindings, controle de fluxo e injeção de dependências.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
01 Estrutura de Projeto & Bootstrap AppModule clássico, platformBrowserDynamic e builder Webpack em angular.json. bootstrapApplication, appConfig declarativo e construtor rápido com Vite e esbuild.
02 Templates & Data Binding Interpolação tradicional, property binding e two-way binding com ngModel. Interpolação com invocação de signals e two-way binding moderno via primitiva model().
03 Controle de Fluxo Diretivas estruturais *ngIf, *ngFor com trackBy manual e ngSwitch. Built-in Control Flow nativo: blocos @if, @for com track obrigatório, @empty e @switch.
04 Diretivas & Composição Diretivas amarradas a módulos, HostListener, HostBinding e herança de classes. Diretivas Standalone e Directive Composition API (hostDirectives) sem herança.
05 Pipes & Transformação Pipes declarados em módulo e dependência recorrente do pipe async para renderizar dados. Pipes standalone puros e leitura direta de Signals no template sem necessidade de pipe async.
06 Injeção de Dependências Injeção obrigatória pelo construtor da classe com modificadores de visibilidade. Injeção funcional idiomática por meio da função utilitária inject() em campos de classe.
07 Ciclo de Vida de Componentes ngOnInit, ngOnChanges e cancelamento manual de subscrições no ngOnDestroy. DestroyRef, operador takeUntilDestroyed(), ganchos afterRender e afterNextRender.

Comparativo de Código: Bootstrap e Injeção (Conceitos 01 e 06)

No Angular 15, a inicialização dependia de um módulo raiz decorado com metadados extensos:

// Angular 15 - app.module.ts
@NgModule({
  declarations: [AppComponent, MeuComponente],
  imports: [BrowserModule, HttpClientModule, FormsModule],
  providers: [MeuServico],
  bootstrap: [AppComponent]
})
export class AppModule {}

// main.ts
platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

No Angular 22, a configuração é declarativa e dispensa a criação de módulos intermediários:

// Angular 22 - app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    provideZonelessChangeDetection(),
    provideRouter(routes),
    provideHttpClient()
  ]
};

// main.ts
bootstrapApplication(AppComponent, appConfig)
  .catch(err => console.error(err));

// Injeção funcional dentro de qualquer classe ou componente
export class MeuComponente {
  private readonly servico = inject(MeuServico);
}

Módulo B: Reatividade e Gerenciamento de Estado

O Módulo B trata do gerenciamento de estado interno da aplicação, desde variáveis simples de componentes até stores compartilhadas entre serviços.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
08 Detecção de Mudanças (Change Detection) Varredura de dirty checking com zone.js e estratégia manual OnPush. Arquitetura Zoneless nativa com renderização pontual disparada por Signals.
09 Signals vs RxJS Gestão de estado síncrono por meio de BehaviorSubject, combineLatest e operadores. Primitivos síncronos limpos: signal(), computed(), effect() e linkedSignal().
10 Gerenciamento de Estado em Serviços Padrão Observable Store manual expondo fluxos e chamadas a next(). Signal Store pattern com mutações atômicas via .set(), .update() e .asReadonly().

Comparativo de Código: Gestão de Estado Reativo (Conceito 09)

No Angular 15, sincronizar valores calculados exigia o encadeamento de operadores assíncronos do RxJS:

// Angular 15 - Manipulação assíncrona para estado síncrono em memória
private readonly quantidade$ = new BehaviorSubject<number>(1);
private readonly preco$ = new BehaviorSubject<number>(100);

readonly total$ = combineLatest([this.quantidade$, this.preco$]).pipe(
  map(([qtd, preco]) => qtd * preco)
);

atualizarQuantidade(novaQtd: number) {
  this.quantidade$.next(novaQtd);
}

No Angular 22, o mesmo cálculo é expresso de forma direta, síncrona e memoizada:

// Angular 22 - Reatividade síncrona e memoizada com Signals
readonly quantidade = signal(1);
readonly preco = signal(100);

readonly total = computed(() => this.quantidade() * this.preco());

atualizarQuantidade(novaQtd: number) {
  this.quantidade.set(novaQtd);
}

Módulo C: Roteamento e Navegação

O Módulo C aborda como as rotas são estruturadas, parâmetros são passados para os componentes e acessos são protegidos.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
11 Fundamentos de Roteamento RouterModule.forRoot() e arquivos dedicados app-routing.module.ts. Provedor funcional provideRouter(routes) com array puro de rotas exportado.
12 Parâmetros de Rota & Resolvers Injeção de ActivatedRoute e subscrições obrigatórias em paramMap. withComponentInputBinding(), recebendo parâmetros de rota diretamente como input().
13 Carregamento Sob Demanda (Lazy Loading) loadChildren amarrado a módulos inteiros (m.MeuModulo). loadComponent direto no nível de componente e blocos @defer no template.
14 Proteção de Rotas (Route Guards) Classes implementando a interface CanActivate com injeção no construtor. Funções puras CanActivateFn de linha única consumindo serviços via inject().
15 Rotas Filhas & Aninhadas Rotas filhas com layouts acoplados a módulos e múltiplos outlets de roteamento. Rotas aninhadas standalone e componentes de layout desacoplados.

Módulo D: Formulários e Validação

O Módulo D explora a construção de formulários corporativos, mecanismos de validação e formulários gerados dinamicamente.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
16 Formulários Baseados em Template FormsModule dependente de módulo, diretiva ngModel e flags manuais. FormsModule standalone integrado a componentes modernos com model().
17 Formulários Reativos FormGroup, FormControl e FormBuilder com validações assíncronas complexas. Strictly Typed Reactive Forms com interoperabilidade direta para Signals.
18 Formulários Dinâmicos Geração dinâmica de campos orientada a esquemas JSON utilizando FormArray. Formulários dinâmicos com Signal Forms e validações condicionais reativas.

Módulo E: Comunicação HTTP e Resiliência

O Módulo E analisa a integração com APIs de backend, interceptação de cabeçalhos e tratamento estruturado de erros.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
19 Comunicação HTTP Básica & CRUD HttpClientModule com chamadas imperativas retornando Observable de dados. provideHttpClient() e busca declarativa reativa via resource() e rxResource().
20 Interceptadores de Requisições Classes implementando HttpInterceptor registradas via token HTTP_INTERCEPTORS. Interceptors funcionais HttpInterceptorFn encadeados com withInterceptors([]).
21 Tratamento de Erros & Resiliência Operadores RxJS catchError e classes globais de ErrorHandler. Tratamento reativo embutido no estado de erro do resource(), fallbacks e sinais de erro.

A Simplificação de Estados HTTP com a Resource API (Conceito 19)

No Angular 15, buscar dados e sincronizar sinalizadores visuais de carregamento e erro demandava a criação manual de variáveis de controle:

// Angular 15 - Controle manual de estados de requisição
dados: Produto[] = [];
isLoading = false;
erro: string | null = null;

carregar() {
  this.isLoading = true;
  this.http.get<Produto[]>('/api/produtos').subscribe({
    next: res => { this.dados = res; this.isLoading = false; },
    error: err => { this.erro = err.message; this.isLoading = false; }
  });
}

No Angular 22, a primitiva declarativa resource() encapsula busca, carregamento e erro em Signals nativos:

// Angular 22 - Data fetching declarativo com signals embutidos
readonly filtro = signal('eletronicos');

readonly produtosResource = resource({
  request: () => ({ categoria: this.filtro() }),
  loader: async ({ request, abortSignal }) => {
    const res = await fetch(`/api/produtos?cat=${request.categoria}`, { signal: abortSignal });
    if (!res.ok) throw new Error('Falha ao obter produtos');
    return res.json() as Promise<Produto[]>;
  }
});

// Acesso direto no template:
// produtosResource.isLoading() -> booleano de progresso
// produtosResource.value()     -> dados retornados
// produtosResource.error()     -> erro capturado, se houver

Módulo F: Arquitetura de Componentes Avançada

O Módulo F trata do desacoplamento de componentes, projeção de conteúdo e comunicação com elementos hospedeiros.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
22 Comunicação entre Componentes Decorators @Input e @Output com EventEmitter e convenções manuais de evento. Signal inputs com input.required(), output() declarativo e Signal model().
23 Projeção de Conteúdo & Fallback Multi-slot ng-content sem suporte a conteúdo alternativo nativo de fallback. Projeção ng-content com Fallback Content integrado quando nenhum nó é projetado.
24 Consultas de Visão (View Queries) @ViewChild e @ViewChildren com resolução postergada até o ngAfterViewInit. Primitivas funcionais reativas viewChild() e viewChildren() entregues como Signals.
25 Componentes Dinâmicos Instanciação imperativa com ViewContainerRef.createComponent(). Diretiva declarativa ngComponentOutlet com suporte nativo a inputs em Signals.
26 Interação com o Hospedeiro Decorators @HostBinding e @HostListener dispersos no corpo da classe. Configuração declarativa unificada na propriedade host do decorator @Component.

Módulo G: Módulos vs Arquitetura Standalone

O Módulo G avalia a eliminação da sobrecarga arquitetural gerada pela proliferação de NgModules em projetos de grande porte.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
27 Módulos vs Arquitetura Standalone Módulos intermediários (SharedModule, FeatureModule) gerando compilações lentas. Standalone por padrão, importação seletiva de dependências e configuração direta.

Módulo H: Animações e Transições

O Módulo H aborda a transição visual entre estados e rotas com baixo consumo de processamento no navegador.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
28 Animações & Transições BrowserAnimationsModule inserido obrigatoriamente no bundle inicial da aplicação. provideAnimationsAsync() carregado sob demanda e integração com a View Transitions API.

Módulo I: Tópicos Avançados e Performance

O Módulo I reúne técnicas de alto desempenho, carregamento sob demanda no template e eliminação de gargalos computacionais no navegador.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
29 Manipulação Segura do DOM Renderer2 e ElementRef injetados no construtor combinados com @ViewChild. inject(Renderer2), consultas reativas com viewChild() e sincronização em effect().
30 Internacionalização (i18n) registerLocaleData configurado em módulo com CommonModule obrigatório. Pipes standalone granulares (CurrencyPipe, DatePipe) e formatação sensível a Signals.
31 Segurança & DomSanitizer DomSanitizer injetado no construtor para tratar exceções de sanitização manualmente. inject(DomSanitizer) integrado a propriedades computadas computed() em Zoneless.
32 Performance & Virtual Scrolling ScrollingModule em AppModule com detecção de rolagem monitorada pelo zone.js. Virtual Scrolling standalone com 60 FPS consistentes sem intervenção do Zone.js.
33 Desconstrução de Decorators Uso amplo de decorators clássicos espalhados em propriedades de classes. Migração completa para funções primitivas (input, output, host, viewChild).
34 Operadores RxJS & Concorrência Fluxos densos de RxJS no componente resolvidos obrigatoriamente com pipe async. Interoperabilidade via toSignal(), reduzindo subscrições manuais no template.
35 Vistas Adiantadas (@defer) Carregamento dinâmico manual com ViewContainerRef e observadores manuais de tela. Blocos declarativos @defer (on viewport; prefetch on idle) nativos no compilador.
36 Zoneless Deep Dive zone.js ativo exigindo chamadas defensivas a ngZone.runOutsideAngular(). Arquitetura inteiramente Zoneless sem monkey-patching e com inicialização rápida.
37 Resource API Avançada Gerenciamento de paginação e filtros via switchMap e subjects manuais. resource() e rxResource() com cancelamento automático de chamadas anteriores obsoletas.

O Carregamento Sob Demanda com o Bloco @defer (Conceito 35)

No modelo clássico, postergar o download do código de um gráfico pesado até que o usuário rolasse a página até a área visível exigia diretivas customizadas baseadas em IntersectionObserver, combinadas com injeção imperativa de ViewContainerRef.

No Angular 22, o compilador introduz o bloco @defer, transformando o carregamento sob demanda em uma instrução declarativa de template:

<!-- Angular 22: O código do componente só é transferido quando o nó se aproxima da viewport -->
@defer (on viewport; prefetch on idle) {
  <app-grafico-telemetria [dados]="metricas()" />
} @placeholder {
  <div class="skeleton-grafico">Aguardando visualização na tela...</div>
} @loading (minimum 300ms) {
  <app-spinner />
} @error {
  <p class="erro">Falha ao carregar o componente do gráfico.</p>
}

Módulo J: Padrões Corporativos e Engenharia

O Módulo J dedica-se à padronização arquitetural de sistemas de grande escala em equipes corporativas de engenharia.

ID Conceito Técnico Abordagem no Angular 15 (Clássico) Abordagem no Angular 22 (Moderno)
38 Smart vs Dumb Components Componentes visuais usando @Input() e EventEmitter com estratégia OnPush manual. Componentes visuais com input.required() e output(), orquestrados por Signals puros.
39 Error Boundaries de Interface ErrorHandler global com risco de quebras locais derrubarem a tela inteira. Error Boundaries com contenção granular de falhas e renderização de layouts substitutos.
40 Ambientes & Feature Flags Substituição de arquivos estáticos environment.ts via fileReplacements no build. InjectionToken fortemente tipado e Feature Flags reativas manipuladas por Signals.

Guia de Referência Rápida ("De para")

A tabela a seguir serve como resumo prático para refatoração e conversão direta de sintaxes cotidianas:

Tarefa Comum Como se fazia no Angular 15 (Clássico) Como se faz no Angular 22 (Moderno)
Bootstrap da aplicação platformBrowserDynamic().bootstrapModule(AppModule) bootstrapApplication(AppComponent, appConfig)
Componente standalone @Component com propriedade standalone: true @Component (Standalone por padrão, sem flag)
Injeção de dependência constructor(private svc: MeuServico) {} private readonly svc = inject(MeuServico);
Leitura de estado no template Interpolação de propriedade simples Interpolação de signal chamando a função com parenteses
Property binding Sintaxe de binding vinculada a propriedade mutável Sintaxe de binding consumindo valor do signal
Two-way binding Diretiva ngModel com necessidade de FormsModule Two-way nativo via primitiva funcional model()
Condicional no template Diretiva estrutural *ngIf com else em template Bloco compilado @if, @else if e @else
Iteração de coleções Diretiva *ngFor com trackBy opcional Bloco compilado @for com track obrigatório
Lista com fallback vazio Condicional auxiliar com *ngIf para lista vazia Cláusula @empty integrada diretamente no bloco @for
Seleção de casos Diretiva estrutural ngSwitch com ngSwitchCase Bloco compilado @switch com @case e @default
Estado reativo primário Objeto BehaviorSubject gerenciado via RxJS Primitivo nativo signal()
Estado derivado Operadores combineLatest e map no RxJS Primitivo síncrono memoizado computed()
Efeito colateral de estado Subscrição manual com subscribe() em ganchos de ciclo Função reativa effect() com cancelamento automático
Propriedade de entrada opcional Decorator @Input() com valor padrão na classe Função reativa readonly titulo = input('Padrão');
Propriedade de entrada obrigatória Decorator @Input com required: true Função reativa readonly id = input.required();
Emissão de evento de saída Decorator @Output() instanciando EventEmitter Função reativa readonly salvou = output();
Consulta de elemento no DOM Decorator @ViewChild('campo') Função reativa readonly campo = viewChild('campo');
Cancelamento de subscrições Subject auxiliar com takeUntil no ngOnDestroy Operador takeUntilDestroyed() ou DestroyRef nativo
Código executado pós-render Gancho de ciclo ngAfterViewInit() Função afterNextRender() segura para SSR e hidratação
Configuração de rotas RouterModule.forRoot() no módulo raiz Provedor funcional provideRouter() no appConfig
Parâmetros de rota Injeção de ActivatedRoute e subscrição em paramMap Configuração withComponentInputBinding() e input()
Carregamento sob demanda de rota loadChildren apontando para módulo loadComponent apontando diretamente para o componente
Guarda de rotas Classe implementando a interface CanActivate Função pura CanActivateFn consumindo serviços via inject
Cliente de requisições HTTP HttpClientModule importado no módulo raiz Provedor funcional provideHttpClient() no appConfig
Interceptação HTTP Classe com token HTTP_INTERCEPTORS Função HttpInterceptorFn via withInterceptors([])
Carregamento sob demanda de view Instanciação dinâmica com ViewContainerRef Bloco declarativo @defer (on viewport) no template
Detecção de mudanças sem zone Inexistente (Zone.js interceptava todo o ambiente) Provedor nativo provideZonelessChangeDetection()

Roteiro Estratégico de Migração

A modernização de um projeto corporativo do Angular 15 para o Angular 22 deve ser conduzida de forma gradual, utilizando as ferramentas automatizadas (Schematics) disponibilizadas pelo próprio Angular CLI.

flowchart TD
    Etapa1["1. Atualização do CLI e Dependências: Elevar versões gradualmente via ng update"]
    Etapa2["2. Migração para Standalone: Executar schematics oficiais de conversão de componentes"]
    Etapa3["3. Modernização dos Templates: Converter *ngIf/*ngFor para Built-in Control Flow (@if, @for)"]
    Etapa4["4. Adoção de Signals e Zoneless: Substituir BehaviorSubjects e ativar provideZonelessChangeDetection"]

    Etapa1 --> Etapa2
    Etapa2 --> Etapa3
    Etapa3 --> Etapa4

    classDef step fill:#08202d,stroke:#3b82f6,stroke-width:1px,color:#f8fafc;
    class Etapa1,Etapa2,Etapa3,Etapa4 step;
  1. Elevação Gradual com ng update: Evite tentar saltar da versão 15 diretamente para a versão 22 em uma única etapa. O processo seguro envolve avançar versão a versão, permitindo que as migrações automáticas de configuração sejam executadas em cada release:
    npx @angular/cli@16 update @angular/core@16 @angular/cli@16
    npx @angular/cli@17 update @angular/core@17 @angular/cli@17
    # Prosseguir gradualmente até a versão atual
    
  2. Conversão Automatizada para Standalone: O Angular CLI disponibiliza um schematic oficial que analisa a árvore de componentes, adiciona as importações necessárias diretamente nas classes e remove os NgModules obsoletos:
    ng generate @angular/core:standalone
    
  3. Migração do Controle de Fluxo para a Nova Sintaxe: A conversão de diretivas estruturais legadas (*ngIf, *ngFor, [ngSwitch]) para os novos blocos compilados (@if, @for, @switch) também pode ser realizada de forma automatizada em toda a base de código:
    ng generate @angular/core:control-flow
    
  4. Substituição de Decorators por Primitivos Reativos: Com os componentes já em formato standalone, inicie a substituição gradual de @Input(), @Output() e @ViewChild() pelas funções input(), output() e viewChild(). Essa etapa padroniza a tipagem e prepara o sistema para a desativação do Zone.js.
  5. Ativação da Arquitetura Zoneless: No arquivo app.config.ts, remova a referência ao zone.js dos polyfills do projeto e configure a detecção moderna:
    provideZonelessChangeDetection()
    
    A aplicação passa a operar com ciclo de renderização direcionado por Signals, eliminando o overhead de monkey-patching e reduzindo o consumo de processamento no cliente.

O Laboratório Prático no GitHub

Para explorar o código-fonte de cada um dos 40 conceitos demonstrados neste guia, com mini-projetos comparativos em Angular 15 e Angular 22 prontos para compilar e executar, acesse o repositório oficial da iniciativa:

O laboratório oferece uma base prática e verificável para apoiar decisões técnicas em projetos de migração corporativa, demonstrando em código real as diferenças de arquitetura e desempenho entre as duas gerações do framework.

Explorar este tema no Grafo de Conhecimento