首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Angular v20 版本发布

Angular v20 版本发布

作者头像
gemron的空间
修改于 2025-05-29 19:36:57
修改于 2025-05-29 19:36:57
3.3K0
举报
文章被收录于专栏:web全栈潮流web全栈潮流

过去的几年对 Angular 来说发生了翻天覆地的变化,我们推出了像使用 Signals 进行响应式和 Zoneless 应用程序的强大功能等重大进步。我们希望这些功能已经帮助 Angular 社区构建下一代快速上市且性能强大的 Web 应用程序。

我们才刚刚开始!Angular v20 是我们最新的发布版本,我们投入了无数小时来打磨一些正在进行中的功能,以提供您应得的稳固的开发者体验。

一些亮点:

  • 稳定 API,如 effect、linkedSignal、toSignal、增量水合、路由级别渲染模式配置以及推广 zoneless 至开发者预览
  • 通过 Angular DevTools 改进调试,并与 Chrome 合作,在 Chrome DevTools 中直接进行自定义 Angular 报告
  • 通过样式指南更新、类型检查、对宿主绑定支持的语言服务、模板中支持未标记的模板字面量表达式、默认启用模板热模块替换等功能,进一步优化开发者体验。
  • 使用 llms.txt 和 angular.dev 指南及视频,在构建生成式 AI 应用程序方面的 GenAI 开发进展
  • 发布关于 Angular 官方吉祥物的评论请求

将响应式功能提升为稳定版

我们在过去三年中重新思考了 Angular 的响应性模型,使其更加健壮和面向未来。在 Angular v16 中,我们发布了 Angular Signals 的开发者预览版,自那时起,它们在 Google 内部和外部得到了广泛的应用。

YouTube 在舞台上分享了如何使用 Angular Signals 与 Wiz 结合,他们在 Living Room 中通过 35%提高了输入延迟。与此同时,TC39 启动了对 JavaScript 语言引入 Signals 的调查,并基于 Angular Signals 提供了一个基于 Angular Signals 的参考实现 。

在收集了 RFCs 的反馈并对实现进行迭代后,我们将 signal、computed、input 和视图查询 API 提升为稳定状态。今天,我们宣布 effect、linkedSignal 和 toSignal 也已成为稳定 API。

新增实验性 API

为了解决使用 Angular 管理异步状态的问题,我们在 v19 中开发了资源 API。从那时起,我们引入了资源流并创建了一个名为 httpResource 的新 API,允许您使用基于 Signal 的反应式 API 进行 HTTP 请求。这两个 API 都作为 v20 的实验性功能提供。

资源 API 允许您在信号变化时启动异步操作,并将此操作的结果作为信号公开:

代码语言:javascript
复制
const userId: Signal<string> = getUserId();
const userResource = resource({
  params: () => ({id: userId()}),
  loader: ({request, abortSignal}): Promise<User> => {
    // fetch cancels any outstanding HTTP requests when the given `AbortSignal`
    // indicates that the request has been aborted.
    return fetch(`users/${request.id}`, {signal: abortSignal});
  },
});

当 userId 信号变化时,上述代码将获取具有特定标识符的用户。

现在假设我们从 WebSocket 获取数据。为此,我们可以使用流式资源:

代码语言:javascript
复制
@Component({
  template: `{{ dataStream.value() }}`
})
export class App {
  // WebSocket initialization logic will live here...
  // ...
  // Initialization of the streaming resource
  dataStream = resource({
    stream: () => {
      return new Promise<Signal<ResourceStreamItem<string[]>>>((resolve) => {
        const resourceResult = signal<{ value: string[] }>({
          value: [],
        });

        this.socket.onmessage = event => {
          resourceResult.update(current => ({
             value: [...current.value, event.data]
          });
        };

        resolve(resourceResult);
      });
    },
  });
}

在这个最小示例中,我们声明了一个新的流式资源,它返回一个信号值的承诺。该信号具有值类型 ResourceStreamItem<string[]>,这意味着该信号可以持有值 { value: string[] } 或 {error: … },如果我们想返回错误。

我们通过 resourceResult 信号发射从 WebSocket 收到的值。

在这个模式的基础上,我们还发布了实验性的 httpResource:

代码语言:javascript
复制
@Component({
  template: `{{ userResource.value() | json }}`
})
class UserProfile {
  userId = signal(1);
  userResource = httpResource<User>(() => 
    `https://example.com/v1/users/${this.userId()}`
  });
}

上面的代码片段将在每次 userId 发生变化时向指定的 URL 发送 HTTP GET 请求。httpResource 返回 HttpResourceRef,它有一个可以直接在模板中访问的 value 属性。此外,userResource 还有其他值,例如 isLoading、headers 等。

在底层,httpResource 使用 HttpClient,因此您可以在 HttpClient 提供器中指定拦截器:

代码语言:javascript
复制
bootstrapApplication(AppComponent, {providers: [
  provideHttpClient(
    withInterceptors([loggingInterceptor, cachingInterceptor]),
  )
]});

将无区域功能提升为开发者预览版

在过去的六个月里,我们在 zoneless 方面取得了很大的进展,特别是在服务器端渲染和错误处理方面。

许多开发者甚至没有意识到,他们在应用程序中使用 Zone.js 来捕获错误。Zone.js 还让框架知道何时将服务器端渲染的应用程序刷新到客户端。在 zoneless 的世界里,我们必须找到这些问题的强大解决方案。

在 v20 版本中,我们现在在 Node.js 中的 SSR 期间为 unhandledRejection 和 uncaughtException 提供了默认处理程序,以防止节点服务器在出现错误时崩溃。

在客户端,您可以在提供者中包含 provideBrowserGlobalErrorListeners 。您可以通过更新提供者列表来开始使用无 zone 模式:

代码语言:javascript
复制
bootstrapApplication(AppComponent, {providers: [
  provideZonelessChangeDetection(),
  provideBrowserGlobalErrorListeners()
]});

此外,请确保从您的 angular.json 中移除 zone.js polyfill。了解无 zone 模式的优势以及如何过渡到您的项目,请参阅我们的 文档 。

如果您正在创建一个新的 Angular 项目,您可以使用 CLI 从一开始就将其设置为无区域模式:

在服务器上巩固 Angular

在 v20 版本中,我们还专注于打磨我们的旗舰服务器端渲染特性——增量湿化和路由级别渲染模式配置。今天,我们很高兴将这两者都提升为稳定版!

提醒一下,增量湿化可以通过在特定触发器下下载和湿化页面的一部分来使您的应用更快。这样,您的用户不需要下载与特定页面相关的所有 JavaScript,而是可以逐步下载他们需要的部分。

要今天开始使用增量水合,请通过指定 withIncrementalHydration 来配置水合:

代码语言:javascript
复制
import { provideClientHydration, withIncrementalHydration } from '@angular/platform-browser';

// ...
provideClientHydration(withIncrementalHydration());

在您组件的模板中,现在可以使用可延迟视图:

代码语言:javascript
复制
@defer (hydrate on viewport) {
  <shopping-cart/>
}

这样,Angular 将会下载购物车组件及其传递依赖,并且仅在它进入视口时才初始化这部分 UI。

此外,您现在可以使用路由级别的渲染模式配置作为稳定的 API!如果您的应用中不同的路由有不同的渲染需求,您可以在服务器路由配置中进行配置:

代码语言:javascript
复制
export const routeConfig: ServerRoute = [
  { path: '/login', mode: RenderMode.Server },
  { path: '/dashboard', mode: RenderMode.Client },
  {
    path: '/product/:id',
    mode: RenderMode.Prerender,
    async getPrerenderParams() {
      const dataService = inject(ProductService);
      const ids = await dataService.getIds(); // ["1", "2", "3"]
      // `id` is used in place of `:id` in the route path.
      return ids.map(id => ({ id }));
    }
  }
];

