深入理解 Angular 12

2025-06-08

深入理解 Angular 12

在本文中,我将详细介绍这个全新版本中(几乎)所有值得关注的内容。我还会重点介绍 Angular 的变更,就像我之前关于Angular 11Angular 10 的文章中所做的那样。

如果您只是想了解一下大致情况,请查看官方发布公告。在这里,我将更深入地介绍发布说明。

加入常春藤联盟...

Angular 团队自 2018 年以来一直致力于Ivy(新的编译和渲染管道)的开发。它最终随 Angular 8 一起发布。自 Angular 9 以来,Ivy 已成为新项目的默认引擎,生态系统正在慢慢迁移到它。从 Angular 12 开始,旧的视图引擎现已正式弃用。它将在未来的主要版本中被移除。此外,将无法使用视图引擎创建新的应用程序。最终,Ivy 已成为新库项目的默认引擎。

目前,由于ngccAngular 的兼容性编译器,库作者仍然可以依赖 View Engine,但现在是时候评估是否可以将库迁移到 Ivy 了。几周前,Minko Gechev 发表了一篇文章详细解释了这一点。另外,请查看相关的RFC

如果你不知道,ngcc它是在创建 Angular 项目或安装依赖项后运行的小进程。当你看到类似的消息时Compiling ... : es2015 as esm2015,它正在ngcc执行其工作。它ngcc的作用是编译依赖于 View Engine 的库,以便 Ivy 可以使用它们。

你可能和我一样,已经注意到这ngcc需要花费大量时间执行,并且会对开发者体验产生非常负面的影响。这就是为什么 Angular 生态系统必须尽快迁移到 Ivy。其次,在生态系统的大多数成员迁移之前,Angular 团队必须保留 View Engine,这会带来很多问题。最后但同样重要的是,依赖于 View Engine 的库不能依赖于 Ivy 的库。

库作者可能无法快速迁移到 Ivy,但他们应该明确敦促那些不愿升级的用户升级。无论如何,前进的道路是尽快将所有内容迁移到 Ivy ;-)

附注:如果您不熟悉 Angular 的内部结构,请观看以下视频。

Kara Erickson 解释 Angular 的工作原理:

Alex Rickabaugh 深入探究 Angular 编译器:

那里还有一篇关于 Ivy 的精彩文章

再见量角器

今年 4 月,Angular 团队宣布计划在 2022 年底终止对Protractor的支持。

从 Angular 12 开始,Protractor 将不再默认包含在新项目中。相反,Angular CLI 将提供使用其他解决方案的选项,例如CypressWebdriverIOTestCafe。这意味着该ng e2e命令将来应该会继续受到支持。

正如公告中所解释的,早在 2013 年 Protractor 创建之时,WebDriver还不是标准,端到端 (e2e) 测试很难编写,维护起来更是噩梦。Protractor 通过包装selenium-webdriver带来了创新的解决方案,并提供了一种控制执行流程的方法。

当然,从那时起,很多事情都发生了变化。我们现在有了WebDriverAPI,async甚至await还有顶级 API await,哇哦。此外,生态系统也在不断发展。像CypressPlaywrightPuppeteer这样的解决方案已经获得了巨大的(当之无愧的)人气。例如,像 Cypress 这样的工具提供了比 Protractor 更好的开发者体验,利用了现代标准,甚至支持跨浏览器测试(以及其他强大的功能)。当前事实上的端到端测试工具的另一个好处是它们与框架无关,这非常有价值。

长话短说,维护 Protractor 对 Angular 团队来说意义不大。现在改进 Protractor 需要投入太多精力,而且会带来大量破坏性的变化。你可以在 RFC 中找到更多详细信息,值得一读。

对于投入大量时间和精力使用 Protractor 编写端到端测试的团队/项目来说,时间表至关重要。Angular 团队仍在忙于评估通过 RFC 收集到的反馈,因此我们可能会在今年晚些时候获得更多信息。

无论如何,如果你还没试过 Cypress,那就试试吧,你不会失望的!顺便说一句,我一直推荐大家开始使用Nrwl NX,这是一个很棒的解决方案,它支持 Angular、React、Next.js、Cypress 等等 ;-)

空值合并

Angular 12 支持在 Angular 模板中使用空值合并运算符。这太棒了!TypeScript从 3.7 版本开始就支持该运算符了

如果你还没听说过这个运算符,我来简单解释一下。它的目的是定义一个后备值,以防出现null或 的情况undefined。以下是一个例子:

let x = foo ?? true;
Enter fullscreen mode Exit fullscreen mode

如果foonullundefined,则将x被设置为true(即后备值),我们可以将其设置为任何我们喜欢的值。

如果没有这个出色的??运算符,我们就必须这样写:

let x = foo !== null && foo !== undefined ? foo : true;
Enter fullscreen mode Exit fullscreen mode

现在 Angular 也支持它了,我们终于可以编写如下表达式:

{{ age ?? calculateAge() }}
Enter fullscreen mode Exit fullscreen mode

而不是使用老旧且冗长的替代方案。太棒了!

您可以在此处了解有关此更改的更多信息。

您可以在TypeScript 手册以及MDN上找到有关空值合并的更多信息

TypeScript 4.2 支持

Angular 12 引入了对TypeScript 4.2 的支持,这意味着我们现在可以使用大量精彩的语言新功能。此外,对 TypeScript 4.0 和 4.1 的支持已被放弃。

以下是 TS 4.2 所包含内容的简要概述:

智能类型别名保存:代码编辑器会显示预期类型,而不是像之前那样显示原始类型。您可以点击此处了解更多信息。

元组类型中的前导/中间剩余元素:现在我们可以在元组中的任何位置包含剩余元素(但有一些注意事项)。对于我们这些偶尔依赖元组的人来说,这非常酷。点击此处了解更多信息。

了解项目结构:TS 4.2 包含一个名为 的新标志--explainFiles,它指示 TypeScript 输出有关程序中包含某个文件的原因的信息。这对于故障排除非常有用。

未调用函数检查的改进:TypeScript 现在可以检测到更多未调用函数的情况。例如,当使用foo而不是 时。更多详细信息和示例可在此处foo()找到

现在可以将解构变量明确标记为未使用let [_first, second] = getValues();,这很棒;noUnusedLocals启用后不会再出现错误!

实际上还有很多其他内容,比如对in操作员更严格的检查,以及一些可能对您造成影响的重大变更。所以请务必查看发行说明

Webpack 5 支持

Angular 11 为我们带来了对 Webpack 5 的实验性支持。借助 Angular 12,Webpack 5 支持现已投入生产。太棒了!

如果你还没看过Webpack 5,你一定会大吃一惊。Webpack 5 于 2020 年 10 月发布,所以现在相当稳定。Webpack 目前是5.37 版本(几天前发布的)。

以下是关于 Webpack 5 变化的简短解释,以及我为什么对此感到高兴 🤩

首先,如您所知,Webpack 是Angular CLI 难题的关键部分,它在捆绑包大小、构建性能等方面发挥着重要作用。

其次,Webpack 5 之所以被称为主要版本,是有原因的。它包含了许多重大变更,这也解释了为什么 Angular 以及生态系统中无数的实用程序/库需要一段时间才能升级。

在发行说明中,Webpack 团队指出 Webpack 5 的重点是:

  • 通过持久缓存提高构建性能
  • 使用更好的算法和默认值改进长期缓存
  • 通过更好的 Tree Shaking 和代码生成来优化 bundle 的大小
  • 提高与 Web 平台的兼容性
  • 清理内部结构
  • 现在引入重大变化(哈哈),让他们尽可能长时间地停留在 v5 上

Webpack 5 最酷的功能是它对模块联合 (Module Federation) 的支持,这为创建微前端提供了必要的基础。这有点超出了本文的讨论范围,但简而言之,模块联合使得不同的构建能够像一个巨大的互联模块图一样运行,并允许我们从远程构建中导入和使用模块。查看官方文档了解更多信息。

如果你很好奇,那么你应该看看Manfred Steyer关于这个话题的讨论:

在主要变化中,Webpack 5 删除了所有以前弃用的内容(例如,,,NoEmitOnErrorsPluginModuleConcatenationPluginNamedModulesPlugin以及IgnorePluginBannerPlugin

此外,之前自动注入的 Node.js polyfill 已被移除;这是该版本中最大的变化之一。这些 polyfill 最初允许 Webpack 让我们在浏览器中使用为 Node.js 编写的模块。这很酷,但它有一个主要缺点:捆绑包更大。此外,这些 polyfill 越来越没用,因为要么有与浏览器兼容的库替代品,要么有支持浏览器的特定发行版。从 Webpack 5 开始,由于这些 polyfill 不再自动添加,我们可能会遇到一些意外情况。例如,我们在浏览器中使用为 Node.js 编写的模块时,可能会没有意识到它之前是通过 Webpack 运行的。您可以在此处了解更多信息。

Webpack 5 引入了对长期缓存的更好支持。在生产模式下,它现在默认包含新的算法:

  • chunkIds: "deterministic"
  • moduleIds: "deterministic"
  • mangleExports: "deterministic"

正如值所示,这些算法为块和模块分配确定性 ID,为导出分配确定性名称。

Webpack 5 能够通过跟踪对导出嵌套属性的访问来执行嵌套摇树优化(欢迎使用 Matrix),这将进一步改进摇树优化。此外,它现在还可以分析模块导出和导入之间的依赖关系。CommonJS摇树优化也得到了改进。此外,还有大量其他优化

Webpack 5 还包含许多改进,以提升开发者体验。例如,开发模式下默认启用了一个新的命名块 ID 算法target。该算法为块提供了易于理解的名称。该属性也得到了显著改进

说实话,我这里没有足够的空间来涵盖 Webpack 5 的所有新功能,内容实在太多 所以我就此打住;-)

如果您只是通过 Angular CLI 间接使用 Webpack,那么大部分内容对您来说应该是“透明的”。但是,如果您在项目中使用自定义 Webpack 构建,那么您可能应该查看迁移指南

最后,如果您对 Webpack 的下一步发展感到好奇,请查看2021 年的路线图,当然还有最新的发行说明

IE11 支持已弃用

虽然听起来可能有点令人难过(我在骗谁呢?😂),Angular 12 即将弃用 IE11。对于我们大多数人来说,Internet Explorer 已经过时了,但不幸的是,许多组织仍在生产环境中使用它。因此,Angular 13 将移除对 IE 11 的支持,这意味着这些组织真的需要开始放弃 IE(无论如何,这都是件好事)。别再找借口了!;-)

