Slide 1

Slide 1 text

Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Christian Liebel @christianliebel Consultant Angular 18

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren “Angular Renaissance”

Slide 4

Slide 4 text

Control state change events const nameControl = new FormControl('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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Fallback content for @Component({ selector: 'app-profile', template: ` Hello Unknown user `, }) 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

Slide 7

Slide 7 text

Material 3 Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Angular 18

Slide 8

Slide 8 text

TypeScript Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Angular 18

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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 {{ binding }} {{ binding }} {{ binding }} {{ binding }}

Slide 12

Slide 12 text

POSSIBLE Future Change Detection Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals {{ binding }} {{ signal() }} {{ binding }} {{ binding }}

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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(); } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://blog.angular-university.io/angular-signal-inputs/

Slide 17

Slide 17 text

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(); } @Component({ selector: "counter", standalone: true, template: "{{ value() }}", }) export class CounterComponent { value = model.required(); } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals https://blog.angular-university.io/angular-signal-inputs/

Slide 18

Slide 18 text

Signal-based Components (since Angular 17.3) @Component({ selector: "counter", standalone: true, template: "", }) export class CounterComponent { @Output() count = new EventEmitter(); } @Component({ selector: "counter", standalone: true, template: "", }) export class CounterComponent { count = output(); } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals

Slide 19

Slide 19 text

Signal-based Components (since Angular 17.2) @ViewChild(MyComponent) a!: MyComponent; @ViewChilren(MyComponent) b!: QueryList; @ContentChild(MyComponent) c!: MyComponent; @ContentChildren(MyComponent) d!: QueryList; a = viewChild(MyComponent); b = viewChildren(MyComponent); c = contentChild(MyComponent); d = contentChildren(MyComponent); Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals

Slide 20

Slide 20 text

Zoneless Change Detection (since Angular 18.0) bootstrapApplication(AppComponent, { providers: [ provideExperimentalZonelessChangeDetection(), ], }); Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Signals

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

@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

Slide 27

Slide 27 text

The problem with modules… @Component({ selector: 'app-my', template: `{{ item.name | myPipe }}`, }) 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

Slide 28

Slide 28 text

@Component({ selector: 'app-my', template: `{{ item.name | myPipe }}`, 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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Interoperability with NgModules @Component({ selector: 'app-my', template: `{{ item.name | myPipe }}`, 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

Slide 34

Slide 34 text

Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Migration ng g @angular/core:standalone Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Standalone Components & APIs

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

If Item not found! @if (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

Slide 43

Slide 43 text

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 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

Slide 44

Slide 44 text

Switch Case A. Default case. @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

Slide 45

Slide 45 text

For
  • {{ item.name }}
  • No items.
  • @for (item of items; track item.name) {
  • {{ item.name }}
  • } @empty {
  • No items.
  • } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow https://angular.dev/essentials/conditionals-and-loops#for-block

    Slide 46

    Slide 46 text

    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

    Slide 47

    Slide 47 text

    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

    Slide 48

    Slide 48 text

    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

    Slide 49

    Slide 49 text

    Migration ng g @angular/core:control-flow Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Built-in Control Flow

    Slide 50

    Slide 50 text

    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

    Slide 51

    Slide 51 text

    Examples @defer (on viewport) { } @placeholder {
    Calendar placeholder
    } @error { Failed to load the calendar! } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Deferrable Views https://angular.dev/guide/defer

    Slide 52

    Slide 52 text

    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

    Slide 53

    Slide 53 text

    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

    Slide 54

    Slide 54 text

    Motivation
    Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Server-Side Rendering

    Slide 55

    Slide 55 text

    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 --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

    Slide 56

    Slide 56 text

    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

    Slide 57

    Slide 57 text

    Partial Hydration (hypothetical syntax!) @defer (render on server; on viewport) { } @placeholder {
    Calendar placeholder
    } @error { Failed to load the calendar! } Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren Server-Side Rendering https://angular.dev/guide/defer

    Slide 58

    Slide 58 text

    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/

    Slide 59

    Slide 59 text

    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

    Slide 60

    Slide 60 text

    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

    Slide 61

    Slide 61 text

    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

    Slide 62

    Slide 62 text

    Migration ng update @angular/cli --name use-application-builder Angular 18 Neue Features optimal nutzen und Bestandsprojekte effizient migrieren esbuild and Vite

    Slide 63

    Slide 63 text

    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

    Slide 64

    Slide 64 text

    Thank you for your kind attention! Christian Liebel @christianliebel [email protected]