sexta-feira, 24 de março de 2017

Lançamento do Angular v4.0!

Ontem (23/02/2017), foi anunciado o lançamento da tão esperada versão 4 do Angular.

Se do AngularJS ("Angular 1") pro "Angular 2" (ou, simplesmente "Angular") houve uma total reescrita do framework (com arquitetura e conceitos completamente novos, sem contar com o uso do Typescript), do "Angular 2" pro "Angular 4" não foram feitas alterações tão impactantes assim - inclusive, foi mantida a compatibilidade do código escrito com a versão 2 (com pequenas exceções, como a relacionada ao pacote de animações, que será apresentada mais adiante).

CURIOSIDADE: Você sabe o porquê da versão do Angular ter passado da 2 diretamente para a 4?

A partir da versão 2, o Angular passou a adotar como convenção de versionamento a "Semantic Versioning" ("SEMVER"). Além disso, todas as bibliotecas "core" do Angular, que estão no mesmo repositório no GitHub, são versionadas dessa mesma forma, apesar de serem distribuídas em diferentes pacotes NPM:

Como a biblioteca de roteamento/navegação ("@angular/router") acabou sendo bastante alterada, inserindo "breaking changes", o seu pacote acabou tendo o primeiro número ("major") incrementado para versão 3, enquanto os outros permaneceram na versão 2, por não terem alterações tão significantes.

Por causa disso, para deixar as versões dos pacotes alinhados, causando menos confusão e facilitando a manutenção, a equipe do Angular resolveu padronizar tudo como versão 4.

Saiba mais:

Mas isso não significa que não foram feitas mudanças importantes nessa nova versão. Embora não tão aparentes para os desenvolvedores, foram feitas alterações significativas "por baixo dos panos" - implicando, principalmente, em melhorias de performance e em redução do tamanho final da aplicação (que, em alguns casos, pode chegar a 60%!). Pelo "changelog" do Angular, dá para ter uma ideia do que foi alterado desde a versão 2.

Mas o que muda para o desenvolvedor?

De fato, pouca coisa mudou (aparentemente), mas algumas delas podem ser destacadas:
  1. Melhorias no *ngIf e no *ngFor
  2. Adicionado o "email validator"
  3. Renderer2
  4. Animations package
  5. Typescript 2.2


1. Melhorias no *ngIf e no *ngFor

Nas versões anteriores do Angular, era comum usar a técnica exemplificada no código abaixo para mostrar/esconder elementos de forma alternada:
<p *ngIf="show">Você pode ver esse parágrafo...</p>
<p *ngIf="!show">Ou você pode ver esse outro parágrafo!</p>

Apesar disso ainda funcionar, com a melhoria do *ngIf, foi adicionado o "else", e pode-se fazer o mesmo código de maneira bem mais elegante:
<p *ngIf="show; else alternativa">Você pode ver esse parágrafo...</p>
<ng-template #alternativa>
  <p>Ou você pode ver esse outro parágrafo!</p>
</ng-template>

Além disso, agora também pode-se fazer atribuições locais conforme o exemplo abaixo (utilizando um Observable):
<div *ngIf="userList | async as users; else loading">
  <user-profile *ngFor="let user of users; count as count" [user]="user">
  </user-profile>
 <div>{{count}} total users</div>
</div>
<ng-template #loading>Loading...</ng-template>

2. Adicionado o "email validator"

Nas versões anteriores do Angular, era necessário usar um "pattern" para fazer a validação de um campo do tipo "email" em um formulário:
<form #f="ngForm">
    <input name="email" type="email" ngmodel required 
      pattern="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])+">
    <button [disabled]="!f.valid">Enviar</button>
</form>  

Na versão 4 do Angular, basta fazer isso:
<form #f="ngForm">
    <input name="email" type="email" ngmodel required email>
    <button [disabled]="!f.valid">Enviar</button>
</form>  


3. Renderer2

O "Renderer" agora é "deprecated" e foi incluído o "Renderer2", que pode (e deve) ser utilizado nos projetos com Angular v4 - o que não significa que o Renderer antigo deixou de funcionar.

Nas próximas versões do Angular, é provável que o Renderer seja retirado; mas, se a versão do Angular da aplicação não for atualizada para as versões futuras do Angular (por exemplo, pro Angular v5), ele continuará funcionando normalmente ("#noBreakingChangesForNow").

Exemplo de uso do Renderer2:

import { Component, Renderer2 } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

constructor(private renderer: Renderer2) {}
// ...


4. Animations package

Na versão 2 do Angular, os elementos de animações ficam no "core" do framework e têm que ser importados do pacote "@angular/core", conforme exemplo abaixo:

import {
  Component,
  trigger,
  state,
  style,
  transition,
  animate
} from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  animations: [
    trigger('divState', [
      state('normal', style({
        'background-color': 'red',
        transform: 'translateX(0)'
      })),
      state('highlighted', style({
        'background-color': 'blue',
        transform: 'translateX(100px)'
      })),
      transition('normal <=> highlighted', animate(300))
    ])
  ]
})
export class AppComponent {
    //...

Já na versão 4, foi criado um pacote separado ("@angular/animations"), de onde esses elementos devem ser importados:

import { Component } from '@angular/core';
import {
  trigger,
  state,
  style,
  transition,
  animate
} from '@angular/animations';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  animations: [
    trigger('divState', [
      state('normal', style({
        'background-color': 'red',
        transform: 'translateX(0)'
      })),
      state('highlighted', style({
        'background-color': 'blue',
        transform: 'translateX(100px)'
      })),
      transition('normal <=> highlighted', animate(300))
    ])
  ]
})
export class AppComponent {
  //...

Além disso, é necessário importar o módulo "BrowserAnimationsModule" do pacote "@angular/platform-browser/animations":

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    BrowserAnimationsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


5. Suporte ao Typescript 2.2

Na versão anterior, apenas o Typescript 1.8 era suportado. A versão 4 suporta o Typescript 2.1 e o 2.2 e, com isso, o ngc ("compiler-cli") fica mais rápido e se consegue melhorias na checagem de tipos da aplicação, sem contar os novos recursos do Typescript que poderão ser utilizados pelos desenvolvedores.

E como atualizar a versão do Angular no projeto?

A atualização para nova versão do Angular é muito simples, basta rodar o comando abaixo no console e conferir as alterações dos pacotes no arquivo "package.json":

$ npm install @angular/common@latest @angular/compiler@latest @angular/compiler-cli@latest @angular/core@latest @angular/forms@latest @angular/http@latest @angular/platform-browser@latest @angular/platform-browser-dynamic@latest @angular/platform-server@latest @angular/router@latest @angular/animations@latest typescript@latest --save

Alterações no "package.json"
Alterações no "package.json"

Depois, basta rodar a aplicação (geralmente através do comando "ng serve", se estiver sendo utilizado o "angular-cli" no projeto) e verificar no console do navegador se tudo está funcionando corretamente .

Observação: Se o projeto utiliza animações, é provável que no console apareça uma mensagem indicando que o módulo "BrowserAnimationsModule" deve ser importado na aplicação.

É isso! Agora é esperar a versão 5, que deve sair lá por Setembro ou Outubro de 2017!