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 {
// 공유 로직을 여기에 작성합니다.
}
타입 전용 import 사용
TypeScript 타입만 필요하다면 import type을 사용하세요.
import type {Parent} from './parent';
타입 전용 import는 컴파일 시 제거되므로 런타임 순환 의존성을 만들지 않습니다.
컴포넌트 계층 재구성
순환 의존성이 설계 문제를 나타내는지 검토하세요. 공통 기능을 세 번째 컴포넌트나 서비스로 추출하는 것이 가장 깔끔한 해결책인 경우가 많습니다.
복잡한 순환 의존성 디버깅
모듈이 많은 복잡한 애플리케이션에서는 순환 의존성을 직접 찾기 어려울 수 있습니다. madge 같은 도구로 순환 import를 시각화하고 감지하는 방법을 고려하세요.
# madge 설치
npm install -g madge
# 순환 의존성 확인
madge --circular --extensions ts ./src
# 시각적인 그래프 생성
madge --circular --extensions ts --image graph.svg ./src
이 도구들은 프로젝트 전체의 순환 의존성 연결을 찾아 시각적인 의존성 그래프를 생성하는 데 도움이 됩니다.