Angular小博客

分享让你更聪明

[译2022]Angular v15 现已推出!

浏览:4次 日期:2024年10月20日 23:02:46 作者:admin

在过去的一年里,我们删除了 Angular 的旧版编译器和渲染管道,这使得在过去几个月内实现了一系列开发人员体验的改进。 Angular v15 是这方面的巅峰之作,它进行了数十项改进,带来了更好的开发人员体验和性能。

独立 API 现已退出开发者预览版!

在 v14 中,我们引入了新的独立 API,使开发人员能够在不使用 NgModule 的情况下构建应用程序。我们很高兴地告诉大家,这些 API 已从开发者预览版毕业,现在已成为稳定 API 界面的一部分。从现在开始,我们将按照语义版本控制逐步发展它们。

作为确保独立 API 准备好毕业的一部分,我们确保独立组件可以跨 Angular 工作,它们现在可以在HttpClient 、 Angular Elements 、路由器等中完全工作。

独立 API 允许您使用单个组件引导应用程序:

import {bootstrapApplication} from '@angular/platform-browser';
import {ImageGridComponent} from'./image-grid';

@Component({
  standalone: true,
  selector: 'photo-gallery',
  imports: [ImageGridComponent],
  template: `
    … <image-grid [images]="imageList"></image-grid>
  `,
})
export class PhotoGalleryComponent {
  // component logic
}

bootstrapApplication(PhotoGalleryComponent);

Router 和 HttpClient 可摇树独立 API

您可以使用新的路由器独立 API 构建多路由应用程序!要声明根路由,您可以使用以下命令:

export const appRoutes: Routes = [{
  path: 'lazy',
  loadChildren: () => import('./lazy/lazy.routes')
    .then(routes => routes.lazyRoutes)
}];

其中lazyRoutes声明于:

import {Routes} from '@angular/router';

import {LazyComponent} from './lazy.component';

export const lazyRoutes: Routes = [{path: '', component: LazyComponent}];

最后,在bootstrapApplication调用中注册appRoutes :

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(appRoutes)
  ]
});

provideRouter API 的另一个好处是它可以进行树摇动!捆绑器可以在构建时删除路由器未使用的功能。在使用新 API 进行的测试中,我们发现从捆绑包中删除这些未使用的功能可以使应用程序捆绑包中的路由器代码大小减少 11%。

指令(Directive)组合API

指令组合 API 将代码重用提升到另一个水平!此功能的灵感来自 GitHub 上最流行的功能请求,要求提供向主机元素添加指令的功能。

指令组合 API 使开发人员能够使用指令增强主机元素,并为 Angular 配备强大的代码重用策略,这要归功于我们的编译器。指令组合 API 仅适用于独立指令。

让我们看一个简单的例子:

@Component({
  selector: 'mat-menu',
  hostDirectives: [HasColor, {
    directive: CdkMenu,
    inputs: ['cdkMenuDisabled: disabled'],
    outputs: ['cdkMenuClosed: closed']
  }]
})
class MatMenu {}

在上面的代码片段中,我们使用两个指令增强了MatMenu : HasColorCdkMenu 。 MatMenu重用HasColor的所有输入、输出和关联逻辑,并且仅重用CdkMenu的逻辑和选定的输入。

这种技术可能会让您想起某些编程语言中的多重继承或特征,不同之处在于我们有解决名称冲突的机制,并且它适用于用户界面原语。

图像指令现已稳定!

我们发布了 Angular图像指令的开发者预览版,该指令是我们与Chrome Aurora在 v14.2 中合作开发的。

演示应用程序之前和之后

我们很高兴地告诉大家,它现在已经稳定了! Land’s End对此功能进行了实验,并在灯塔实验室测试中观察到 LCP 提高了 75%。

v15 版本还包括一些针对 image 指令的新功能:

您可以直接在组件或 NgModule 中使用独立的NgOptimizedImage指令:

import { NgOptimizedImage } from '@angular/common';

// Include it into the necessary NgModule
@NgModule({
  imports: [NgOptimizedImage],
})
class AppModule {}

// ... or a standalone Component
@Component({
  standalone: true
  imports: [NgOptimizedImage],
})
class MyStandaloneComponent {}

要在组件中使用它,只需将图像的src属性替换为ngSrc并确保指定 LCP 图像的priority属性。

您可以在我们的文档中找到更多信息。

路由守卫功能

与可摇树的独立路由器 API 一起,我们致力于减少防护中的样板文件。让我们看一个示例,其中我们定义了一个警卫来验证用户是否已登录:

@Injectable({ providedIn: 'root' })
export class MyGuardWithDependency implements CanActivate {
  constructor(private loginService: LoginService) {}

  canActivate() {
    return this.loginService.isLoggedIn();
  }
}

