Table of contents
- Standalone API agora está estável e pronta para produção!
- Router and HttpClient tree-shakable standalone APIs
- API de composição de diretivas
- A diretiva de imagem agora está estável!
- Guarda de rotas funcionais
- O roteador desempacota as importações padrão
- Melhores stack traces
- Lançamento de componentes baseados em MDC para produção
- Mais melhorias nos componentes
- CDK Listbox
- Melhorias no suporte de esbuild experimental
- Importações automáticas no language service
- Melhorias na CLI
- Destaques da contribuição da comunidade
- Descontinuações
- Animado com o que vem por aí!
Tradução livre do artigo original: blog.angular.io/angular-v15-is-now-availabl..
No ano passado, foi removido o compilador legado e o pipeline de renderização do Angular, que permitiu o desenvolvimento de uma série de melhorias na experiência do desenvolvedor nos últimos meses. Angular v15 é o resultado disso com dezenas de refinamentos que levam a uma melhor experiência e desempenho do desenvolvedor.
Standalone API agora está estável e pronta para produção!
Na v14, foram introduzidas novas standalone APIs que permitem aos desenvolvedores criarem aplicativos sem usar NgModules. A equipe do Angular está feliz em compartilhar que essas APIs saíram da fase de preview e agora fazem parte da API estável do framework. A partir de agora ela será evoluída gradualmente seguindo o versionamento semântico.
Como parte de garantir que as standalone APIs estivessem prontas para serem utilizadas em produção, foram garantidos que os componentes standalone funcionem em todo ecosistema Angular e agora funcionem completamente com as APIs HttpClient
, Angular Elements, router e mais.
As APIs standalone permitem que você inicialize um aplicativo usando um único componente:
import {bootstrapApplication} from '@angular/platform-browser';
import {ImageGridComponent} from'./image-grid';
@Component({
standalone: true,
selector: 'photo-gallery',
imports: [ImageGridComponent],
template: `
… <image-grid [images]="imageList"></image-grid>
`,
})
export class PhotoGalleryComponent {
// component logic
}
bootstrapApplication(PhotoAppComponent);
Router and HttpClient tree-shakable standalone APIs
Você pode criar um aplicativo de multi-rotas usando as novas APIs standalone do router! Para declarar a rota raiz, você pode usar o seguinte exemplo:
export const appRoutes: Routes = [{
path: 'lazy',
loadChildren: () => import('./lazy/lazy.routes')
.then(routes => routes.lazyRoutes)
}];
Onde lazyRoutes são declarados em:
import {Routes} from '@angular/router';
import {LazyComponent} from './lazy.component';
export const lazyRoutes: Routes = [{path: '', component: LazyComponent}];
e finalmente, registre o appRoutes
na chamada bootstrapApplication
:
bootstrapApplication(AppComponent, {
providers: [
provideRouter(appRoutes)
]
});
Outro benefício da API ProvideRouter
é que ela pode ser tree-shakable! Os Bundlers podem remover recursos não utilizados do roteador em tempo de compilação. Em testes com a nova API, foi descoberto que a remoção desses recursos não utilizados do pacote resultou em uma redução de 11% no tamanho do código do router no bundle do aplicativo.
API de composição de diretivas
A API de composição de diretivas traz a reutilização de código para outro nível! Esse recurso foi inspirado pela solicitação de recurso mais popular no GitHub, solicitando a funcionalidade de adicionar diretivas a um elemento host.
A API de composição de diretivas permite que os desenvolvedores aprimorem os elementos do host com diretivas e adiciona ao Angular com uma poderosa estratégia de reutilização de código, que só é possível graças ao compilador do Angular. A API de composição de diretivas funciona apenas com diretivas independentes.
Vejamos um exemplo rápido:
@Component({
selector: 'mat-menu',
hostDirectives: [HasColor, {
directive: CdkMenu,
inputs: ['cdkMenuDisabled: disabled'],
outputs: ['cdkMenuClosed: closed']
}]
})
class MatMenu {}
No trecho de código acima, aprimoramos MatMenu
com duas diretivas: HasColor
e CdkMenu
. MatMenu
reutiliza todas as entradas, saídas e lógica associada com HasColors
e apenas a lógica e as entradas selecionadas do CdkMenu
.
Esta técnica pode lembrá-lo de herança múltipla ou traços em algumas linguagens de programação, com a diferença de que temos um mecanismo para resolução de conflitos de nomes e é aplicável a primitivas de interface de usuário.
A diretiva de imagem agora está estável!
Foi anunciada a preview da diretiva de imagem Angular que foi desenvolvida em colaboração com o Chrome Aurora na v14.2.
Agora ela está estável! A Land's End experimentou esse recurso e observou 75% de melhoria no LCP em um teste no lighthouse.
A versão v15 também inclui alguns novos recursos para a diretiva de imagem:
Geração automática de srcset: a diretiva garante que uma imagem de tamanho apropriado seja solicitada gerando o atributo srcset para você. Isso pode reduzir o tempo de download de suas imagens.
Modo de preenchimento [experimental]: este modo faz com que a imagem preencha seu contêiner pai, eliminando a necessidade de declarar a largura e a altura da imagem. É uma ferramenta útil se você não souber os tamanhos de suas imagens ou se quiser migrar imagens de plano de fundo CSS para usar a diretiva.
Você pode usar a diretiva NgOptimizedImage
diretamente em seu componente ou NgModule
:
import { NgOptimizedImage } from '@angular/common';
// Include it into the necessary NgModule
@NgModule({
imports: [NgOptimizedImage],
})
class AppModule {}
// ... or a standalone Component
@Component({
standalone: true
imports: [NgOptimizedImage],
})
class MyStandaloneComponent {}
Para usá-lo em um componente, basta substituir o atributo src da imagem por ngSrc e certifique-se de especificar o atributo de prioridade para suas imagens LCP.
Você pode encontrar mais informações na documentação.
Guarda de rotas funcionais
Junto com as APIs de router independentes e tree-shakable, foi trabalhado o boilerplate das guardas de rota. Vejamos um exemplo onde definimos uma guarda que verifica se o usuário está logado:
@Injectable({ providedIn: 'root' })
export class MyGuardWithDependency implements CanActivate {
constructor(private loginService: LoginService) {}
canActivate() {
return this.loginService.isLoggedIn();
}
}
const route = {
path: 'somePath',
canActivate: [MyGuardWithDependency]
};
LoginService implementa a maior parte da lógica e na guarda só invocamos isLoggedIn(). Mesmo que o guard seja bem simples, temos muito boilerplate.
Com as novas guarda de rotas funcionais, você pode refatorar esse código para:
const route = {
path: 'admin',
canActivate: [() => inject(LoginService).isLoggedIn()]
};
Expressamos toda a guarda dentro da sua declaração. As guardas funcionais também podem ser compostas — você pode criar funções do tipo factory que aceitam uma configuração e retornam uma função de guarda ou resolver. Você pode encontrar um exemplo para executar proteções de roteador em série no GitHub.
O roteador desempacota as importações padrão
Para tornar o roteador mais simples e reduzir ainda mais o boilerplate, o roteador agora desempacota automaticamente as exportações padrão durante o carregamento lazy.
Vamos supor que você tenha o seguinte LazyComponent
:
@Component({
standalone: true,
template: '...'
})
export default class LazyComponent { ... }
Antes dessa alteração, para fazer o carregamento lazy de um componente independente , você precisava:
{
path: 'lazy',
loadComponent: () => import('./lazy-file').then(m => m.LazyComponent),
}
Agora o roteador irá procurar por uma exportação padrão e se encontrar, usará automaticamente, o que simplifica a declaração de rota para:
{
path: 'lazy',
loadComponent: () => import('./lazy-file'),
}
Melhores stack traces
A equipe do Angular recebe muitos insights das pesquisas anuais com desenvolvedores, por isso queremos agradecer a você por dedicar um tempo para compartilhar seus pensamentos! Entramos de cabeça nas dificuldades com a experiência de depuração que os desenvolvedores enfrentam, descobrimos que as mensagens de erro poderiam ser melhoradas.
Problemas de depuração para desenvolvedores Angular
Foi feita uma parceria com o Chrome DevTools para corrigir isso! Veja um exemplo de stack trace que você pode trabalhar em um aplicativo Angular:
ERROR Error: Uncaught (in promise): Error
Error
at app.component.ts:18:11
at Generator.next (<anonymous>)
at asyncGeneratorStep (asyncToGenerator.js:3:1)
at _next (asyncToGenerator.js:25:1)
at _ZoneDelegate.invoke (zone.js:372:26)
at Object.onInvoke (core.mjs:26378:33)
at _ZoneDelegate.invoke (zone.js:371:52)
at Zone.run (zone.js:134:43)
at zone.js:1275:36
at _ZoneDelegate.invokeTask (zone.js:406:31)
at resolvePromise (zone.js:1211:31)
at zone.js:1118:17
at zone.js:1134:33
Este snippet sofre de dois problemas:
- Há apenas uma linha correspondente ao código que o desenvolvedor criou. Todo o resto vem de dependências de terceiros (framework Angular, Zone.js, RxJS)
- Não há informações sobre qual interação do usuário causou o erro
Não há informações sobre qual interação do usuário causou o erro
A equipe do Chrome DevTools criou um mecanismo para ignorar scripts provenientes de node_modules anotando source maps por meio da CLI do Angular. Também foi criada uma API de marcação de pilha assíncrona que nos permitiu concatenar tarefas assíncronas agendadas e independentes em um único stack trace. Jia Li integrou o Zone.js com a API de marcação de pilha assíncrona, o que permitiu fornecer stack traces vinculados.
Essas duas mudanças melhoram drasticamente o stack trace que os desenvolvedores veem no Chrome DevTools:
ERROR Error: Uncaught (in promise): Error
Error
at app.component.ts:18:11
at fetch (async)
at (anonymous) (app.component.ts:4)
at request (app.component.ts:4)
at (anonymous) (app.component.ts:17)
at submit (app.component.ts:15)
at AppComponent_click_3_listener (app.component.html:4)
Aqui você pode acompanhar a execução do botão pressionado no AppComponent até o erro. Você pode ler mais sobre as melhorias aqui.
Lançamento de componentes baseados em MDC para produção
Estamos felizes em anunciar que a refatoração dos componentes de material Angular com base no Material Design Components for Web (MDC) está concluída! Essa mudança permite que o Angular se alinhe ainda mais com a especificação do Material Design, reutilize código de primitivas desenvolvidas pela equipe do Material Design e nos permite adotar o Material 3 assim que finalizado os tokens de estilo.
Para muitos dos componentes, atualizamos os estilos e a estrutura DOM e outros reescrevemos do zero. Mantivemos a maioria das APIs TypeScript e seletores de componentes/diretivas para os novos componentes idênticos à implementação antiga.
Migramos milhares de projetos do Google, o que nos permitiu facilitar o caminho da migração externa e documentar uma lista abrangente das alterações em todos os componentes.
Devido ao novo DOM e CSS, você provavelmente descobrirá que alguns estilos em seu aplicativo precisam ser ajustados, principalmente se seu CSS estiver substituindo estilos em elementos internos em qualquer um dos componentes migrados.
A implementação antiga de cada novo componente agora está obsoleta, mas ainda está disponível a partir de uma importação “herdada”. Por exemplo, você pode importar a implementação do botão mat antigo importando o módulo de botão legado.
import {MatLegacyButtonModule} from '@angular/material/legacy-button';
Visite o guia de migração para obter mais informações.
Mudamos muitos dos componentes para usar tokens de design e variáveis CSS internamente, o que fornecerá um caminho mais tranquilo para os aplicativos adotarem os estilos de componentes do Material 3.
Mais melhorias nos componentes
Resolvemos o 4º problema mais votado - suporte à seleção de intervalo no controle slider.
Para obter uma entrada de intervalo, use:
<mat-slider>
<input matSliderStartThumb>
<input matSliderEndThumb>
</mat-slider>
Além disso, todos os componentes agora têm uma API para personalizar a densidade que resolveu outro problema popular do GitHub.
Agora você pode especificar a densidade padrão em todos os seus componentes personalizando seu tema:
@use '@angular/material' as mat;
$theme: mat.define-light-theme((
color: (
primary: mat.define-palette(mat.$red-palette),
accent: mat.define-palette(mat.$blue-palette),
),
typography: mat.define-typography-config(),
density: -2,
));
@include mat.all-component-themes($theme);
As novas versões dos componentes incluem uma ampla gama de melhorias de acessibilidade, incluindo melhores taxas de contraste, tamanhos de alvo de toque aumentados e semântica ARIA refinada.
CDK Listbox
O Component Dev Kit (CDK) oferece um conjunto de primitivas de comportamento para a construção de componentes de interface do usuário. Na v15, introduzimos outra primitiva que você pode personalizar para seu caso de uso — a listbox CDK:
O módulo @angular/cdk/listbox
fornece diretivas para ajudar a criar interações de caixa de listagem personalizadas com base no padrão de caixa de listagem WAI ARIA.
Ao usar @angular/cdk/listbox
, você obtém todos os comportamentos esperados para uma experiência acessível, incluindo suporte a layout bidi, interação com teclado e gerenciamento de foco. Todas as diretivas aplicam suas funções ARIA associadas ao elemento host.
Melhorias no suporte de esbuild experimental
Na v14, anunciamos o suporte experimental para esbuild em ng build
para permitir tempos de compilação mais rápidos e simplificar nosso pipeline.
Na v15, agora temos Sass experimental, modelo SVG, substituição de arquivo e ng build --watchsupport
! Por favor, tente esbuild atualizando os builder angular.json
de:
"builder": "@angular-devkit/build-angular:browser"
para
"builder": "@angular-devkit/build-angular:browser-esbuild"
Se você encontrar algum problema com suas compilações de produção, informe-nos registrando um problema no GitHub.
Importações automáticas no language service
O language service agora pode importar automaticamente os componentes que você está usando em um template, mas não adicionou a um componente independente ou a um NgModule
.
Melhorias na CLI
Na CLI Angular, introduzimos suporte para APIs estáveis independentes. Agora você pode gerar um novo componente independente via ng g component --standalone
.
Também temos a missão de simplificar a saída de ng new
. Como primeiro passo, reduzimos a configuração removendo test.ts, polyfills.ts e ambientes. Agora você pode especificar seus polyfills diretamente em angular.json
na seção polyfills
:
"polyfills": [
"zone.js"
]
Para reduzir ainda mais os arquivos de configuração, agora usamos .browserlist
para permitir que você defina a versão de destino do ECMAScript.
Destaques da contribuição da comunidade
Estamos gratos em compartilhar que, desde o lançamento da v14, recebemos contribuições de mais de 210 pessoas em framework, componentes e CLI! Nesta seção, gostaria de destacar dois deles.
Fornecida a capacidade de configurar opções padrão para DatePipe
Esse recurso permite que você altere globalmente a configuração de formatação padrão para DatePipe. Aqui está um exemplo com a nova API bootstrapApplication:
bootstrapApplication(AppComponent, {
providers: [
{
provide: DATE_PIPE_DEFAULT_OPTIONS,
useValue: { dateFormat: 'shortDate' }
}
]
});
A configuração acima habilitará o formato shortDate
para todos os locais em que você usa DatePipe
em seu aplicativo.
Adicionada a tag de pré-carregamento para imagens prioritárias durante o SSR
Para garantir que as imagens prioritárias sejam carregadas o mais rápido possível, Jay Bell adicionou uma funcionalidade à diretiva de imagem para incluir uma tag <link rel="preload">
para elas ao usar o Angular Universal.
Não há necessidade de ação do seu lado se você já ativou a diretiva de imagem. Se você especificou uma imagem como prioridade, a diretiva irá pré-carregá-la automaticamente.
Descontinuações
Os lançamentos major nos permitem evoluir a estrutura em direção à simplicidade, melhor experiência do desenvolvedor e alinhamento com a plataforma da web.
Depois de analisar milhares de projetos no Google, encontramos alguns padrões raramente usados que, na maioria dos casos, são mal utilizados. Como resultado, estamos descontinuando o providedIn: 'any'
é uma opção que tem uso muito limitado, além de um punhado de casos esotéricos internos ao framework.
Também estamos descontinuando o providedIn: NgModule
. Ele não tem amplo uso e, na maioria dos casos, é usado incorretamente, em circunstâncias em que você deve preferir providedIn: 'root'
. Se você deve realmente definir o escopo de provedores para um NgModule específico, use NgModule.providers
.
Com o layout em evolução em CSS, a equipe deixará de publicar novos lançamentos de @angular/flex-layout
. Continuaremos fornecendo correções de segurança e compatibilidade de navegador para o próximo ano. Você pode aprender mais sobre isso na primeira postagem do blog da nossa série “CSS moderno”.
Animado com o que vem por aí!
O lançamento do Ivy em 2020 permitiu muitas melhorias em geral que você pode encontrar já sendo lançadas. O NgModules opcional é um ótimo exemplo. Ele ajuda na redução dos conceitos com os quais os iniciantes precisam lidar como parte de sua jornada de aprendizado básica e também suporta recursos avançados, como API de composição de diretivas por meio de diretivas independentes.
Em seguida, estamos abordando melhorias em nosso pipeline de renderização do lado do servidor e reatividade, trazendo melhorias de qualidade de vida em geral!
Mal posso esperar para compartilhar com vocês o que está por vir!