在上面的代码片段中,我们配置在服务器上渲染登录页面,在客户端渲染仪表板,并预渲染产品页面。

注意产品页面需要一个 id 参数。为了解决每个产品的标识符,我们可以使用异步函数 getPrerenderParams。它返回一个对象,其中其键映射到路由参数。在 /product/:id 页面中,我们返回一个具有 id 属性的对象。

您可以使用大多数云服务提供商托管您的服务器端渲染应用。我们与 Firebase App Hosting 紧密合作,推出了一款无缝部署方案,该方案支持混合渲染(SSR、SSG 和 CSR),并为您提供 Google Cloud 的安全性和可扩展性。

精炼开发者体验

在开发 v20 版本的过程中,我们投入了大量时间在工程卓越性上——对现有 API 进行打磨,以提升您的开发体验。我们在各个方面都做到了这一点——框架、路由、表单、http 等。让我在这里分享我们做的工作吧!

Chrome DevTools 中的性能洞察

为了进一步提升开发者体验并深入了解应用性能,我们与 Chrome DevTools 团队合作,将 Angular 特定的分析数据直接集成到性能面板中。以前,开发者经常需要在框架特定的分析器和浏览器的 DevTools 之间切换,这使得关联信息和定位瓶颈变得具有挑战性,尤其是在压缩后的生产代码中。这次新集成旨在通过在同一时间轴上显示 Angular 运行时数据,如组件渲染、变更检测周期和事件监听器执行,来解决这一问题。

从 Angular v20 开始提供的这项直接集成,利用了性能面板扩展 API,特别是使用 console.timeStamp API,以低开销确保性能分析不会对应用性能产生负面影响。开发者现在可以更深入地了解 Angular 的内部工作原理,通过颜色编码的条目区分开发者编写的 TypeScript 代码和 Angular 编译器生成的代码。要启用此功能,只需在您的应用程序或 DevTools 控制台中运行全局实用工具 ng.enableProfiling() 即可。这一进步提供了更直观、更全面的性能分析体验,使开发者能够构建性能更优的 Angular 应用程序。

在上面的截图中,您可以看到这个功能在运行。注意性能时间线底部有一个专门用于 Angular 的轨道。通过颜色编码的条形,您可以预览组件实例化、运行变更检测等。Angular DevTools 和 Chrome 性能时间线中的 Angular 轨道使用相同的钩子,区别在于 Chrome 的性能时间线可以将您的应用程序的生命周期置于框架之外的 JavaScript 调用上下文中。

此外,Chrome 性能时间线中的 Angular 轨道显示了一些目前在 Angular DevTools 中不存在的数据,例如组件和提供者实例化。

框架新增和改进

要动态创建一个 Angular 组件,您可以使用 createComponent 函数。在 v20 版本中,我们引入了新的功能,允许您为动态创建的组件应用指令和指定绑定:

代码语言:javascript
复制
import {createComponent, signal, inputBinding, outputBinding} from '@angular/core';

const canClose = signal(false);
const title = signal('My dialog title');

// Create MyDialog
createComponent(MyDialog, {
  bindings: [
    // Bind a signal to the `canClose` input.
    inputBinding('canClose', canClose),

    // Listen for the `onClose` event specifically on the dialog.
    outputBinding<Result>('onClose', result => console.log(result)),
   
    // Creates two way binding with the title property
    twoWayBinding('title', title),
  ],
  directives: [
    // Apply the `FocusTrap` directive to `MyDialog` without any bindings.
    FocusTrap,

    // Apply the `HasColor` directive to `MyDialog` and bind the `red` value to its `color` input.
    // The callback to `inputBinding` is invoked on each change detection.
    {
      type: HasColor,
      bindings: [inputBinding('color', () => 'red')]
    }
  ]
});

我们在上面创建了一个对话框组件并指定:

  • canClose 输入绑定,传递信号 canClose 作为值
  • 将输出 onClose 设置为回调,以记录发出的结果
  • 在 title 属性和 title 信号之间建立双向绑定