const route = {
  path: 'somePath',
  canActivate: [MyGuardWithDependency]
};

LoginService实现了大部分逻辑,在守卫中我们只调用isLoggedIn() 。尽管守卫非常简单,但我们有很多样板代码。

使用新的功能性路由器防护,您可以将此代码重构为:

const route = {
  path: 'admin',
  canActivate: [() => inject(LoginService).isLoggedIn()]
};

我们在守卫声明中表达了整个守卫。功能防护也是可组合的——您可以创建类似工厂的函数来接受配置并返回防护或解析器函数。您可以在 GitHub 上找到串行运行路由器防护的示例。

路由器解开默认导入

为了使路由器更简单并进一步减少样板文件,路由器现在在延迟加载时自动解包默认导出。

假设您有以下LazyComponent :

@Component({
  standalone: true,
  template: '...'
})
export default class LazyComponent { ... }

在此更改之前,要延迟加载独立组件,您必须:

{
  path: 'lazy',
  loadComponent: () => import('./lazy-file').then(m => m.LazyComponent),
}

现在,路由器将查找默认导出,如果找到,则自动使用它,这将路由声明简化为:

更好的堆栈跟踪

我们从年度开发者调查中获得了很多见解,因此我们要感谢您花时间分享您的想法!深入研究开发人员面临的调试体验难题,我们发现错误消息需要一些改进。

有关调试挑战的反馈

Angular 开发人员的调试难题

我们与 Chrome DevTools 合作解决了这个问题!让我们看一下您可能在 Angular 应用程序上使用的示例堆栈跟踪:

ERROR Error: Uncaught (in promise): Error
Error
    at app.component.ts:18:11
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (asyncToGenerator.js:3:1)
    at _next (asyncToGenerator.js:25:1)
    at _ZoneDelegate.invoke (zone.js:372:26)
    at Object.onInvoke (core.mjs:26378:33)
    at _ZoneDelegate.invoke (zone.js:371:52)
    at Zone.run (zone.js:134:43)
    at zone.js:1275:36
    at _ZoneDelegate.invokeTask (zone.js:406:31)
    at resolvePromise (zone.js:1211:31)
    at zone.js:1118:17
    at zone.js:1134:33

这段代码有两个主要问题:

Chrome DevTools 团队创建了一种机制,通过 Angular CLI 注释源映射来忽略来自node_modules的脚本。我们还合作开发了异步堆栈标记 API,该 API 允许我们将独立的预定异步任务连接到单个堆栈跟踪中。 Jia Li将 Zone.js 与异步堆栈标记 API 集成,这使我们能够提供链接的堆栈跟踪。

这两项更改极大地改善了开发人员在 Chrome DevTools 中看到的堆栈跟踪:

ERROR Error: Uncaught (in promise): Error
Error
    at app.component.ts:18:11
    at fetch (async)  
    at (anonymous) (app.component.ts:4)
    at request (app.component.ts:4)
    at (anonymous) (app.component.ts:17)
    at submit (app.component.ts:15)
    at AppComponent_click_3_listener (app.component.html:4)

在这里,您可以跟踪从AppComponent中按下按钮一直到出现错误的执行过程。您可以在此处阅读有关改进的更多信息。

将基于 MDC 的组件发布到稳定版

我们很高兴地宣布基于Web 材料设计组件 (MDC) 的Angular 材料组件的重构现已完成!这一更改使 Angular 能够更接近 Material Design 规范,重用 Material Design 团队开发的原语代码,并使我们能够在最终确定样式标记后采用 Material 3。

对于许多组件,我们更新了样式和 DOM 结构,其他组件我们从头开始重写。我们保留了新组件的大部分 TypeScript API 和组件/指令选择器与旧实现相同。

我们迁移了数千个 Google 项目,这使我们能够使外部迁移路径变得顺畅,并记录所有组件中更改的完整列表

由于新的 DOM 和 CSS,您可能会发现应用程序中的某些样式需要调整,特别是当您的 CSS 覆盖任何迁移组件上的内部元素的样式时。

每个新组件的旧实现现已弃用,但仍可通过“旧版”导入使用。例如,您可以通过导入旧按钮模块来导入旧的mat-button实现。

import {MatLegacyButtonModule} from '@angular/material/legacy-button';

请访问迁移指南以获取更多信息。

我们将许多组件移至后台使用设计标记和 CSS 变量,这将为应用程序采用 Material 3 组件样式提供一条平滑的路径。

组件方面的更多改进

我们解决了第四个投票最多的问题——滑块中的范围选择支持

要获取范围输入,请使用:

<mat-slider>
  <input matSliderStartThumb>
  <input matSliderEndThumb>
</mat-slider>

此外,所有组件现在都有一个 API 来自定义密度,这解决了另一个流行的 GitHub 问题

