百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

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

ccwgpt 2024-09-20 13:05 19 浏览 0 评论

作者 | Minko Gechev

译者 | 张卫滨

策划 | 张卫滨

在过去的一年间,我们移除了 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): 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



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

  • 只有一行信息对应开发人员编写的代码。其他的都来源于第三方依赖(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): 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 的组件发布稳定版

我们很高兴地宣布,基于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 生成逻辑的异同比较

相关推荐

团队管理“布阵术”:3招让你的团队战斗力爆表!

为何古代军队能够以一当十?为何现代企业有的团队高效似“特种部队”,有的却松散若“游击队”?**答案正隐匿于“布阵术”之中!**今时今日,让我们从古代兵法里萃取3个核心要义,助您塑造一支战斗力爆棚的...

知情人士回应字节大模型团队架构调整

【知情人士回应字节大模型团队架构调整】财联社2月21日电,针对原谷歌DeepMind副总裁吴永辉加入字节跳动后引发的团队调整问题,知情人士回应称:吴永辉博士主要负责AI基础研究探索工作,偏基础研究;A...

豆包大模型团队开源RLHF框架,训练吞吐量最高提升20倍

强化学习(RL)对大模型复杂推理能力提升有关键作用,但其复杂的计算流程对训练和部署也带来了巨大挑战。近日,字节跳动豆包大模型团队与香港大学联合提出HybridFlow。这是一个灵活高效的RL/RL...

创业团队如何设计股权架构及分配(创业团队如何设计股权架构及分配方案)

创业团队的股权架构设计,决定了公司在随后发展中呈现出的股权布局。如果最初的股权架构就存在先天不足,公司就很难顺利、稳定地成长起来。因此,创业之初,对股权设计应慎之又慎,避免留下巨大隐患和风险。两个人如...

消息称吴永辉入职后引发字节大模型团队架构大调整

2月21日,有消息称前谷歌大佬吴永辉加入字节跳动,并担任大模型团队Seed基础研究负责人后,引发了字节跳动大模型团队架构大调整。多名原本向朱文佳汇报的算法和技术负责人开始转向吴永辉汇报。简单来说,就是...

31页组织效能提升模型,经营管理团队搭建框架与权责定位

分享职场干货,提升能力!为职场精英打造个人知识体系,升职加薪!31页组织效能提升模型如何拿到分享的源文件:请您关注本头条号,然后私信本头条号“文米”2个字,按照操作流程,专人负责发送源文件给您。...

异形柱结构(异形柱结构技术规程)

下列关于混凝土异形柱结构设计的说法,其中何项正确?(A)混凝土异形柱框架结构可用于所有非抗震和抗震设防地区的一般居住建筑。(B)抗震设防烈度为6度时,对标准设防类(丙类)采用异形柱结构的建筑可不进行地...

职场干货:金字塔原理(金字塔原理实战篇)

金字塔原理的适用范围:金字塔原理适用于所有需要构建清晰逻辑框架的文章。第一篇:表达的逻辑。如何利用金字塔原理构建基本的金字塔结构受众(包括读者、听众、观众或学员)最容易理解的顺序:先了解主要的、抽象的...

底部剪力法(底部剪力法的基本原理)

某四层钢筋混凝土框架结构,计算简图如图1所示。抗震设防类别为丙类,抗震设防烈度为8度(0.2g),Ⅱ类场地,设计地震分组为第一组,第一自振周期T1=0.55s。一至四层的楼层侧向刚度依次为:K1=1...

结构等效重力荷载代表值(等效重力荷载系数)

某五层钢筋混凝土框架结构办公楼,房屋高度25.45m。抗震设防烈度8度,设防类别丙类,设计基本地震加速度0.2g,设计地震分组第二组,场地类别为Ⅱ类,混凝土强度等级C30。该结构平面和竖向均规则。假定...

体系结构已成昭告后世善莫大焉(体系构架是什么意思)

实践先行也理论已初步完成框架结构留余后人后世子孙俗话说前人栽树后人乘凉在夏商周大明大清民国共和前人栽树下吾之辈已完成结构体系又俗话说青出于蓝而胜于蓝各个时期任务不同吾辈探索框架结构体系经历有限肯定发展...

框架柱抗震构造要求(框架柱抗震设计)

某现浇钢筋混凝土框架-剪力墙结构高层办公楼,抗震设防烈度为8度(0.2g),场地类别为Ⅱ类,抗震等级:框架二级,剪力墙一级,混凝土强度等级:框架柱及剪力墙C50,框架梁及楼板C35,纵向钢筋及箍筋均采...

梁的刚度、挠度控制(钢梁挠度过大会引起什么原因)

某办公楼为现浇钢筋混凝土框架结构,r0=1.0,混凝土强度等级C35,纵向钢筋采用HRB400,箍筋采用HPB300。其二层(中间楼层)的局部平面图和次梁L-1的计算简图如图1~3(Z)所示,其中,K...

死要面子!有钱做大玻璃窗,却没有钱做“柱和梁”,不怕房塌吗?

活久见,有钱做2层落地大玻璃窗,却没有钱做“柱子和圈梁”,这样的农村自建房,安全吗?最近刷到个魔幻施工现场,如下图,这栋5开间的农村自建房,居然做了2个全景落地窗仔细观察,这2个落地窗还是飘窗,为了追...

不是承重墙,物业也不让拆?话说装修就一定要拆墙才行么

最近发现好多朋友装修时总想拆墙“爆改”空间,别以为只要避开承重墙就能随便砸!我家楼上邻居去年装修,拆了阳台矮墙想扩客厅,结果物业直接上门叫停。后来才知道,这种配重墙拆了会让阳台承重失衡,整栋楼都可能变...

取消回复欢迎 发表评论: