Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular 18: Neue Features optimal nutzen und Be...

Angular 18: Neue Features optimal nutzen und Bestandsprojekte effizient migrieren

Seit Angular 16 hat Google umfassende Änderungen an seinem SPA-Framework vorgenommen, um es in das nächste Jahrzehnt der Webentwicklung zu führen. Damit einher geht eine nachhaltige Veränderung der Gestalt von Angular-Anwendungen: Es setzen sich zunehmend funktionale Schnittstellen durch, die die alten objektorientierten APIs sowie TypeScript-Dekoratoren ersetzen. Signals breiten sich Stück für Stück im Framework aus, sodass reaktive Programmierung immer wichtiger wird. Standalone-Komponenten und -APIs sind längst zum Standard geworden und die neue Kontrollfluss-Syntax vereinfacht häufige Anwendungsfälle im Template erheblich. Nicht zuletzt ist auch Server-Side Rendering nun zentraler Bestandteil des Frameworks geworden und . Christian Liebel stellt in dieser Session die Neuerungen in Angular 18 vor und gibt eine Einschätzung, ob, wann und wie Entwickler auf die neuen Features umsteigen sollen. Kommen Sie vorbei und bringen Sie Ihr Angular-Wissen auf den neusten Stand!

Christian Liebel

September 18, 2024
Tweet

More Decks by Christian Liebel

Other Decks in Programming