您现在可以通过自定义主题来指定所有组件的默认密度:

@use '@angular/material' as mat;

$theme: mat.define-light-theme((
  color: (
    primary: mat.define-palette(mat.$red-palette),
    accent: mat.define-palette(mat.$blue-palette),
  ),
  typography: mat.define-typography-config(),
  density: -2,
));

@include mat.all-component-themes($theme);

新版本的组件包括广泛的可访问性改进,包括更好的对比度、增加的触摸目标尺寸和改进的 ARIA 语义。

CDK列表框

组件开发工具包 (CDK) 提供了一组用于构建 UI 组件的行为原语。在 v15 中,我们引入了另一个可以根据您的用例进行自定义的原语 — CDK 列表框:

@angular/cdk/listbox模块提供指令来帮助创建基于 WAI ARIA 列表框模式的自定义列表框交互。

通过使用@angular/cdk/listbox您可以获得可访问体验的所有预期行为,包括双向布局支持、键盘交互和焦点管理。所有指令都将其关联的 ARIA 角色应用于其宿主元素。

实验性 esbuild 支持的改进

在 v14 中,我们宣布在ng build中对esbuild进行实验性支持,以实现更快的构建时间并简化我们的管道。

在 v15 中,我们现在有了实验性的 Sass、SVG 模板、文件替换和ng build --watch支持!请通过从以下位置更新您的构建器angular.json来尝试 esbuild:

"builder": "@angular-devkit/build-angular:browser"

 到:

"builder": "@angular-devkit/build-angular:browser-esbuild"

如果您在生产版本中遇到任何问题,请通过在 GitHub 上提交问题来告知我们。

语言服务中的自动导入

语言服务现在可以自动导入您在模板中使用但尚未添加到独立组件或 NgModule 的组件。

语言服务自动导入

CLI 改进

在 Angular CLI 中,我们引入了对独立稳定 API 的支持。现在您可以通过ng g component --standalone生成一个新的独立组件。

我们还致力于简化ng new的输出。第一步,我们通过删除test.ts 、 polyfills.tsenvironments来减少配置。现在,您可以直接在angular.json polyfills部分中指定您的 polyfill:

"polyfills": [
  "zone.js"
]

为了进一步减少配置开销,我们现在使用.browserlist来允许您定义目标 ECMAScript 版本。

社区贡献亮点

我们很高兴与大家分享,自 v14 发布以来,我们收到了来自框架、组件和 CLI 的 210 多人的贡献!在本节中,我想重点介绍其中两个。

提供为 DatePipe 配置默认选项的能力

Matthias Weiß的此功能允许您全局更改DatePipe的默认格式配置。以下是新bootstrapApplication API 的示例:

bootstrapApplication(AppComponent, {
  providers: [
    {
      provide: DATE_PIPE_DEFAULT_OPTIONS,
      useValue: { dateFormat: 'shortDate' }
    }
  ]
});

上面的配置将为您在应用程序中使用DatePipe所有位置启用shortDate格式。

在 SSR 期间为优先图像添加 <link> 预加载标记

为了确保尽快加载优先图像, Jay Bell在图像指令中添加了一项功能,以便在使用 Angular Universal 时为其包含<link rel="preload">标记。

如果您已经启用了 image 指令,则无需执行任何操作。如果您已指定图像作为优先级,该指令将自动预加载它。

弃用

主要版本使我们能够将框架朝着简单化、更好的开发人员体验以及与 Web 平台保持一致的方向发展。

在分析了 Google 内的数千个项目后,我们发现很少有很少使用的模式,这些模式在大多数情况下都被滥用了。因此,我们弃用了providedIn: 'any'是一个选项,除了框架内部的一些深奥案例之外,它的用途非常有限。

我们还弃用了providedIn: NgModule 。它的用途并不广泛,而且在大多数情况下,在您应该更喜欢使用providedIn: 'root'的情况下,它的使用是错误的。如果您确实应该将提供程序范围限定到特定的NgModule ,请改用NgModule.providers 。

随着 CSS 布局的不断发展,团队将停止发布新版本的@angular/flex-layout 。我们将在明年继续提供安全和浏览器兼容性修复程序。您可以在我们的“现代 CSS”系列的第一篇博客文章中了解更多相关信息。

对接下来发生的事情感到兴奋!

Ivy 于 2020 年推出,带来了许多全面的改进,您可以发现这些改进已经在推出。可选的 NgModules 就是一个很好的例子。它有助于减少初学者在关键学习过程中需要处理的概念,并且还支持高级功能,例如通过独立指令的指令组合 API。

接下来,我们将解决服务器端渲染管道和反应性的改进,同时全面提高生活质量!

迫不及待地想与您分享接下来会发生什么!

原文链接:https://blog.angular.dev/angular-v15-is-now-available-df7be7f2f4c8