Stiamo assumendo! Visualizza le posizioni aperte

Le novità di Angular 17

Angular si è rinnovato con un sito completamente nuovo ed un insieme di funzionalità che danno una ventata d’aria fresca al framework, sia dal punto di vista di Developer Experience che di User Experience.

In questo articolo vedremo alcuni tra i principali cambiamenti.

Angular Signals

Signals è un sistema che permette ad Angular di gestire uno stato applicativo in maniera granulare. 
Questo sistema reattivo di gestione dello stato permette al change detector di ottimizzare la re-renderizzazione dei componenti coinvolti, permettendo allo sviluppatore di massimizzare le performances dei componenti che sviluppa.

Un signal è un wrapper che rende “osservabile” un attributo di classe.

L’API di Signals rende il paradigma di programmazione reattiva più semplice da applicare grazie alla sua API minimale:

				
					@Component({
  selector: 'my-app',
  standalone: true,
  template: `
    {{ fullName() }} <button (click)="setName('John')">Click</button>
  `,
})
export class App {
  firstName = signal('Jane');
  lastName = signal('Doe');
  fullName = computed(() => `${this.firstName()} ${this.lastName()}`);

  constructor() {
    effect(() => console.log('Name changed:', this.fullName()));
  }

  setName(newName: string) {
    this.firstName.set(newName);
  }
}
				
			

Per creare un Signal, è sufficiente dichiarare un attributo di classe assegnandogli un valore iniziale “wrappato” dalla funzione signal .

Per leggere il valore corrente di un Signal si invoca l’attributo di classe come funzione.

Per modificare il valore di un Signal bisogna passare il nuovo valore coma argomento del metodo set . Il Change Detector di Angular verrà così segnalato e provvederà a notificare tutti gli osservatori, nel nostro caso l’aggiornamento del template e dell’attributo computed.

Per “reagire” ai cambiamenti di valore di un Signal, si usa effect, una funzione che accetta una callback come argomento, e la invoca ad ogni cambiamento di stato.

Un Signal può essere di diversa natura: read-only, scrivibile, composto ecc. Grazie a dei metodi di utilità, un Signal è compatibile con gli Observables della libreria rxjs . Per approfondimenti lasciamo il link alla documentazione dedicata e al nostro form di contatto.

 

Control flow (Developer Preview)

I template Angular supportano il “control flow” come alternativa alle direttive ngIf, ngFor.

Un esempio:

