写点什么

Angular v15 发布:可以脱离 NgModules 构建组件了

Minko Gechev

  • 2023-01-04
    北京
  • 本文字数:5312 字

    阅读完需:约 17 分钟

Angular v15发布:可以脱离 NgModules 构建组件了

在过去的一年间,我们移除了 Angular 的遗留编译器和渲染流水线,这使得我们能够在过去的几个月中开发了一系列针对开发人员体验的改善。Angular v15 是这项工作的高潮,它有几十项改进,可以带来更好的开发人员体验和性能。

 

独立 API 结束开发人员预览阶段

在 v14 中,我们引入了新的独立(standalone)API,它能够让开发人员在不使用 NgModule 的情况下构建应用。我们很高兴地向大家宣布,这些 API 已经从开发人员预览阶段毕业,现在成为了稳定 API 的一部分。从现在开始,我们将会按照语义化版本的方式逐步演进它们。

 

为了确保独立 API 能够毕业,我们的一部分工作就是保证独立组件能够在整个 Angular 中运行,它们现在已经完全可以在 HttpClient、Angular 元素、路由器中运行了。

 

独立 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);
复制代码

 

路由器和 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 的另外一个好处在于它是支持可摇树(tree-shakable)的。打包器可以在构建时移除路由器未使用的特性。在使用新 API 进行的测试中,我们发现从包(bundle)中移除这些未使用的特性后,应用包中路由器代码的大小减少了 11%。

 

指令组合 API

指令组合 API 将代码的重用提升到了一个新的层次。该特性来源于 GitHub 上最受欢迎的一个特性请求,它要求提供向宿主(host)元素添加指令的功能。

 

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

 

我们快速看一个样例:

 

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

 

在上面的代码片段中,我们使用两个指令 HasColor 和 CdkMenu 对 MatMenu 进行了增强。MatMenu 重用了 HasColor 的所有输入、输出和相关的逻辑,以及 CdkMenu 的逻辑和选中的输入。

 

这项技术可能会让你想起其他编程语言中的多重继承或 trait,与之不同的是,我们有一个解决名称冲突的机制,而且适用于用户界面的基础元素。

 

图像指令的功能已经稳定

在 v14.2 中,我们曾经宣布与Chrome Aurora合作开发的 Angular图像指令的开发人员预览版。

 


优化前后的示例应用

 

我们很开心的宣布,图像指令的功能已经稳定。Land's End对这一功能进行了实验,在lighthouse lab测试中观察到 LCP 有 75%的改善。

 

v15 还包含了图像指令的一些新特性:

  • 自动生成 srcset:该指令会为我们生成一个 srcset 属性,确保请求一个大小适当的图像。这可以减少图像的下载时间。

  • 填充模式[实验性的]:该模式使用图像来填充其父容器,从而避免了声明图像的宽度和高度。如果你不知道图像的尺寸,或者想要迁移 CSS 背景图像以使用指令的话,这是一个非常便利的工具。

 

在组件或 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 {}
复制代码

 

要在组件中使用它的话,只需将图像的 scr 属性替换为 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),}
复制代码

 

现在,路由器会寻找一个默认的导出,如果能够找到的话,将会自动使用它,这会简化路由的声明:

 

{  path: 'lazy',  loadComponent: () => import('./lazy-file'),}
复制代码

 

更好的堆栈跟踪

我们从每年的开发者调查中得到了很多的启示,所以我们要感谢你花时间来分享你的想法。深入研究开发人员在调试体验所面临的斗争之后,我们发现错误信息可以进行一些改进。

 


关于调试所面临挑战的反馈

 

我们与 Chrome DevTools 协作来解决这个问题。我们看一个在 Angular 应用中可能得到的堆栈跟踪样例。

 

ERROR Error: Uncaught (in promise): ErrorError    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
复制代码

 

这个片段有两个主要的问题:

  • 只有一行信息对应开发人员编写的代码。其他的都来源于第三方依赖(Angular 框架、Zone.js、RxJS)。

  • 没有任何关于用户交互导致错误的信息。

 

Chrome DevTools 团队创建了一种机制,通过 Angular CLI 标注源码映射(source map)来忽略来自 node_modules 的脚本。我们还合作开发了一个异步堆栈标签 API,它允许我们将独立的、调度的异步任务串联成一个堆栈跟踪。Jia Li将 Zone.js 与异步堆栈标签 API 进行了集成,这使得我们能够提供链接在一起的堆栈跟踪信息。

 

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

 

ERROR Error: Uncaught (in promise): ErrorError    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 的组件发布稳定版

我们很高兴地宣布,基于Material Design Components for Web(MDC)的 Angular material 组件的重构已经完成。这个变化使 Angular 更加符合 Material Design 规范,并使我们能够在最终确定 style token 后立即采用 Material 3。

 

对于许多组件,我们更新了样式和 DOM 结构,还从头重写了一些组件。我们为新组件保留了大多数 TypeScript API 和组件/指令选择器,使其与旧的实现方式完全相同。

 

我们迁移了数以千计的谷歌项目,这使得我们确保外部迁移路径能够顺利进行,并且记录了所有组件的变更清单

 

由于使用了新的 DOM 和 CSS,你可能会发现应用中的一些样式需要调整,尤其是如果你的 CSS 覆盖了已迁移组件的内部元素的样式的话。

 

每个新组件的旧实现均已被废弃,但是依然可以通过“legacy”导入获取它们。比如,通过导入遗留的按钮模块,你可以导入旧的 mat-button 实现。

 

import {MatLegacyButtonModule} from '@angular/material/legacy-button';
复制代码

 

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

 

在幕后,我们将许多组件修改为使用 design token 和 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 语义。

 

