Skip to content

Angular 9 正式发布:Ivy 引擎带来的性能革命

Angular 9 于 2020 年 2 月 6 日正式发布,Ivy 渲染引擎成为默认选项。升级了一批内部项目后,来分享真实的体积变化数据和踩坑经验。

实际体积变化数据

官方数据有时过于乐观,这是我们内部几个项目升级后的实测结果:

项目规模升级前 main.js升级后 main.js减少
小型(20 组件)187KB131KB30%
中型(80 组件)412KB268KB35%
大型(200+ 组件)891KB671KB25%

大型项目减少比例相对小,因为业务代码占比更高,框架代码的 tree-shaking 收益被稀释。

升级步骤

bash
# 一键升级(推荐)
ng update @angular/core@9 @angular/cli@9

# CLI 会自动:
# 1. 更新 package.json 依赖版本
# 2. 运行 migration schematic(处理 ViewChild static、字符串 loadChildren 等)
# 3. 运行 ngcc 编译第三方库

升级后常见问题排查

1. ExpressionChangedAfterItHasBeenCheckedError 增多

Ivy 的变更检测更严格。常见原因是在 ngAfterViewInit 里修改了父组件绑定的值:

typescript
// ❌ 触发错误
ngAfterViewInit() {
  this.title = 'loaded'; // 父组件模板绑定了 title
}

// ✅ 用 setTimeout 或 ChangeDetectorRef 解决
constructor(private cdr: ChangeDetectorRef) {}
ngAfterViewInit() {
  setTimeout(() => {
    this.title = 'loaded';
    this.cdr.detectChanges();
  });
}

2. 第三方组件库样式异常

Ivy 改变了组件样式封装的实现方式,某些依赖 .mat-xxx 等全局类的样式写法可能失效:

scss
// ❌ 在宿主组件样式里穿透子组件(Ivy 下可能不生效)
:host ::ng-deep .mat-input-element {
  color: red;
}

// ✅ 在全局样式(styles.scss)里覆盖
.my-custom-input .mat-input-element {
  color: red;
}

3. 动态组件创建 API 变化

typescript
// View Engine 方式(仍兼容但不推荐)
const factory = this.resolver.resolveComponentFactory(MyComponent);
this.container.createComponent(factory);

// Ivy 推荐方式(Angular 9+ 支持)
this.container.createComponent(MyComponent);

新增的 providedIn 选项

typescript
// Angular 9 新增 'any' 和 'platform' 选项
@Injectable({ providedIn: 'any' })
// 'any': 每个懒加载模块获得独立实例,根模块共享一个实例

@Injectable({ providedIn: 'platform' })
// 'platform': 多个 Angular 应用之间共享同一实例(微前端场景)

TestBed 性能提升

Angular 9 的 TestBed 在 Ivy 下不再每次都重新编译组件,测试套件运行速度显著提升:

typescript
// 不变的测试代码,但执行速度快了 2-3x
describe("UserComponent", () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [UserComponent],
    }).compileComponents();
  });
  // ...
});

总结

Angular 9 是近年来对开发者最友好的大版本升级——绝大多数项目可以无痛升级,体积和性能都有实质改善。如果你还在 Angular 8 上,现在就是升级的好时机。

MIT Licensed