一旦 IE 支持消失,Angular 将变得更小、更快,从而对我们所有人来说都更好。此外,一旦维护与旧版浏览器向后兼容的负担消失(IE11 是最后一个!),Angular 将能够利用现代 API(例如CSS 变量交叉观察器CSS 网格代理Web 动画等等

我真的等不及 IE 支持消失!

默认严格

是是是🤩。从 Angular 12 开始,Angular 的严格模式在 CLI 中默认启用。这太棒了。

如你所知,我非常支持 TypeScript 的严格模式,也支持 Angular 的严格模式。如果你想了解更多,可以看看我去年写的文章,以及 Minko Gechev解释这一变化的文章

默认生产构建

到目前为止,运行该ng build命令都会创建一个开发版本。从 Angular 12 开始,ng build将默认创建一个生产版本。

希望它能帮助一些团队避免犯下在生产环境中构建和部署开发版本的错误。不过,我担心犯下这种错误的团队仍然会遇到其他问题 ;-)

Sass 对内联样式的支持

Angular 很早就支持 Sass,但目前为止,我们只能在外部样式表中使用 Sass。从 Angular 12 开始,现在可以将 Sass 与内联组件样式(即在styles属性内)一起使用。

这需要通过将新inlineStyleLanguage属性设置为truein来启用angular.json

Tailwind 支持

Tailwind现已获得 Angular 的正式支持。实际上,Angular CLI 在 v11.2 中就已引入了对 Tailwind 的支持。

Tailwind 正忙于接管世界,特别是现在它有一个rad JIT 编译器,并且在 Angular 中内置对它的支持真是太好了。

以前,将 Tailwind 添加到 Angular 项目需要自定义 Webpack 构建。现在不再需要了!现在,添加 Tailwind 非常简单,只需安装包、tailwind.config.js使用 创建文件npx tailwindcss init,并确保启用Tailwind 的 JIT 模式即可。

Http 改进

Angular 12 在其 HTTP 支持方面引入了许多改进。

请求和拦截器的元数据

首先,HttpClient现在可以使用 来存储和检索请求的自定义元数据。这对于 HTTP 拦截器尤其有用。此功能可以通过新的 来使用HttpContext

以前,向拦截器提供上下文非常复杂,但现在会简单得多。现在,提供的不同 HTTP 方法HttpClient包含一个新context: HttpContext选项,我们可以用它来传递一个 map。

Netanel Basal撰写了一篇有关此问题的文章,如果您想了解更多,请查看

在 HttpParams 上附加所有

该类HttpParams现在有了一个新appendAll方法,可以用来轻松地一次添加一组参数:

appendAll(params: {[param: string]: string|string[]}): HttpParams
Enter fullscreen mode Exit fullscreen mode

参数现在可以作为数字和布尔值传递

以前,数字和布尔值不能直接用作 HTTP 参数。我们必须将它们转换为字符串。现在不用了!

HttpStatusCode

Angular 以 const enum 的形式引入了自己的 HTTP 状态代码的人类可读名称列表。

以前,如果我们想要拥有人类可读的名称,就必须引入自己的解决方案。多亏了这个新功能,我们现在可以使用HttpStatusCode

例如:

if (response.status === HttpStatusCode.Ok) {
 ...
}
Enter fullscreen mode Exit fullscreen mode

对于那些在后端和前端都使用 TypeScript 的人来说,这并不是非常有用(因为我们可能已经有了自己的抽象),但如果你的项目只在前端使用 TypeScript/Angular,那么这是一个不错的改进。

XhrFactory

该类XhrFactory已移至其他包。现在,它由angular/common而非公开angular/common/http

请注意,升级中包含了迁移,因此您甚至不会注意到是否运行ng update;-)

路由器变更

Angular 路由器在 Angular 12 中发生了一些变化。

首先,该routerLinkActiveOptions指令已得到增强。现在,我们可以指定是否需要对 URL 的不同部分进行精确匹配,以便将 CSS 类添加到链接。

以前,我们只能要求整个 URL 完全匹配(或不完全匹配):

<a
  routerLink="/products/foo"
  routerLinkActive="highlight-product"
  [routerLinkActiveOptions]="{ exact: true }"
>
  foo
</a>
Enter fullscreen mode Exit fullscreen mode

现在,我们可以为路径、查询参数、矩阵参数和片段提供细粒度的匹配规则:

<a
  routerLink="/products/foo"
  routerLinkActive="highlight-product"
  [routerLinkActiveOptions]="{ paths: 'exact', queryParams: 'subset', matrixParams: 'ignored', fragment: 'ignored' }"
>
  foo
</a>
Enter fullscreen mode Exit fullscreen mode

支持的值有exactignoredsubset,可用于queryParamsmatrixParams。对于路径,您可以传入exactsubset,以及exactignored来表示fragment

请注意,isActive路由器的方法也接受这些新选项。

fragment 可空

到目前为止,ActivatedRouteSnapshot.fragment它还不可为空。Angular 12 中已经改变了这一点。不过不用太担心,ng update我们已经为你做好了准备。

表格

对发出的事件进行更多控制

选项emitEvent已添加到FormGroup和的各种方法中FormArray。得益于此更改,现在可以在更多情况下控制是否需要发出事件。

例如,以前使用 的removeControl方法移除控件时FormGroup,总会触发一个事件。通过此更改,我们现在可以避免此类问题。

emitEvent选项已添加到以下方法中FormGroup

  • addControl
  • removeControl
  • setControl

以及以下方法FormArray

  • push
  • insert
  • removeAt
  • setControl
  • clear

模板驱动表单的最小和最大验证器支持

minAngular 的和验证max现在可以与模板驱动表单一起使用:

<input [(ngModel)]="foo.bar" [min]="min" [max]="42" />
Enter fullscreen mode Exit fullscreen mode

请注意,这是一个重大变化,因为这些变化以前会被忽略。

国际化

Angular 的 i18n 系统随着此版本而发生了变化。

正如公告博客文章中指出的那样,目前有许多遗留的消息 ID 格式正在使用中。这些格式很脆弱,空格、格式模板和 ICU 表达式可能会引发问题。

Angular 12 引入了一种新的规范消息 ID 格式(即,一种格式统领所有格式)。这种格式更具弹性,也更直观。

这种格式将减少应用程序中由于空格变化等原因导致翻译不匹配的不必要的翻译无效和相关的重新翻译成本。

从 v11 开始,新项目会自动配置为使用新的消息 ID,并且现在有工具可以迁移包含现有翻译的现有项目。如果您担心,可以使用该localize-migrate工具迁移您的消息 ID:

ng extract-i18n --format=legacy-migrate
npx localize-migrate --files=*.xlf --map-file=messages.json
Enter fullscreen mode Exit fullscreen mode

您可以在此处找到更多信息

性能改进

此版本带来了许多性能改进。最明显的改进是随着 Webpack 5 的升级而来的,但还有更多:

一些未使用的方法已从 中删除DomAdapter。这很酷,因为它的方法不可摇树,并且包含在所有 Angular 应用程序中,如相应的 PR中所述。

Angular 现在为安全属性访问生成更少的代码;例如对于模板表达式a?.b和新支持的空合并:a ?? b

Angular 编译器现在支持增量编译,即使存在重定向的源文件也是如此。以前,当 TypeScript 对源文件进行重复数据删除时,之前的编译工作无法复用。您可以在此处阅读更多相关信息。

Angular 编译器现在会缓存源文件的文件系统路径。以前,它会反复调用fs.resolve(),非常耗时。

getDirectives功能已得到改进。随着这一变化,ng命名空间也已扩展,包含一个新getDirectiveMetadata实用程序。

还有一些

ng API 改进

我们可以从浏览器开发工具中使用的ng 调试 API已通过 Angular 12 得到改进。

有一个名为 的新函数getDirectiveMetadata,可用于检索有关组件和指令的信息。我认为我们不会经常用到它,但未来的开发工具改进很可能会依赖于它。您可以在这里了解更多信息。

我们还实现了一个名为 的新分析器函数esetProfiler,该函数也已在生产模式下可用。该函数可以在多种场景中调用。例如,它可以用于跟踪模板创建时长、模板更新、生命周期钩子处理等。同样,即将推出的开发工具也将利用此 API,为我们提供更多关于应用程序运行时性能的深入信息。

目前这仍处于实验阶段,但我想我们稍后会听到更多相关信息。我很好奇像 Sentry 这样的工具是否/何时会集成收集此类信息的支持,以便为我们提供有用的性能仪表盘。

新的开发工具

Angular 12 发布几天后,Angular 团队宣布推出适用于 Google Chrome 的全新 Angular Dev Tools。您可以在此处下载。

使用这个全新的浏览器扩展,您可以在开发过程中轻松检查 Angular 应用程序。它支持:

  • 可视化应用程序的结构(即检查组件树)
  • 探索和编辑组件
  • 分析性能

使用嵌入式分析器,我们可以记录变化检测事件,并在事件发生时进行预览。对于每个变化检测周期,我们可以查看其耗时、哪些组件耗时最长,以及该周期是否导致掉帧。

Angular 之前通过Augury项目提供了半官方的开发工具(新工具的基础!),但这些工具与 Ivy 不兼容。所以这对 Angular 社区来说是个好消息!

还有更多...

此版本中还有大量细微变化。以下是简要概述。

APP_INITIALIZER 现在支持 Observables

到目前为止,还无法将 Observables 与 一起使用APP_INITIALIZER。从 Angular 12 开始,我们可以这样做,这将使代码更加简洁!

如果你还不知道 Angular 的这个特性,APP_INITIALIZER它是一个 token,我们可以用它来定义需要在应用程序初始化期间执行的函数。如果该函数是异步的,返回一个Promise或 一个Observable(new :p),那么 Angular 会等待它完成后再启动应用程序。

这一变化非常受欢迎,因为这意味着我们可以使用 RxJS 编写更多代码,而不必“回退”到PromiseAPI。

您可以在此处阅读更多相关信息

运行时控制动画

以前,禁用动画的唯一方法是提供NoopAnimationsModule。从 Angular 12 开始,现在可以根据运行时信息、使用BrowserAnimationModule.withConfig方法并传递disableAnimations布尔属性来禁用动画。

位置服务上的新 historyGo 方法

AngularLocationService现在包含一个historyGo方法,可用于导航至会话历史记录中的特定页面,该页面通过其相对于当前页面的相对位置进行标识。此方法与原生window.history.go方法相对应。查看 MDN获取一些示例。

语言服务改进

语言服务为 IDE 提供有关 Angular 代码的所有有用见解,该服务也在此版本中得到了改进。

在 Angular 12 中,语言服务默认启用(以前需要我们选择加入)。

从 Angular 12 开始,它还将检测是否未启用严格模板类型检查,并建议您启用这些检查

语言服务现在还包含性能跟踪功能,可用于跟踪性能。此功能可以在 VSCode 中启用,具体说明请见此处(不过这还只是相对底层的功能)。

如果您还不了解语言服务,请查看官方文档,或Ninja Squad撰写的精彩博客文章,或此视频介绍

直接从 HTML 模板禁用 lint 规则

Angular 模板编译器现在会跟踪 HTML 注释。

以前,无法从 HTML 模板中禁用 linter 规则,因为 Angular 模板编译器会忽略注释。解决方法是从组件的控制器中禁用整个模板的 linter 规则。得益于此更改,现在可以从模板中更精确地执行此操作:

<!-- eslint-disable-next-line @angular-eslint/template/no-any -->
<span>{{ $any(foo).bar }}</span>
Enter fullscreen mode Exit fullscreen mode

太棒了,代码更简洁!

DatePipe 现在支持 ICU 标准独立星期几

以前,无法使用 DatePipe 将日期格式化为独立的星期几。

由于这一变化,现在支持芬兰日期格式,我相信这对一小部分 Angular 社区来说是个好消息 😉

Injectable 装饰器的 providedIn 字段支持 forwardRef

现在可以在装饰器领域forwardRef内使用providedIn@Injectable

ResourceHost 接口上新增了 transformResource 钩子

transformResource接口中添加了一个方法ResourceHost。得益于此,工具现在可以执行诸如引入内联样式预处理器支持等操作。这使得 SASS 能够支持内联样式。

您可以在这里这里了解更多相关信息

可以创建自定义路由器出口实现

到目前为止,创建自定义路由器插座是可能的,但需要经过一些麻烦(即,使用注册自定义插座ChildrenOutletContexts)。

Angular 12为自定义路由器出口提供了更清晰的支持

错误修复

与往常一样,此版本包含大量错误修复。

以下是发行说明的副本:

  • 动画:确保一致的过渡命名空间顺序(#19854)(01cc995
  • 动画:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(e918250
  • 动画:移除根视图时清理 DOM 元素(#41059)(c49b280
  • 动画:允许在阴影 DOM 中的元素上使用动画(#40134)(dad42c8),关闭#25672
  • 动画:移除根视图时清理 DOM 元素(#41001)(a31da48
  • bazel:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(8503246
  • bazel:更新构建工具以适应 rules_nodejs 中的最新更改(#40710)(696f7bc
  • bazel:更新集成测试以使用rules_nodejs@3.1.0#40710)(34de89a
  • bazel:更新 JSON.parse 使用的类型转换(#40710)(2c90391
  • benchpress:更新 JSON.parse 使用的类型转换(#40710)(e721a5d
  • 常见:使用 HttpClient 请求正文为布尔值添加正确的 ContentType( #38924 ) ( #41885 ) ( 922a602 )
  • 常见:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(f2b6fd8
  • 常见:视口滚动条未找到阴影 DOM 内的元素(#41644)(c0f5ba3),关闭#41470
  • 常见:暂时重新导出并弃用XhrFactory#41393)(7dfa446
  • 常见:在根视图被移除时清理位置更改监听器 ( #40867 ) ( 38524c4 ),关闭#31546
  • 常见:允许数字或布尔值作为 http 参数(#40663)(91cdc11),关闭#23856
  • 常见:避免在 NgTemplateOutlet 中改变上下文对象(#40360)(d3705b3),关闭#24515
  • 编译器:在封装样式中保留@page规则(#41915)(3e365ba),关闭#26269
  • 编译器:从规则中剥离作用域选择器@font-face#41815)(2a11cda),关闭#41751
  • 编译器:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(bae8126
  • 编译器:非文字内联模板在部分编译中处理不正确(#41583)(ab257b3
  • 编译器:未在备用命名空间内为 ng-template 生成更新指令(#41669)(2bcbbda),关闭#41308
  • 编译器:避免使用向后跨度解析 EmptyExpr(#41581)(e1a2930
  • 编译器:处理区分大小写的 CSS 自定义属性(#41380)(e112e32),关闭#41364
  • 编译器:在部分组件声明的 JIT 编译期间包含使用的组件(#41353)(ff9470b),关闭#41104 #41318
  • 编译器:支持多个:host-context()选择器(#40494)(07b7af3),关闭#19199
  • 编译器:更新 JSON.parse 使用的类型转换(#40710)(f728490
  • compiler-cli:使用 '' 作为间接模板的源映射 URL(#41973)(7a4d980),关闭#40854
  • 编译器-cli:将链接器公开为 Babel 插件(#41918)(8fdac8f
  • 编译器-cli:在引用发射器中优先使用非别名导出(#41866)(75bb931),关闭#41443 #41277
  • 编译器-cli:允许链接器处理最小化的布尔值(#41747)(1fb6724),关闭#41655
  • compiler-cli:匹配字符串索引部分声明(#41747)(f885750),关闭#41655
  • compiler-cli:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(5b463f4
  • compiler-cli:模板中的自动完成文字类型。(#41456)(#41645)(8b2b5ef
  • 编译器-cli:如果组件没有内联样式,则预处理不会出错(#41602)(a5fe8b9
  • compiler-cli:确保编译器ts.Program正确跟踪(#41291)(deacc74
  • 编译器-cli:防止在增量重新编译中消除默认导入(#41557)(7f16515),关闭#41377
  • compiler-cli:解析rootDirs为绝对路径(#41359)(3e0fda9),关闭#36290
  • compiler-cli:添加useInlining类型检查配置选项(#41043)(09aefd2),关闭#40963
  • 编译器-cli: readConfiguration现有选项应覆盖 tsconfig 中的选项(#40694)(b7c4d07
  • compiler-cli:从节点扩展angularCompilerOptionstsconfig (#40694)(5eb1954),关闭#36715
  • 编译器-cli:更新 ngcc 集成测试以获取 rules_nodejs 中的最新更改(#40710)(d7f5755
  • compiler-cli:更新 JSON.parse 使用的类型转换(#40710)(b75d7cb
  • 核心:不保留动态编译的组件和模块(#42003)(1449c5c),关闭#19997
  • 核心:围绕 ngOnDestroy 生命周期钩子调用分析器(#41969)(e9ddc57
  • 核心: AsyncPipe 现在与 RxJS 7 兼容(#41590)(9759bca
  • 核心:使用表达式绑定处理多个 i18n 属性(#41882)(73c6c64),关闭#41869
  • 核心:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(f9c1f08
  • 核心:使用 TS 4.2 检测已降级的合成构造函数 ( #41305 ) ( 274dc15 ),关闭#41298
  • 核心:切换emitDistinctChangesOnlyDefaultValue到 true(#41121)(7096246
  • 核心:删除重复的 EMPTY_OBJ 常量(#41066)(bf158e7
  • 核心:删除重复的 EMPTY_ARRAY 常量(#40991)(e12d9de
  • 核心:允许更新 EmbeddedViewRef 上下文(#40360)(a3e1719),关闭#24515
  • 核心:使 DefaultIterableDiffer 保持重复项的顺序 ( #23941 ) ( a826926 ),关闭#23815
  • 核心: NgZone 合并选项应该正确触发 onStable (#40540)(22f9e45
  • 元素:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(4f5d094
  • 元素:更新 JSON.parse 使用的类型转换(#40710)(efd4149
  • 表单:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(dc975ba
  • http:超时时完成请求(#39807)(61a0b6d),关闭#26453
  • http:在 XMLHttpRequest 中止事件上发出错误 ( #40767 ) ( 3897265 ),关闭#22324
  • 语言服务:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(9b6198c
  • 语言服务:使用脚本版本进行增量编译(#41475)(78236bf
  • language-service:仅在模板中提供 Angular 属性补全(#41278)(0226a11
  • 语言服务:添加插件选项以强制使用 strictTemplates (#41062)(e9e7c33
  • 语言服务:为 Ivy 和 View Engine 使用单一入口点(#40967)(e986a97
  • localize:将错误放宽为缺少目标的警告(#41944)(35ceed2),关闭#21690
  • localize:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(658ed1f
  • localize:更新 JSON.parse 使用的类型转换(#40710)(4b469c9
  • ngcc:使用 TS 4.2 检测已降级的合成构造函数(#41305)(8d3da56),关闭#41298
  • platform-b​​rowser:如果使用影子 DOM 封装,则防止样式节点的内存泄漏(#42005)(d555555),关闭#36655
  • 平台浏览器:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(ea05cfd
  • 平台浏览器:配置XhrFactory使用BrowserXhr#41313)(e0028e5),关闭#41311
  • 平台浏览器:更新 JSON.parse 使用的类型转换(#40710)(7ecfd2d
  • platform-b​​rowser-dynamic:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(bc45029
  • 平台服务器:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(4b9d4fa
  • 路由器:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(0067edd
  • 路由器:仅当重用策略指示应重新连接时才检索存储的路由(#30263)(a4ff071),关闭#23162
  • 路由器:递归合并空路径匹配(#41584)(1179dc8),关闭#41481
  • 路由器:片段可以为空(#37336)(b555160),关闭#23894 #34197
  • 路由器:更新 JSON.parse 使用的类型转换(#40710)(350dada
  • service-worker:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(6b823d7
  • service-worker:更新 JSON.parse 使用的类型转换(#40710)(4f7ff96
  • 升级:使用 ngMocks 时保留 $interval.flush ( #30229 ) ( 87dc851 )
  • 升级:更新支持的节点版本范围以仅包含 LTS 版本(#41822)(10c4523

顺便问一下,你有没有注意到Ben LeshAsyncPipe已经给它打了补丁,让它兼容 RxJS 6 和 7?是不是很酷? ;-)

重大变更

与往常一样,此版本有许多重大变化。

由于官方发布说明非常清楚,我只是将其复制/粘贴到这里:

  • 最小化的 UMD 包不再包含在分布式 NPM 包中。
  • 动画:现在,移除根视图时,DOM 元素会正确移除。如果您使用 SSR 并使用应用的 HTML 进行渲染,则需要确保在销毁应用之前将 HTML 保存到变量中。测试也可能意外地依赖于旧行为,试图查找之前测试中未移除的元素。如果是这种情况,应更新失败的测试,以确保它们具有正确的设置代码来初始化它们所依赖的元素。
  • common:类的方法PlatformLocation,即onPopStateonHashChange,用于返回void。现在,这些方法返回可调用以删除事件处理程序的函数
  • 通用:该类的方法HttpParams现在接受参数值,string | number | boolean而不是string。如果您在应用程序中扩展了此类,则必须更新方法的签名以反映这些更改
  • 编译器命令行(compiler-cli):链接库不再生成旧版 i18n 消息 ID。任何提供这些消息翻译的下游应用程序都需要使用localize-migrate命令行工具迁移其消息 ID。
  • 核心:Angular 不再支持 Node v10,因此如果您仍在开发环境中使用它,那么现在是时候升级了!
  • core:以前,ng.getDirectives如果给定的 DOM 节点没有与其关联的 Angular 上下文(例如,如果在 Angular 应用之外为 DOM 元素调用函数),该函数会抛出错误。此行为与ng命名空间下的其他调试实用程序不一致,这些实用程序处理这种情况时不会引发异常。现在,ng.getDirectives为此类 DOM 节点调用该函数会导致该函数返回一个空数组 core:切换 defaultemitDistinctChangesOnlyDefaultValue会更改其默认行为,并可能导致某些依赖不正确行为的应用程序失败

emitDistinctChangesOnly标志也已被弃用,并将在未来的主要版本中删除

之前的实现中,QueryList.changes.subscribe每当QueryList重新计算 时都会触发变更。这导致变更通知数量人为地增多,因为重新计算的结果可能QueryList与列表相同。何时QueryList重新计算 是一个实现细节,它不应该成为决定变更事件触发频率的因素。

遗憾的是,直接修复此行为导致太多现有应用程序失败。因此,Angular 将此修复视为破坏性修复,并在@ContentChildren和中引入了一个标志@ViewChildren来控制此行为。

export class QueryCompWithStrictChangeEmitParent {
  @ContentChildren('foo', {
    // This option is the new default with this change.
    emitDistinctChangesOnly: true,
  })
  foos!: QueryList<any>;
}
Enter fullscreen mode Exit fullscreen mode

为了向后兼容,在 v12 之前
emitDistinctChangesOnlyDefaultValue设置为false。此更改
将默认值更改为true

  • 核心:令牌的类型APP_INITIALIZER已更改,以便更准确地反映 Angular 处理的返回值类型。以前,每个初始化器回调的类型都被设置为 return any,现在改为Promise<unknown> | Observable<unknown> | void。万一您的应用程序使用Injector.getTestBed.injectAPI 注入APP_INITIALIZER令牌,您可能需要更新代码以适应更严格的类型。

APP_INITIALIZER
此外,如果该令牌用于表达式中,而表达式的推断类型必须发送到 .d.ts 文件中,则 TypeScript 可能会报告 TS2742 错误
。为了解决这个问题,需要一个显式的类型注释,
通常是ProviderProvider[]

  • core:最低支持zone.js版本为0.11.4。这意味着如果您使用的是旧版本,也是时候升级项目中的 zone.js 了!
  • 形式:emitEvent选项已添加到以下内容FormArrayFormGroup方法中:

  • FormGroup.addControl

  • FormGroup.removeControl

  • FormGroup.setControl

  • FormArray.push

  • FormArray.insert

  • FormArray.removeAt

  • FormArray.setControl

  • FormArray.clear

FormArray如果您的应用程序具有扩展或FormGroup类化并覆盖上述方法的自定义类
,则可能需要更新您的实现以考虑新的选项
并确保从类型角度来看覆盖是兼容的。

  • 表单:之前,在 上定义的min和属性会被 Forms 模块忽略。现在,这些属性的存在将触发最小/最大验证逻辑(如果指令也出现在给定输入框中),并且相应的表单控件状态将反映这一点。max<input type="number">formControlformControlNamengModel
  • 平台浏览器: XhrFactory已从@angular/common/http移至@angular/common


import { XhrFactory } from '@angular/common/http';
Enter fullscreen mode Exit fullscreen mode


import { XhrFactory } from '@angular/common';
Enter fullscreen mode Exit fullscreen mode
  • 路由器:严格的空值检查将报告可能为空的片段。迁移路径:添加空值检查。
  • router:扩展了输入的类型RouterLinkActive.routerLinkActiveOptions,以便进行更精细的控制。之前读取此属性的代码可能需要更新以适应新类型。

更新路线图

根据当前的 Angular路线图,团队目前正忙于以下改进:

  • 提升开发者在调试和分析时的体验。这应该有助于我们理解组件结构(我想象 React Dev Tools 也能支持 React 的组件结构)以及变更检测。
  • 通过自动拆卸功能缩短测试时间和调试时间:这将改善测试与测试时间之间的隔离。TestBed将进行更改,以便在每次测试执行后自动清理和拆卸测试环境。
  • 使用 ES2017+ 作为默认输出:他们将识别障碍并消除这些障碍,以便可以升级默认输出语言
  • 将 MDC Web 集成到 Angular Material 中
  • 提高 Angular Material 组件的可访问性
  • 发布关于高级概念的指南,例如变化检测、性能分析、与 Zone.js 的交互等
  • 更新 e2e 测试策略(参见上文)
  • 准备升级到 RxJS v7+。你可能知道,RxJS 7最近发布了。希望我们很快就能升级到

未来,Angular 团队计划:

  • 研究微前端架构:他们可能会介绍使用 Angular 轻松创建微前端的方法
  • 通过对 Angular 表单进行严格类型化来改善开发人员的体验(我们迫切需要这个)
  • 使 Zone.js 成为可选的,这应该可以简化框架、改善调试、减少包大小,甚至允许利用原生的 async/await 语法
  • 通过将 Angular 编译器 ( ngc) 集成为 TypeScript 编译器插件来提高构建性能
  • 允许向宿主元素添加指令。这也是社区长期以来的呼声!
  • 使 NgModules 成为可选的,以简化学习曲线
  • 为我们提供更简单的方法来实现组件级别的代码拆分

Angular Material 和 Angular CDK

Sass 迁移

在内部,Angular Material 和 CDK 都已迁移到新的 Sass 模块系统

如果您的应用程序使用其中任何一个,那么您需要确保已将其替换node-sasssasshttps://www.npmjs.com/package/sass。该node-sass软件包已不再维护!

通过这次迁移,Sass 主题 API 得到了增强,现在我们可以利用 Sass 的@use实用程序。

现在有一个@angular/material和的单一入口点@angular/cdk

最后,API 也进行了修改,使其更加清晰。许多函数、混合宏和变量均进行了重命名。

您可以在新的主题指南中找到有关这些更改的更多信息:https://github.com/angular/components/blob/master/guides/theming.md。此外,请注意,https://material.angular.io上的指南已重写,以展示新的 API 并包含相关说明。

升级过程会自动将代码迁移到新的 Sass API。您可以在此处查看升级前后的示例

Angular CDK 变更

版本 12对 Angular CDK进行了许多更改。

在这里,我仅列出新功能,但如果您想了解有关错误修复和性能改进的详细信息,可以查看发行说明:

  • 拖放:drop 事件现在包含一个dropPoint属性,用于确定拖放项目时鼠标指向的准确位置。更多信息请点击此处
  • 拖放:现在可以自定义预览容器
  • :新增指令,允许启用“循环视图重复器”,该重复器会缓存已处理的行,并在数据集更改时重新使用它们。这有助于提升性能(减少延迟)。
  • 表格:在界面中添加了粘性元素的偏移量StickyUpdate
  • Stepper:当用户尝试离开某个步骤时,interacted发出一个事件
  • 步进器:现在可以改变方向
  • 可访问性现在可以将FocusOptions对象传递到各种焦点陷阱方法中
  • 测试:新的 WebDriver harness 环境。我还没有深入研究过,所以无法透露更多信息。请查看PR

Angular Material 变更

Angular Material也进行了一些更改。同样,请查看发行说明以获取完整的错误修复列表。

新功能:

  • 日期选择器:不再依赖对话框
  • 步进器:现在可以动态改变方向(参见 CDK 中的类似变化)
  • Stepper:允许延迟渲染内容
  • 菜单:允许以编程方式更新菜单位置
  • Mat 错误:现在使用aria-live="polite"而不是role="alert"。更多详情请见此处
  • 选项卡:添加方法以编程方式将焦点设置在特定选项卡上
  • List:现在返回一个数组,其中包含与selectAlldeselectAll方法中更改的选项。查看PR了解详情
  • 滑动切换:允许通过提供程序全局配置默认颜色
  • 工具提示:现在通过组件上的类公开工具提示的有效位置
  • 单选按钮复选框滑块:在打印样式表中包含这些组件的背景颜色

实验版本上还有许多变化:https://github.com/angular/components/blob/master/CHANGELOG.md#material-experimental

Angular Universal

Angular Universal 12 也刚刚发布

在此版本中,Universal 现在默认内联关键 CSS,这非常酷。

Universal 现在包含一个新proxyConfig选项,可以为构建器提供自定义代理配置ssr-dev-server

在这个版本中,有一个名为Clover的全新(实验性)SSR 引擎(让我想起了 Java 生态系统中的一款质量工具)。这个新引擎看起来很有前景。它旨在简化流程,消除Window is undefined错误,消除 SSR/预渲染的多次构建需求,生成无需额外构建的应用程序外壳等等。我们稍后可能会听到更多关于它的消息。如果您感兴趣,请查看PR

此版本包括一个构建器,可用于使用新的 Universal Clover 方法生成静态页面(即预渲染)。

最后,此版本还包括对开发服务器的TLS 支持。

谷歌地图

众所周知,Angular 包含 Google 地图和 Youtube 的组件。版本 12 为 Google 地图组件带来了一些改进:

  • 现在包含一个icon输入,可以轻松自定义标记
  • 现在,当单击clusterClick集群时会发出事件
  • 包含Google Maps Geocoder API 的包装器MapDirectionsResponse,并导出之前未公开的
  • 引入对渲染热图的支持
  • 添加了MapDirectionsRenderer,允许在地图上呈现方向,以及MapDirectionsService,用于google.maps.DirectionsService计算两点之间的路线
  • 标记聚类器上的新options输入,类似于其他指令

升级

与往常一样,有一个完整的升级指南可供使用,并将ng update为您提供帮助:https://update.angular.io/?l =3&v=11.0-12.0

如果您正在使用Nrwl NX(您真的应该使用),请注意 Nx 12.3 已经包含对 Angular 12 的支持!点击此处了解更多信息。此外,Nx 还可以帮助您从 TSLint 迁移到 ESLint(现在是时候了!)

结论

在本文中,我探讨了 Angular 12 的新功能。

与往常一样,这次发布是英雄之作(还能是什么?!😎)。

Ivy 正在不断进步,希望ngcc随着生态系统的迁移,我们“很快”就能不再为此烦恼。此版本带来了许多精彩的变化,快来查看并升级吧!

今天就到这里!

附言:如果您想了解有关产品/软件/ Web 开发的大量其他有趣的事情,请查看 Dev Concepts 系列订阅我的时事通讯,并在 Twitter 上打招呼

鏂囩珷鏉ユ簮锛�https://dev.to/angular/angular-12-in-deep-1j6m
PREV
Angular + Animate.css 的五个简单步骤
NEXT
在 Angular 中渲染大型列表的 3 种方法框架很快,但你的代码很慢