0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Angular】`ng build --prod`した資源をブラウザで開いたら、[Uncaught NullInjectorError: StaticInjectorError(AppModule)[HogeModule -> ParamDecoratorFactory]と出てしまった。

Last updated at Posted at 2019-12-20

環境

  • Angular 8
  • Node.js 12.13.0

NullInjectorErrorは突然に

実装した画面を開発環境で実際に確認するべく、いつも通りng build --prodしてS3に格納。CloudFrontのCreate Invalidationをやっていざ確認!と思ってページを開いてみたら…。

Uncaught NullInjectorError: StaticInjectorError(AppModule)

:innocent::innocent::innocent::innocent::innocent:

以前にもこのエラーが出たことがあったが、その時はServiceクラスをCoreModuleのProvidersに追加してないせいだったのでProvidersに追加して問題は解決した。
今回も新しく作成したServiceクラスをProvidersに追加し忘れたかなと思って確認した。
が、全て追加されていた。
しかも、

[CoreModule -> ParamDecoratorFactory]

なんだこれ…見たことない…。

原因はDecoratorの書き方にあった

同じチームの神ことKさんが気になる記事を発見してくださった。(ありがたやありがたや…:clap:)
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使う時は括弧を忘れずにしよう

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?