实验性 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 上提交issue

 

CLI 的改进

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

 

我们还在简化 ng new 输出。作为第一步,我们通过删除 test.ts、polyfills.ts 和 environments 来减少配置。现在你可以直接在 angular.json 中的 polyfills 区域指定你的 polyfills:

 

"polyfills": [  "zone.js"]
复制代码

 

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

 

功能废弃

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

 

在分析了谷歌的数千个项目后,我们发现了一些很少使用的模式,这些模式在大多数情况下会被滥用。因此,我们废除的 providedIn: 'any'就是这种情况,除了框架内部的一些晦涩情况外,它的用途非常有限。

 

我们也将废弃 providedIn: NgModule。它的用途并不广泛,而且在大多数情况下会导致使用不当,在这种情况下你应该选择 providedIn: 'root'。如果你真的需要将提供者的范围扩大到特定的 NgModule,请使用 NgModule.providers。

 

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

 

未来展望

2020年推出的Ivy实现了很多全面性的改进,你可以发现这些改进已经开始浮现。可选的 NgModules 就是一个很好的样例。它有助于减少初学者需要处理的概念,它同时能够支持高级功能,如通过独立指令实现组合 API。

 

下一步,我们将处理服务器端渲染流水线和反应性的改进,同时带来全面的改进与增强。

 

原文链接:

https://blog.angular.io/angular-v15-is-now-available-df7be7f2f4c8

相关阅读:


AngularJS 进阶 (二十五)requirejs + angular + angular-route 浅谈 HTML5 单页面架构


2023 重学 Angular


谈谈企业级前端 Angular 应用的定制化二次开发话题


SAP UI5 应用和 Angular 应用视图里控件 id 生成逻辑的异同比较

2023-01-04 16:1412520

评论

发布
暂无评论
发现更多内容

数字孪生PaaS平台WDP4.3正式发布!三大升级,让开发更简单

Meta 小元

云原生 智慧城市 数字孪生

共享24小时自助洗车加盟你看好吗

共享电单车厂家

自助洗车 共享洗车 24小时无人洗车 共享自助洗车机

共享自助洗车店加盟需要投资多少

共享电单车厂家

共享自助洗车 自助洗车机 自助洗车

共享洗车机设备多少钱一台?贵不贵

共享电单车厂家

共享洗车机设备 自助洗车机多少钱 自助洗车机价格

科技向善,“以人为本”将掷地有声!

鼎道智联

澳鹏数据标注平台MatrixGo加速人工智能落地

澳鹏Appen

人工智能 数据标注 训练数据

阿里巴巴代码规约检测&Java 代码规约扫描

阿里云云效

阿里巴巴 阿里云 代码扫描 #java 代码规约检测

如何实现一个支持分级数据统计的增强型透视图

明道云

活动报名|3DCAT实时渲染云行业生态合作系列沙龙之“云XR如何赋能虚拟仿真实验教学”线上活动邀您参会

3DCAT实时渲染

虚拟仿真 实时渲染

架构实战营作业一

热猫

架构

加盟24小时共享自助洗车怎么样?

共享电单车厂家

自助洗车机 自助洗车 24小时共享自助洗车 24小时无人自助洗车 自助洗车加盟

CPP进阶:迭代器失效

正向成长

迭代器失效

瞄准程序员招聘痛点,ShowMeBug让面试代码操作可“回放”

ShowMeBug

NFT游戏NFT数字藏品交易系统搭建开发

薇電13242772558

NFT

Flink Next:Beyond Stream Processing

Apache Flink

大数据 flink 编程 流计算 实时计算

代码评审的最佳解决方案

阿里云云效

云计算 阿里云 敏捷开发 代码管理 代码评审

恒源云(GpuShare)_无监督的QG方法

恒源云

自然语言处理 深度学习

USB DDK助你轻松实现HarmonyOS USB驱动开发

HarmonyOS开发者

HarmonyOS 驱动框架

设计模式—代理模式以及动态代理的实现

Linux服务器开发

c++ 设计模式 后端开发 Linux服务器开发 Linux后台开发

fastposter v2.6.2 发布 程序员专属海报生成器

物有本末

Vue 海报 Pillow 海报生成器 电商海报

怎么搭建在线帮助页面

小炮

帮助中心

适创科技以云仿真平台,支持“中国智造”升级

阿里云弹性计算

仿真 高性能计算 EHPC 神龙架构 CAE

全托管云原生 MQTT 消息服务 EMQX Cloud 版本更新,助力开展更加安全灵活的物联网业务

EMQ映云科技

物联网 IoT mqtt emq 3月月更

车载运行小程序,快速打造智慧汽车应用生态

Speedoooo

车联网 物联网 智慧终端 智慧汽车 车载小程序

流动性挖矿APP系统开发介绍模式

Geek_232be3

LIP流动性挖矿

BookKeeper PMC 成员翟佳受邀参与DataFunSummit 大数据存储架构峰会

Apache Pulsar

开源 架构 云原生 bookKeeper Apache Pulsar

NFT元宇宙开发Defi模式NFT游戏开发DAPP

Geek_232be3

区块链 NFT生态链游

流动性挖矿开发模式,方案设计

Geek_232be3

流动性挖矿

利用云效创建代码仓库,免费还方便

阿里云云效

git 云计算 阿里云 代码仓库 Codeup

24小时自助洗车店加盟靠谱吗

共享电单车厂家

自助洗车机 自助洗车 24小时无人自助洗车 自助洗车加盟 24小时自助洗车店

成本管理系统解决方案

低代码小观

企业管理 资产管理 成本优化 低成本 CRM系统

Angular v15发布:可以脱离 NgModules 构建组件了_大前端_InfoQ精选文章