Control flow

				
					@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <h2>Todos</h2>
    <input #text />
    <button (click)="add(text.value)">Add</button>

    @for (todo of todos; track $index) {
    <p>
      <input type="checkbox" (change)="toggle($index)" />
      @if (todo.done) {
      <s>{{ todo.text }}</s>
      } @else {
      <span>{{ todo.text }}</span>
      }
    </p>
    } @empty {
    <p>No todos</p>
    }
  `,
})
export class TodosComponent {
  todos: Array<{done: boolean; text: string}> = [];

  add(text: string) {
    this.todos.push({text, done: false});
  }

  toggle(index: number) {
    this.todos[index].done = !this.todos[index].done;
  }
}
				
			

Common Module

				
					@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule],
  template: `
    <h2>Todos</h2>
    <input #text />
    <button (click)="add(text.value)">Add</button>
    <div *ngIf="todos.length; else empty"></div>
    <p *ngFor="let todo of todos; let index = index">
      <input type="checkbox" (change)="toggle(index)" />
      <s *ngIf="todo.done; else pending">{{ todo.text }}</s>
      <ng-template #pending>
        <span>{{ todo.text }}</span>
      </ng-template>
    </p>
    <ng-template #empty>
      <p>No todos</p>
    </ng-template>
  `,
})
export class TodosComponent {
  todos: Array<{ done: boolean; text: string }> = [];

  add(text: string) {
    this.todos.push({ text, done: false });
  }

  toggle(index: number) {
    this.todos[index].done = !this.todos[index].done;
  }
}

				
			

Hydration SSR

Angular è cambiato anche nella gestione dello stato in Server Side Rendering: dopo che il client riceve l’FCP e il bundle js, non viene renderizzata nuovamente l’intera pagina ma soltanto alcuni nodi specifici. Questo permette di:

  • Non avere artefatti visivi dopo il first contentful paint.
  • Ottenere migliori prestazioni Web Core Vitals
  • User Experience più fluida
In aggiunta a tutti i benefici che il Server Side Rendering offre già.

Deferrable views

Analizziamo il caso in cui si utilizza Angular in Server Side Rendering: bisogna essere consapevoli di cosa si renderizza lato server, e cosa si renderizza lato client.

Questo comportamento si può gestire in diversi modi, ad esempio dichiarando una variabile di stato booleana inizializzata a false che diventa true dopo il ciclo di vita di mount (gestito quindi lato client). Questo stato usato come binding in un ngIf vincola una porzione di template ad essere gestita solo dal client e non dal server.

In Angular 17 nulla di ciò è più necessario. E’ sufficiente usare il blocco @defer direttamente sul template e un attributo di utilità isBrowser nel Component. Angular gestirà il flusso di stato

				
					@Component(
    selector: "my-app",
    template: `
    @defer(when isBrowser) {
        <p>Hi, I am the client.</p>
    }
    <p>Hi, I am the server.</p>
    `
)
export class AppComponent {
  isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
}
				
			

Un altro caso d’uso importante è quello in cui il browser deve renderizzare un componente che per qualche motivo impiega molto a comparire sulla pagina.

Una buona User Experience si basa anche su quanto velocemente una pagina risponde ad un input utente. Un caso standard di “loading spinner” si potrebbe descrivere in questo modo:

				
					@defer {
  <large-component />
} @loading (after 100ms; minimum 1s) {
  <img decoding="async" alt="loading..." src="loading.gif" />
}

				
			

Migrazioni per la standalone API

Per supportare gli sviluppatori nella migrazione da NgModules a standalone api, il team di Angular ha creato un tool che permette di automatizzare il processo. Il requisito è di avere installato almeno la versione 15.2.0, la build deve essere pulita senza errori di compilazione ed il branch sul tuo vcs deve essere pulito.

Per lanciare l’automatismo basta scrivere questo comando su terminale dalla root del progetto:

				
					ng generate @angular/core:standalone
				
			

Per i nuovi progetti basta usare il flag --standalone dopo ng new,

Esbuild e Vite (Developer Preview)

ng serve ora supportaesbuild per generare le build di produzione e di sviluppo e di produzione, e vite per il server di sviluppo. Questo significa che le performances di build in fase di sviluppo saranno sensibilmente più veloci. E’ una funzionalità opt-in essendo ancora in “developer preview”, per attivarla bisogna modificare angular.json come segue:

				
					...
"architect": {
  "build": {                     /* Add the esbuild suffix  */
    "builder": "@angular-devkit/build-angular:browser-esbuild",
...
				
			

Jest come test runner (Developer Preview)

Jest è uno dei framework di testing più diffusi e amati nell’ecosistema JavaScript. Da questa versione di angular in poi è possibile usarlo:

npm install --save-dev jest

				
					{
  "projects": {
    "my-app": {
      "architect": {
        "test": {
          "builder": "@angular-devkit/build-angular:jest",
          "options": {
            "tsConfig": "tsconfig.spec.json",
            "polyfills": ["zone.js", "zone.js/testing"]
          }
        }
      }
    }
  }
}
				
			

Conclusioni

Con queste novità il team di Google dimostra non solo di ascoltare le richieste degli sviluppatori (vedi Jest, Esbuild + Vite) e un’attenzione particolare alla Developer Experience (vedi Control Flow, @defer), ma dimostra soprattutto che Angular è un Framework che tiene stretto il proprio posto nel mercato dell’industria Web e lo terrà ancora per lungo tempo.

Personalmente ho molto apprezzato l’introduzione dei Signal ed il lavoro fatto per semplificare e migliorare il Server Side Rendering

Il nuovo sito di Angular sarà completamente open-source e disponibile su GitHub, non vediamo l’ora di poterlo studiare e condividere le nostre scoperte con voi.

Vuoi approfondire uno di questi argomenti?

Condividi l'articolo: