Angular 16 official release

In previous Angular v15, the Angular team reached an important milestone in Angular's simplicity and developer experience by upgrading the independent API from the developer preview to the stable version. Today, Angular continues that momentum with the release of its biggest version update since Angular's original launch; huge leaps forward in Reactivity, server-side rendering, and tooling.

image.png

1. Rethink Reactive Reactivity

As part of the v16 release, Angular brings a developer preview of the new Reactivity model, which brings significant improvements to performance and developer experience. It is fully backward compatible and interoperable with the current system, and provides some functions as follows:

  • Improve runtime performance by reducing the number of calculations during change detection.
  • Brings a simpler mental model to Reactivity, making it clear about view dependencies and data flow through the application.
  • Enables fine-grained reactivity, which in a future release will allow us to only check for changes in affected components.
  • In a future release, make Zone.js optional by using Signals to notify the framework when the model changes.
  • Provides computed properties without recomputing on each change detection cycle.
  • Implemented better interoperability with RxJS.

1.1AngularSignals

The AngularSignals library allows you to define reactive values ​​and express dependencies between them. You can learn more about library features in the corresponding RFCs . Here's a simple example of how to use it with Angular:

@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.firstName()));
  }
  setName(newName: string) {
    this.firstName.set(newName);
  }
}

The above code segment creates a calculated attribute value fullName, which depends on firstName and lastNamesignals. We also declare an effect, and its callback function will be executed every time the signal value it reads is updated, that is, re-executed when firstName changes. , the fullName computed property above means it will depend on changes in the firstName and lastName signal values. When we set firstName to "John", the browser will print the following log:

"Namechanged:JohnDoe"

1.2 RxJS Interoperability

You'll be able to easily convert signals to observables with functions in @angular/core/rxjs-interop that are part of the v16 dev preview. For example, here's how to convert a signal to an observable:

import { toObservable, signal } from '@angular/core/rxjs-interop';
@Component({...})
export class App {
  count = signal(0);
  count$ = toObservable(this.count);
  ngOnInit() {
    this.count$.subscribe(() => ...);
  }
}

Here's an example of how to convert an observable to a signal to avoid using async pipes:

import {toSignal} from '@angular/core/rxjs-interop';
@Component({
  template: `
    <li *ngFor="let row of data()"> {
   
   { row }} </li>
  `
})
export class App {
  dataService = inject(DataService);
  data = toSignal(this.dataService.data$, []);
}

Angular users usually want to complete a flow when the related Subject completes. The following pattern is very common:

destroyed$ = new ReplaySubject<void>(1);
data$ = http.get('...').pipe(takeUntil(this.destroyed$));
ngOnDestroy() {
  this.destroyed$.next();
}

Next, we introduce a new RxJS operator takeUntilDestroyed, a simple usage example is as follows:

data$=http.get('…').pipe(takeUntilDestroyed());

By default, this operator will inject into the current cleanup context. If used in a component, it will use the component's lifecycle. takeUntilDestroy is especially useful when you want to tie the lifecycle of an Observable to the lifecycle of a specific component. And takeUntilDestroy is implemented based on the DestroyRef below.

1.3signals next stage

Next, we will study signal-based components , which will simplify lifecycle hook functions and a simple declarative input (inputs) and output (outputs), and we will also write a more complete set of examples and documentation.

The most popular Issue in the Angular repository is " Proposal: InputasObservable ". We responded a few months ago to support this feature as part of the framework, and we're excited to share that later this year, we'll be rolling out a feature that will enable signal-based input -- you'll be able to The interop package converts inputs into observables.

2. Server-side rendering and hydration enhancement

According to Angular's annual developer survey, server-side rendering is the number one area of ​​improvement for Angular. Over the past few months, Angular has worked with the ChromeAurora team to improve performance and DX for hydration and server-side rendering. Today, Angular brings a developer preview of non-destructive hydration for full applications.

image.png

In the new full application non-destructive hydration, Angular no longer re-renders the application from scratch. Instead, the framework looks for existing DOM nodes and attaches event listeners to those nodes while building its internal data structures. The benefits of doing this are:

  • To the end user, there is no flickering of content on the page.
  • There are better Web Core vitals in some cases.
  • Future-proof the architecture, enabling fine-grained code loading with primitives we'll be launching later this year.
  • Easily integrate with existing applications with just a few lines of code.
  • For components that perform manual DOM manipulation, use the ngSkipHydration attribute in templates to gradually adopt hydration.

In early testing, we saw a 45% increase in Large Contentful Paint through application-wide Hydration. Some apps have already implemented Hydration in production and reported improvements in CWV: to get started just add the following lines of code to main.ts.

import {
  bootstrapApplication,
  provideClientHydration,
} from '@angular/platform-browser';
...
bootstrapApplication(RootCmp, {
  providers: [provideClientHydration()]
});

2.1 New server-side rendering features

As part of the v16 release, we've also updated Angular Universal's ng-add schematic to enable you to add server-side rendering to your project using the standalone API. We've also introduced support for stricter Content .

2.2 Next steps for Hydration and server-side rendering

The work in v16 is just a stepping stone, we plan to do more work here. In some cases, there is an opportunity to delay loading JavaScript that is not critical to the page, and to Hydrate related components later. This technique is called partial hydration, and we'll explore it in the next step.

Since Qwik popularized the idea of ​​recoverability from Google's closed-source framework Wiz, we've had many requests for this feature in Angular. Restorability is definitely on our roadmap, and we're working closely with the Wiz team to explore more spaces. We're cautious about the limitations it brings to the developer experience, evaluating different tradeoffs, and will keep you updated as we make progress.

You can see more future plans by reading " What's next for server-side rendering in Angular ".

3. Improved tools for independent components/directives/pipelines

Angular is an application framework used by millions of developers for many mission-critical applications, we take breaking changes seriously, we started exploring independent APIs years ago, in 2022 we released them in developer preview, now, After over a year of collecting feedback and iterating on the APIs, we hope for wider adoption!

In order to support developers to convert their applications to independent APIs, we have developed a migration schematic diagram and a migration guide for independent components . You enter the project and execute the following commands:

ng generate @angular/core:standalone

Schematic will transform your code, remove unnecessary NgModules classes, and finally change the project's bootstrap to use standalone APIs.

3.1 Standalone ng new set

As part of Angular v16, you can start by creating a new standalone project. To try the dev preview of the standalone APIs schematic, make sure you're on Angular CLI v16 and run:

ng new --standalone

You'll get simpler project directories without any NgModules, plus all generators in the project will generate standalone directives, components and pipelines.

3.2 Configure Zone.js

After the initial release of the standalone APIs, we heard from developers that they wanted to be able to configure Zone.js using the new bootstrapApplication API. We add some options via provideZoneChangeDetection:

bootstrapApplication(App, {
  providers: [provideZoneChangeDetection({ eventCoalescing: true })]
});

3.3 Development preview version of esbuild-based build system

Over a year ago, we announced that we were getting experimental support for esbuild in the Angular CLI for faster builds. Today, we're excited to share that with v16, our esbuild-based build system is in dev preview! Early tests showed an improvement of more than 72% in cold production environment builds.

image.png

In ng serve, we now use Vite as the development server, and esbuild provides builds in development and production environments.

We want to emphasize that Angular CLI completely relies on Vite as a development server. To support selector matching, the Angular compiler needs to maintain a dependency graph between components, which requires a different compilation model than Vite. You can try Vite + esbuild by updating angular.json:

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

Next, we'll address i18n support before we move this feature from developer preview to production.

3.4 Autocomplete imports in templates

How many times have you gotten an error from the CLI or language service using a component or pipeline in a template without actually importing the corresponding implementation? I guess many times. Language services now allow automatic import of components and pipelines.

1.gif

The animation above shows the automatic import function of the Angular language service in VSCode.

4. Improve developer experience

In addition to the big plans we're focusing on, we're also working on introducing much-requested features.

4.1 Input required (Required inputs)

Since we introduced Angular in 2016, it's impossible to get a compile-time error without specifying a value for a particular input. Since the Angular compiler performs checks at build time, this change adds zero overhead at runtime, and developers have been asking for this feature for years, and we got a strong indication that it will be very handy! In v16, you can mark an input as required if you want:

@Component(...)
export class App {
  @Input({ required: true }) title: string = '';
}

4.2 Pass router data as component input

The development experience for routing has been evolving rapidly, and one of the popular feature requests on GitHub is to be able to bind route parameters to the inputs of the corresponding components. We're excited to share that this feature is now available as part of the v16 release. Now, the following data can be passed to the input of the routing component:

  • route data — resolvers and data attributes
  • Path parameter
  • Query parameters

Here is an example of how to access route resolver data:

const routes = [
  {
    path: 'about',
    loadComponent: import('./about'),
    resolve: { contact: () => getContact() }
  }
];
@Component(...)
export class About {
  // The value of "contact" is passed to the contact input
  @Input() contact?: string;
}

4.3 CSP support for inline styles

Angular includes inline style elements in a component's styled DOM that violate the default style-src Content Security Policy (CSP). To fix this, they should contain a nonce attribute, or the server should include a hash of the style content in the CSP header. Although at Google we found no meaningful attack vectors for this vulnerability, many companies have implemented strict CSPs, leading to popular feature requests on the Angular repository.

In Angular v16, we implemented a new feature across frameworks, Universal, CDK, Material, and CLI that allows you to specify a nonce attribute for the styles of Angular inline components. There are two ways to specify a nonce: using the ngCspNonce attribute or by injecting the token with CSP_NONCE.

The ngCspNonce attribute is useful if you have access to server-side templates that can add nonces to headers and index.html when constructing responses.

<html>
<body>
  <app ngCspNonce="{% nonce %}"></app>  
</body>
</html>

Another way is to specify a nonce via CSP_NONCE injection token. If you have access to the nonce at runtime and want to be able to cache index.html, use this method:

import {bootstrapApplication, CSP_NONCE} from '@angular/core';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
  providers: [{
    provide: CSP_NONCE,
    useValue: globalThis.myRandomNonceValue
  }]
});

4.4 Flexible ngOnDestroy

Angular's Lifecycle Hooks provide a large number of functions that can be inserted into different moments of application execution. How to achieve higher flexibility is an opportunity and choice, for example, providing access to OnDestroy as an observable as an observable way.

In v16, we made OnDestroy injectable, which provides the flexibility developers have been asking for. The new functionality allows you to inject a DestroyRef corresponding to a component, directive, service or pipeline, and to register an onDestroy lifecycle hook function. DestroyRef can be injected anywhere in the injection context, including outside of components - in this case, the ngDestroy hook will be executed when the corresponding injector is destroyed:

import { Injectable, DestroyRef } from '@angular/core';
@Injectable(...)
export class AppService {
  destroyRef = inject(DestroyRef);
  destroy() {
    this.destroyRef.onDestroy(() => /* cleanup */ );
  }
}

4.5 Self-closing tags

A much-requested feature we recently implemented that allows you to use self-closing tags for components in Angular templates is a small development experience improvement that will save you some typing. for example:

<super-duper-long-component-name [prop]="someVar"></super-duper-long-component-name>
//替换为
<super-duper-long-component-name [prop]="someVar" />

4.6 Better, more flexible components

Over the past few quarters, we've worked closely with Google's Material Design team to deliver a Material 3 implementation of Angular Material for the Web. The MDC Web-based components we are delivering in 2022 provide the foundation for this work.

As a next step, we're working on launching an expressive token-based theming API later this year that enables higher customization of Angular Material components.

As a reminder, we will be removing legacy, non-MDC based components in v17, make sure you follow our migration guide to get the latest version.

Reference documents:

https://blog.angular.io/angular-v16-is-here-4d7a28ec680d

Guess you like

Origin blog.csdn.net/xiangzhihong8/article/details/130504921