What I learned making an Angular component library work without zone.js
说明与用途
作者维护的 Angular 组件库 LiberaUI 在切换到无 zone.js 的变更检测时出现静默故障:表单控件不再更新,定时器和 Promise 使界面过时,测试也通过了错误的原因。修复方法是在 writeValue 中添加 markForCheck(),用信号替换普通字段,并从测试中移除 detectChanges()。
问题
A small Angular component library (LiberaUI) broke silently under zoneless change detection: form controls stopped updating, timers/promises left UI stale, and tests passed for the wrong reason.
结果
LiberaUI components update correctly under zoneless change detection. Form controls reflect programmatic values, timers/promises update UI, and tests no longer pass for the wrong reason. The author recommends writing these tests before trusting any component library.
工作流
- Add ChangeDetectorRef.markForCheck() to writeValue in every ControlValueAccessor implementation
- Replace plain fields updated by timers/promises with signal state
- Remove fixture.detectChanges() calls from regression tests; use provideZonelessChangeDetection() and await fixture.whenStable()
- Write keyboard and accessibility regression tests dispatching real key events
证据
Without zone.js, control.setValue('x') called writeValue, the field changed, and the input on screen stayed empty. Nothing told Angular the view was dirty, because nothing in a template had triggered the change.
The fix is one line, and it works on every Angular version the library supports: this.changeDetector.markForCheck();
When I first ran them, 8 of 8 form controls failed. That number is the reason I'd recommend writing these tests before you trust a library, including mine.
provideExperimentalZonelessChangeDetection() before Angular 20
- 记录日期: 2026-11-03T21:13:58.489Z