此外,我们还向组件添加了 FocusTrap 和 HasColor 指令。注意,我们还可以为应用在 MyDialog 上的 HasColor 指令指定输入绑定。

扩展模板表达式语法

我们一直在弥合 Angular 模板表达式和完整 JavaScript 语法之间的差距,以实现更高的表达性和更好的开发者体验。今天,我们引入了对指数运算符 ** 和 in 运算符的支持:

代码语言:javascript
复制
<!-- n on power two -->
{{ n ** 2 }}

<!-- checks if the person object contains the name property -->
{{ name in person }}

在 v20 版本中,我们还允许您直接在表达式中使用未标记的模板字面量:

代码语言:javascript
复制
<div [class]="`layout col-${colWidth}`"></div>

扩展诊断

为了防止常见的错误,我们引入了静态检查,可以检测到 无效的空合并 、检测 结构指令缺失的导入 ,以及当你没有调用传递给 @for 的 track 函数时的 警告 :

代码语言:javascript
复制
@Component({
  template: `
    @for (user of users; track trackFn) {
      <!-- ... ->
    }
  `
})
class UserList {
  users = getUsers();

  trackFn() {
    // ... body
  }
}

Angular 模板中的 @for 循环接受一个 track 表达式。在实践中,trackFn 本身就是一个表达式,它返回一个 trackFn 函数,这是一个有效的值。同时,我们很可能想要调用 trackFn,新的诊断功能使得捕捉此类错误变得更加容易。

风格指南更新

在过去十年中,我们看到了成千上万的 APP 使用 Angular,因此决定更新我们的风格指南。我们的主要目标是使其现代化并去除不必要的复杂性。

在我们从一个 RFC 收集反馈后,我们引入了一系列简化措施——从风格指南中移除非 Angular 特定的代码健康实践,并将与编码风格无关的 Angular 最佳实践移至文档中。我们还使文件名和类名后缀变为可选,以鼓励更有意向的抽象命名,从而减少样板代码。

从 Angular v20 开始,默认情况下,Angular CLI 将不会为您的组件、指令、服务和管道生成后缀。对于现有项目,使用 ng update 将启用后缀生成,通过更新您的 angular.json。要在新项目中启用后缀生成,请使用以下图表示例配置:

代码语言:javascript
复制
{
  "projects": {
    "app": {
      ...
      "schematics": {
        "@schematics/angular:component": { "type": "component" },
        "@schematics/angular:directive": { "type": "directive" },
        "@schematics/angular:service": { "type": "service" },
        "@schematics/angular:guard": { "typeSeparator": "." },
        "@schematics/angular:interceptor": { "typeSeparator": "." },
        "@schematics/angular:module": { "typeSeparator": "." },
        "@schematics/angular:pipe": { "typeSeparator": "." },
        "@schematics/angular:resolver": { "typeSeparator": "." }
      },
  ...
}

近年来,Angular 发生了很大的变化,我们希望在风格指南中反映这种变化。因此,我们删除了大多数与 NgModules 相关的指导,并重新审视了在指令元数据中使用 @HostBinding 和 @HostListener 的方法,转而使用 host 对象。为了确保我们不会因为新的指南而降低开发者的体验,我们还解决了主机绑定支持中的一些空白。

改进的宿主绑定

历史上我们推荐使用 @HostBinding 和 @HostListener 的一个原因是,与组件元数据中的 host 对象相比,它们在编辑器支持方面略有优势,因为您可以直接在特定的绑定或方法上使用它们。同时,它们可能难以发现,使用装饰器,并且可能导致代码更加繁琐。

在 Angular v20 中,我们引入了对主机绑定和监听器表达式的类型检查和语言支持。

在下面的 GIF 中,您可以看到这个功能的效果。我们首先得到一个错误,因为我们调用了一个名为 getAppTile 的函数,而不是 getAppTitle。一旦我们修复了这个问题,语言服务就会检测到程序没有进行类型检查,因为我们向一个不需要任何参数的函数传递了参数。

要启用此功能,请将 typeCheckHostBindings 属性在 tsconfig.json 中的 angularCompilerOptions 设置为 true。我们将在 Angular v21 中默认启用此功能。

Angular DevTools 中的增量水合

为了简化增量水合和可延迟视图的调试,您现在可以直接在 Angular DevTools 中预览它们!

下面的屏幕截图显示了如何检查 defer 块及其随后加载的内容。

当使用 defer 块与增量水合时,您还会看到图标指示 Angular 是否已水合当前组件。

对 vitest 的实验性支持

随着 Karma 的弃用,我们与测试框架作者合作,寻找一个维护良好的替代品,以实现浏览器测试。我们提交了一个拉取请求,为我们创建了一个实验性沙盒,以便尝试不同的测试运行器。

在 v20 版本中,Angular CLI 带来了实验性的 vitest 支持,包括监视模式和浏览器测试!

要在 node 环境中尝试使用 vitest,请在您的项目中运行:

代码语言:javascript
复制
npm i vitest jsdom --save-dev

之后,请更新您的测试配置文件 angular.json:

代码语言:javascript
复制
"test": {
    "builder": "@angular/build:unit-test",
    "options": {
        "tsConfig": "tsconfig.spec.json",
        "buildTarget": "::development",
        "runner": "vitest"
    }
}

接下来,您可能需要更新您的单元测试文件以包含正确的导入:

代码语言:javascript
复制
...
import { describe, beforeEach, it, expect } from 'vitest';
...

最后,使用 vitest 运行您的单元测试 ng test。

Angular Material 中的生活质量改进

在本次版本中,我们进一步打磨了按钮组件,以更好地符合 M3 规范。

语音按钮

几项变更:

  • 实现了音调按钮
  • 与 M3 规范对齐术语
  • 添加了设置按钮默认外观的能力
  • 为图标按钮添加了 matIconButton 选择器,以保持一致性。

我们实施的一些质量改进包括:

  • 为对话框添加了新的 closePredicate,用于关闭带有 108 👍 的 请求 。
  • 新的覆盖 API,以实现更好的摇树优化
  • 现在自动处理 prefers-reduced-motion 自动
  • 新的 DI 令牌以 禁用 动画
  • 将 MatButton 和 MatAnchor 合并,以便用户无需导入两者。

支持使用 GenAI 的开发者

为了启用 LLMs 生成现代 Angular 代码并让您能够使用 GenAI 构建应用程序,我们启动了两个项目

  • 维护一个 llms.txt 文件(见 GitHub 上的 pull request),帮助大型语言模型发现最新的 Angular 文档和代码示例
  • 为使用 GenAI 构建应用程序的开发者提供起点

一些语言模型仍然使用结构化指令而不是最新的控制流来生成旧的 Angular 语法,或者使用 NgModules 而不是独立的组件、指令和管道。解决这个问题是一个多步骤的过程,我们首先创建了一个 llms.txt 文件。未来,我们将继续提供使用最新 Angular 语法的代码示例,并探索开发系统提示,提示LLMs使用正确的 API。

我们开始的第二个努力是为构建具有 AI 功能的 API 的开发者提供指南。我们进行了多次直播 ,展示了如何在 Angular 应用程序中利用 Genkit 和 Vertex AI。我们开源了示例应用程序 ,并在 angular.dev/ai 上列出了一些我们发现的最佳实践。

这只是让 Angular 成为您代理 AI 应用程序解决方案的开始。

弃用 NgIf、NgFor 和 NgSwitch

我们在 v17 版本中引入了 Angular 的内置控制流,以带来一系列改进:

  • 更直观的语法,更接近 JavaScript
  • 使用更简单,无需导入其他模块或单独的指令
  • 通过更新 diff 算法提升性能
  • 通过类型缩小改进类型检查

我们还发布了一个 schematic,只需一行代码即可将您的项目从结构化指令迁移到内置控制流:

代码语言:javascript
复制
ng generate @angular/core:control-flow

目前,HTTP Archive 公共数据集中超过一半的 Angular v17+ 应用程序都使用了新的语法!

根据社区情绪和采用度指标,我们将继续弃用 *ngIf、*ngFor 和 *ngSwitch,并鼓励大家使用最新的内置控制流。这意味着根据我们的弃用政策,我们可以在一年后的版本 22 中移除结构化指令。

官方 Angular 吉祥物

随着 Angular 的持续发展和演变,我们非常高兴地宣布一项新的举措,这将进一步丰富我们出色的社区:创建官方 Angular 吉祥物!虽然 Angular 是一个广为人知且广泛使用的框架,但它一直缺少一个像其他许多成功的开源项目那样有趣、视觉化的代表。我们听到了大家的请求,希望有一个可以与之联系的具体物品,比如毛绒玩具或钥匙扣,我们很高兴与大家一起踏上这个充满创意的旅程。我们的团队与 Dart 和 Firebase 吉祥物的设计师合作,分享 Angular 的核心优势和社区精神。这个过程导致了三个初始吉祥物提案,我们迫不及待地要与大家分享。

现在,轮到您,Angular 社区成员,发挥作用了!遵循 Angular 的包容性和社区驱动决策的价值,我们正在向所有人开放这一过程。在 goo.gle/angular-mascot-rfc 找到官方 Angular 面具 RFC。

这是一瞥初始概念:

“Angular 形状角色”从我们的标志中汲取灵感

聪明而坚韧的“鳐鱼”(比它的真实生活版本可爱多了!)

鲸鱼的一种变体。

我们邀请您查看完整的 RFC,为这些提案中的一项投票,提出改进意见,甚至提出名称建议。您的反馈对塑造 Angular 的功能至关重要,我们很高兴看到同样的协作精神定义我们的未来吉祥物。让我们共同努力创造一些真正特别的东西!

感谢大家的所有贡献!

全世界有成千上万的库作者、会议和聚会组织者、教育工作者以及其他通过 Angular 推动网络发展的人!没有你们,我们不可能取得今天的成就。

自 v19 发布以来,我们收到了来自框架、组件和 CLI 的 225 多人的提交并合并了它们!您所做出的每一个改变都帮助我们使 Angular 变得更好。我想强调一些我们从社区成员那里获得的功能:

谢谢大家 🙏

展望未来!

作为 v20 的一部分,我们在过去几年中启动的众多大型努力中,如响应性、无区域、增量激活、框架和表单 API 等方面,都进行了大量的打磨。我们还为即将到来的进步如无选择器、信号表单、单元测试以及官方 Angular 吉祥物等初步绘制了高层次的草图!

我们正在为你们构建 Angular,你们的反馈对我们推进这些倡议至关重要。随着我们对这些重大项目的整体计划逐渐成形,我们将分享更新和征求评论。在此之前,请确保分享你对未来官方 Angular 面具的想法!我们非常期待找到一个能够象征 Angular 产品和价值观的标识。让我们知道你对 RFC 中的概念的看法!

下次再见,感谢你们成为 Angular 旅程的一部分 🙏

本文系外文翻译,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 将响应式功能提升为稳定版
  • 新增实验性 API
  • 将无区域功能提升为开发者预览版
  • 在服务器上巩固 Angular
  • 精炼开发者体验
    • Chrome DevTools 中的性能洞察
    • 框架新增和改进
    • 扩展模板表达式语法
    • 扩展诊断
    • 风格指南更新
    • 改进的宿主绑定
    • Angular DevTools 中的增量水合
    • 对 vitest 的实验性支持
    • Angular Material 中的生活质量改进
    • 支持使用 GenAI 的开发者
  • 弃用 NgIf、NgFor 和 NgSwitch
  • 官方 Angular 吉祥物
  • 感谢大家的所有贡献!
  • 展望未来!
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档