Angular 偵測到元件、指令或管道之間存在循環依賴。當元件 A 匯入元件 B,而元件 B(直接或間接)匯入元件 A,形成循環時,就會發生此錯誤。
這種循環參照會讓 Angular 無法正確初始化元件,導致像這樣的錯誤:
NG0919: Cannot read @Component metadata. This can indicate a runtime circular dependency in your app that needs to be resolved.
在較舊的 Angular 版本中,你可能會改看到像這樣的錯誤:
Cannot read properties of undefined (reading 'ɵcmp')
常見成因
元件互相匯入
最常見的成因是兩個元件互相匯入:
parent.ts
import {Component} from '@angular/core';
import {Child} from './child';
@Component({
selector: 'app-parent',
imports: [Child],
template: '<app-child/>',
})
export class Parent {}
child.ts
import {Component} from '@angular/core';
import {Parent} from './parent';
@Component({
selector: 'app-child',
imports: [Parent],
template: '<app-parent/>',
})
export class Child {}
間接循環參照
循環依賴也可能透過中間檔案發生:
ComponentA -> ComponentB -> ComponentC -> ComponentA
解決方式
重構共用邏輯
把共用功能移到一個不匯入任一元件的獨立檔案中:
shared.service.ts
import {Service} from '@angular/core';
@Service()
export class SharedService {
// Shared logic here
}
使用僅型別匯入
如果你只需要 TypeScript 的型別,請使用 import type:
import type {Parent} from './parent';
僅型別匯入會在編譯時期被抹除,不會造成執行時期的循環依賴。
重構元件階層
思考循環依賴是否意味著設計上的問題。通常,把共用功能抽出到第三個元件或服務是最乾淨的解法。
為複雜的循環依賴除錯
對於有許多模組的複雜應用程式,手動找出循環依賴可能很困難。可以考慮使用像 madge 這類工具來視覺化並偵測循環匯入:
# Install madge
npm install -g madge
# Check for circular dependencies
madge --circular --extensions ts ./src
# Generate a visual graph
madge --circular --extensions ts --image graph.svg ./src
這些工具可以協助找出整個專案中的循環依賴鏈,並產生視覺化的依賴圖。