Transcript

  1. Hello, it’s me. Angular 18 Neue Features optimal nutzen und

    Bestandsprojekte effizient migrieren Christian Liebel X: @christianliebel Email: christian.liebel @thinktecture.com Angular & PWA Slides: thinktecture.com /christian-liebel
  2. Control state change events const nameControl = new FormControl<string|null>('name', Validators.required);

    nameControl.events.subscribe(event => { // process the individual events }); Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Angular 18 https://blog.angular.dev/angular-v18-is-now-available-e79d5ac0affe#b6b1
  3. Route redirection functions const routes: Routes = [{ path: "old-user-page",

    redirectTo: ({ queryParams }) => { return queryParams["foo"] ? `/user/${queryParams["foo"]}` : `/not-found`; }, }]; Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Angular 18 https://blog.angular.dev/angular-v18-is-now-available-e79d5ac0affe#7fb8
  4. Fallback content for <ng-content> @Component({ selector: 'app-profile', template: ` <ng-content

    select=".greeting">Hello</ng-content> <ng-content>Unknown user</ng-content> `, }) export class Profile {} Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Angular 18 https://blog.angular.dev/angular-v18-is-now-available-e79d5ac0affe#2a2b
  5. Signals Standalone Components and APIs Built-in Control Flow and Deferrable

    Views Server-Side Rendering, esbuild and Vite Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Agenda
  6. Overview – A signal is a reactive primitive: a wrapper

    around a value that notifies interested consumers when that value changes – The signal concept is a lot simpler than RxJS (= streamlined APIs) – Signals form the basis for a new, more effective change detection system in Angular that could eventually replace Zone.js (= performance improvement) – Works great with ChangeDetectionStrategy.OnPush Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals
  7. OLD Zone.js-based Change Detection Angular 18 Neue Features optimal nutzen

    und Bestandsprojekte effizient migrieren Signals current (global) zone NgZone Angular boot onclick setTimeout Detect changes Detect changes <app-root> <app-nav> <app-content> <app-list> {{ binding }} {{ binding }} {{ binding }} {{ binding }}
  8. POSSIBLE Future Change Detection Angular 18 Neue Features optimal nutzen

    und Bestandsprojekte effizient migrieren Signals <app-root> <app-nav> <app-content> <app-list> {{ binding }} {{ signal() }} {{ binding }} {{ binding }}
  9. API – Writable Signals const count = signal(0); count.set(3); –

    Computed Signals const doubleCount = computed(() => count() * 2); – Effects effect(() => console.log(`The count is: ${doubleCount()}`)); Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://angular.dev/guide/signals
  10. Don't Use Effects and What To Do Instead Angular 18

    Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://www.youtube.com/watch?v=aKxcIQMWSNU
  11. RxJS Interop – Convert observable to signal counter$ = interval(1000);

    counter = toSignal(this.counter$, {initialValue: 0}); – Convert signal to observable counter = signal(0); counter$ = toObservable(this.counter); – takeUntilDestroyed() Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://angular.dev/guide/signals/rxjs-interop
  12. Signal-based Components (since Angular 17.1) @Component({ selector: "counter", standalone: true,

    template: "{{ value }}", }) export class CounterComponent { @Input() value = 0; @Input({ required: true }) value2!: number; } @Component({ selector: "counter", standalone: true, template: "{{ value() }}", }) export class CounterComponent { value = input(0); value2 = input.required<number>(); } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://blog.angular-university.io/angular-signal-inputs/
  13. Signal-based Components (since Angular 17.2) @Component({ selector: "counter", standalone: true,

    template: "{{ value }}", }) export class CounterComponent { @Input({ required: true }) value = 0; @Output() valueChange = new EventEmitter<number>(); } @Component({ selector: "counter", standalone: true, template: "{{ value() }}", }) export class CounterComponent { value = model.required<number>(); } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://blog.angular-university.io/angular-signal-inputs/
  14. Signal-based Components (since Angular 17.3) @Component({ selector: "counter", standalone: true,

    template: "", }) export class CounterComponent { @Output() count = new EventEmitter<number>(); } @Component({ selector: "counter", standalone: true, template: "", }) export class CounterComponent { count = output<number>(); } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals
  15. Signal-based Components (since Angular 17.2) @ViewChild(MyComponent) a!: MyComponent; @ViewChilren(MyComponent) b!:

    QueryList<MyComponent>; @ContentChild(MyComponent) c!: MyComponent; @ContentChildren(MyComponent) d!: QueryList<MyComponent>; a = viewChild(MyComponent); b = viewChildren(MyComponent); c = contentChild(MyComponent); d = contentChildren(MyComponent); Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals
  16. Zoneless Change Detection (since Angular 18.0) bootstrapApplication(AppComponent, { providers: [

    provideExperimentalZonelessChangeDetection(), ], }); Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals
  17. NgRx Signal Store – Reactive state management solution based on

    Signals – Simple and lightweight – Package: @ngrx/signals – Replacement for component store and entity adapter – Function-based, but can be class-based – Stable with NgRx 18 Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://ngrx.io/guide/signals
  18. Maturity – effect(), RxJS interop, Signal-based components, and zoneless change

    detection are still in developer preview (as of Angular 18.2.4) – Used by YouTube Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals
  19. Migration Strategy – Why? You should migrate to Signals, as

    they improve performance and API simplicity. – When? You should write new components based on Signals and migrate older components if time permits. Currently, there’s no hurry: RxJS and the traditional ways in Angular won’t go away anytime soon, and some Signal APIs and frameworks are still in developer preview. – How? Manual effort required, no automated migration available. (Could probably be handled by GenAI.) Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals
  20. Signals Standalone Components and APIs Built-in Control Flow and Deferrable

    Views Server-Side Rendering, esbuild and Vite Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Agenda
  21. Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren

    NgModules UI-related components (BookModule) UI-related components (TodoModule) Logic/ infrastructure components (BookModule) Logic/ infrastructure components (TodoModule) Components Directives Pipes High-Level Services Low-Level Services
  22. @NgModule({ declarations: [AppComponent, HomeComponent, MenuComponent], imports: [BrowserModule], providers: [DataService], bootstrap:

    [AppComponent], }) export class AppModule { } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren NgModules
  23. The problem with modules… @Component({ selector: 'app-my', template: `<a *ngFor="let

    item of items" [appTooltip]="item.tooltip">{{ item.name | myPipe }}</a>`, }) export class MyComponent { @Input({ required: true }) items!: Item[]; } Question: Where does appTooltip and myPipe come from? Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren NgModules
  24. @Component({ selector: 'app-my', template: `<a *ngFor="let item of items" [appTooltip]="item.tooltip">{{

    item.name | myPipe }}</a>`, standalone: true, imports: [NgFor, TooltipDirective, MyPipe] }) export class MyComponent { @Input({ required: true }) items!: Item[]; } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components
  25. Default with Angular 19 @Component({ selector: 'app-my', template: '', standalone:

    false }) export class MyComponent { } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components
  26. Lazy Loading export const ROUTES: Route[] = [ { path:

    'admin', loadComponent: () => import('./admin/panel.component') .then(mod => mod.AdminPanelComponent), providers: [MyService] }, // … ]; Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components https://angular.io/guide/standalone-components#lazy-loading-a-standalone-component
  27. Lazy Loading Multiple Routes export const ROUTES: Route[] = [

    {path: 'admin', loadChildren: () => import('./admin/routes')}, // … ]; export default [ {path: 'home', component: AdminHomeComponent}, {path: 'users', component: AdminUsersComponent}, // … ] as Route[]; Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components https://angular.io/guide/standalone-components#lazy-loading-many-routes-at-once
  28. Interoperability with NgModules – Standalone components/directives/pipes can’t be part of

    NgModules – When used in non-standalone components, it needs to be imported @NgModule({ declarations: [MyStandaloneComponent], imports: [MyStandaloneComponent], }) export const MyModule {} Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components
  29. Interoperability with NgModules @Component({ selector: 'app-my', template: `<a *ngFor="let item

    of items" [appTooltip]="item.tooltip">{{ item.name | myPipe }}</a>`, standalone: true, imports: [CommonModule, TooltipModule, PipeModule] }) export class MyComponent { @Input({ required: true }) items!: Item[]; } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components
  30. Folder Structure Modules main.ts app/app-routing.module.ts app/app.module.ts Standalone Apps main.ts app/app.routes.ts

    app/app.config.ts Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Applications
  31. Bootstrap API Modules import { platformBrowser } from '@angular/platform-browser'; import

    { AppModule } from './app/app.module'; platformBrowser() .bootstrapModule(AppModule) .catch(e => console.error(e)); Standalone Apps import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; bootstrapApplication(AppComponent) .catch(e => console.error(e)); Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Applications
  32. Providers Modules @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(routes), HttpClientModule ] })

    export class AppModule { } Standalone Apps export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), provideHttpClient(), // fallback for modules: importProvidersFrom (TranslateModule) ] }; Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Applications
  33. Migration Strategy – Maturity: Standalone components and APIs are fully

    stable. – Why? Standalone components and APIs improve developer experience and prepare your codebase for upcoming Angular features. – When? New projects should be started using standalone APIs, new components should be added as standalone components (default since version 17), NgModules and standalone are interoperable. – Existing projects should be migrated as soon as possible, new parts should be added using standalone components/APIs. – Some ng add/ng update integrations may not work with standalone workspaces. Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components & APIs
  34. How? – Migration can be partly automated – Manual changes

    will be required – Effort for mid-size projects: 4–8 hours – No functional difference – Changes to the project setup may lead to the migration to break – Replacements in unit tests may be incorrect – Migration does not introduce the new folder structure (app config) Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components & APIs
  35. Migration ng g @angular/core:standalone Angular 18 Neue Features optimal nutzen

    und Bestandsprojekte effizient migrieren Standalone Components & APIs
  36. Signals Standalone Components and APIs Built-in Control Flow and Deferrable

    Views Server-Side Rendering, esbuild and Vite Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Agenda
  37. If <ng-container *ngIf="item; else notFound"> <app-component [item]="item" /> </ng-container> <ng-template

    #notFound> Item not found! </ng-template> @if (item) { <app-component [item]="item" /> } @else { Item not found! } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow https://angular.dev/essentials/conditionals-and-loops#if-block
  38. Motivation – Control flow is built into the renderer, so

    you don’t have to import the structural directives (e.g., CommonModule, NgIf). – Dummy DOM elements such as <ng-container> are no longer needed. – The structural directive syntax (e.g., *ngIf) is not very common. – Better performance (up to 90% for @for), no longer tied to Zone.js. – Improve developer experience when dealing with common scenarios, such as “else” blocks, empty lists or deferring loading certain content. – But: Built-in control flow is not extensible, in contrast to structural directives (e.g., *ngxPermission). Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow https://angular.dev/guide/templates/control-flow https://blog.angular.io/introducing-angular-v17-4d7033312e4b
  39. Switch <ng-container [ngSwitch]="condition"> <ng-container *ngSwitchCase="caseA"> Case A. </ng-container> <ng-container *ngSwitchDefault>

    Default case. </ng-container> </ng-container> @switch (condition) { @case (caseA) { Case A. } @default { Default case. } } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow https://angular.dev/guide/templates/control-flow#switch-block---selection
  40. For <li *ngFor="let item of items; trackBy: trackByFn"> {{ item.name

    }} </li> <li *ngIf="items.length===0"> No items. </li> @for (item of items; track item.name) { <li> {{ item.name }} </li> } @empty { <li> No items. </li> } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow https://angular.dev/essentials/conditionals-and-loops#for-block
  41. Migration Strategy – Maturity: The built-in control flow is fully

    stable in Angular 18. – Why? Optimizes developer experience for common scenarios and improves performance (Zone.js, mandatory tracking in for loops) – When? Start using control flow now and migrate your codebase as soon as possible. Otherwise, keep using structural directives and migrate later. – Supported by current versions of WebStorm, VS Code and Prettier. – But: The syntax does not match the HTML standard and may lead to problems with older IDE versions or tooling that is not aware of it. Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow
  42. How? – Migration can be automated – Target path can

    be specified (allowing a step-by-step migration) – Allows formatting affected files – Removes CommonModule/structural directive imports from component class – Manual changes likely required – Effort for mid-size projects: < 1 hour – No functional changes Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow
  43. How? – @for tracks the count variable by default (not

    necessarily best for performance) – The built-in control flow does not support some rarely used features that were previously possible (e.g., *ngFor collection aliasing, multiple *ngIf aliases, …). These usages must be changed before running the migration. – Template reformatting does not use Prettier Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow
  44. Migration ng g @angular/core:control-flow Angular 18 Neue Features optimal nutzen

    und Bestandsprojekte effizient migrieren Built-in Control Flow
  45. Motivation – Takes lazy loading a step further by bringing

    it to the template level, which can improve the load time performance of your application. – Loads a (large/rarely used) view only based on a certain trigger (e.g., when the template enters the viewport, the device is idle, …). – Everything uses template magic, enabled by the new @defer block. – Offers helpers like @placeholder (while the content is being loaded), or @error when the content fails to load. – An example for a feature that is only accessible via the new syntax. – Fully stable in Angular 18 Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Deferrable Views
  46. Examples @defer (on viewport) { <calendar-cmp /> } @placeholder {

    <div>Calendar placeholder</div> } @error { Failed to load the calendar! } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Deferrable Views https://angular.dev/guide/defer
  47. Signals Standalone Components and APIs Built-in Control Flow and Deferrable

    Views Server-Side Rendering, esbuild and Vite Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Agenda
  48. Motivation – Server-side rendering (SSR) renders the application on the

    server, significantly improving load time performance – Prerendering/static site generation (SSG) renders all static HTML files during build time, improving server response time – Hydration allows client-side Angular to reattach to the server-rendered DOM nodes during launch, improving client-side load time – Partial Hydration (implementation in progress) renders the content of a @defer block on the server and reattaches on the client. Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Server-Side Rendering
  49. Motivation <html> <body> <app-root></app-root> </body> </html> <html> <body> <app-root _nghost-ng-c1888335296=""

    ng- version="17.1.3" ngh="0" ng-server- context="ssr"><main _ngcontent-ng- c1888335296="" class="main"><div _ngcontent- ng-c1888335296="" class="content"><div _ngcontent-ng-c1888335296="" class="left- side"><svg _ngcontent-ng-c1888335296="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 982 239" fill="none" class="angular-logo"><!-- -- ></svg></a></div></div></div></main><router- outlet _ngcontent-ng- c1888335296=""></router-outlet><!-- container--></app-root> </body> </html> Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Server-Side Rendering
  50. In Angular 17 – SSR is now fully integrated with

    Angular and includes SSR, prerendering, and hydration – Angular Universal is no longer offered as a separate library – For new projects, SSR can be easily enabled (e.g., ng new <name> --ssr) – Existing projects first have to switch to the new application builder and update their configuration – Angular Material 18: all components support hydration Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Server-Side Rendering
  51. Caveats – Setting up SSR with authentication is hard, SSG

    may be impossible. – Custom or Noop Zone.js are not yet supported. – When the Angular Service Worker is used, SSR is only used on the first visit. – All components must be built for hydration. – Libraries that depend on DOM manipulation (D3 charts, grids, …) may break hydration. Skipping hydration is possible via ngSkipHydration, but you’ll lose the advantages of hydration. Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Server-Side Rendering
  52. Partial Hydration (hypothetical syntax!) @defer (render on server; on viewport)

    { <app-calendar/> } @placeholder { <div>Calendar placeholder</div> } @error { Failed to load the calendar! } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Server-Side Rendering https://angular.dev/guide/defer
  53. Motivation The JavaScript ecosystem has advanced and new (and significantly

    faster) build tools have arrived. Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren esbuild and Vite https://esbuild.github.io/
  54. Motivation – Significantly faster build times (initial/incremental) – Compatibility with

    native ECMAScript Modules (ESM) and the modern JavaScript ecosystem – Hot module replacement (HMR) support for styles (performance improvement) Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren esbuild and Vite https://blog.angular.io/introducing-angular-v17-4d7033312e4b
  55. New Builders browser-esbuild More compatible, drop-in replacement for “browser” builder

    application Integrated SSR, requires code changes when SSR was used, requires configuration changes "architect": { "build": { "builder": "@angular-devkit/build-angular:application", "options": { "outputPath": { "base": "dist/my-app" }, "index": "src/index.html", "polyfills": [ "zone.js" ], "tsConfig": "tsconfig.app.json", "assets": [ "src/favicon.ico", "src/assets", Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren esbuild and Vite https://angular.dev/tools/cli/build-system-migration
  56. Motivation – Maturity: New apps created from Angular 17 onwards

    will automatically use the application builder – Why? Significantly faster build times, modern JavaScript – When? The existing Webpack-based build system is still stable. Old apps will not be migrated automatically. As Angular will move on, you should migrate as time permits. – How? Aim for application; if that is not possible, try browser-esbuild. Just replace the builders in angular.json and see if the build works. If not, investigate and estimate the effort. Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren esbuild and Vite
  57. Migration ng update @angular/cli --name use-application-builder Angular 18 Neue Features

    optimal nutzen und Bestandsprojekte effizient migrieren esbuild and Vite
  58. The “Angular Renaissance” is real Notable advancements while being backwards

    compatible Increased build/runtime performance and developer experience Keep your users and developers happy Angular 17.1+ apps will look significantly different to previous versions Avoid technical debt, migrate now Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Summary