【Angular】`ng build --prod`한 자원을 브라우저로 열면, [Uncaught NullInjectorError: StaticInjectorError(AppModule)[HogeModule -> ParamDecoratorFactory]라고 나왔다.

5033 단어 Angular

환경


  • Angular 8
  • Node.js 12.13.0

  • NullInjectorError는 갑자기



    구현한 화면을 개발 환경에서 실제로 확인하기 위해, 언제나처럼 ng build --prod 하고 S3에 저장. CloudFront의 Create Invalidation을 하고 막상 확인! 라고 생각해 페이지를 열어 보면…
    Uncaught NullInjectorError: StaticInjectorError(AppModule)
    



    이전에도 이 에러가 나온 적이 있었지만, 그 때는 Service 클래스를 CoreModule의 Providers에 추가하지 않았기 때문에 Providers에 추가해 문제는 해결했다.
    이번에도 새로 만든 Service 클래스를 Providers에 추가하는 것을 잊었을까라고 생각해 확인했다.
    하지만 모두 추가되었습니다.
    게다가,
    [CoreModule -> ParamDecoratorFactory]
    

    뭐야 이거… 본 적 없어…

    원인은 Decorator를 작성하는 방법에있었습니다.



    같은 팀의 신 K 씨가 신경이 쓰이는 기사를 발견해 주셨다. (고맙고 고맙습니다… )
    TypeScript - 데코레이터
    아무래도 ParamDecoratorFactory는 데코레이터에 관계 있는 것 같은…?
    데코레이터를 사용하고 있는 개소…? 아….

    이번 프로젝트에서는 디렉토리 구성을 다음과 같이 하고 있었다.
    참고 : How to define a highly scalable folder structure for your Angular project
    app
    ├ core
    │ ├ services
    │ └ core.module.ts
    ├ modules
    │ ├ moduleA
    │ ├ moduleB
    │ └ moduleC
    ├ shared
    │ ├ components
    │ ├ pipes
    │ └ interface
    └ app.module.ts
    

    기본적으로 Service 클래스는 모두 CoreModule에 모여 거기의 Providers에 추가, CoreModule를 AppModule에 import라고 하는 형태를 취하고 있었다.
    게다가 CoreModule가 AppModule 이외에서 불리지 않게, AppModule 이외로부터 불리면 예외를 던지도록 하고 있었다.

    이하 그 설정을 하는 소스 코드↓(이 설정 방법은 비교적 어디서나 쓰고 있는 녀석)

    core.module.ts
    export class CoreModule {
        // CoreModuleのimportはAppModuleのみ。それ以外でimportをすると例外を投げる。
        // @ts-ignore
        constructor(@Optional @SkipSelf parentModule: CoreModule) {
            if (parentModule) {
                throw new Error(`CoreModule is already loaded. Import it in the AppModule only`);
            }
        }
    }
    

    여기서 데코레이터를 사용하고 있지 않은가!
    컴파일 에러로 가르쳐주고 있었는데, 당시의 자신은 여기를 @ts-ignore 를 사용해 망쳐 버리고 있었던 것이다.

    TypeScript에서 데코레이터를 사용할 때는 괄호를 붙일 필요가 있었다.

    그런 이렇게 다음과 같이 수정 (받은)

    core.module.ts
    export class CoreModule {
        // CoreModuleのimportはAppModuleのみ。それ以外でimportをすると例外を投げる。
        constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
            if (parentModule) {
                throw new Error(`CoreModule is already loaded. Import it in the AppModule only`);
            }
        }
    }
    

    이제 다시 Prod 빌드하고 S3에 배포, CloudFront를 괴롭히면 정상적으로 표시되게 되었다.

    요약



    TypeScript에서 Decorator를 사용할 때는 괄호를 잊지 마십시오.

    좋은 웹페이지 즐겨찾기