Marginalia

Angular v6で導入されるTree-Shakable DIの紹介

追記: 最新では scopeprovidedIn に変わってます。


Angular v6 では、これまでの Dependency Injection の仕組みを Tree-Shaking 可能にするためのオプション機能を追加します。

概要を説明するために簡単なスライドを作りました。

現状の問題

現在の Dependency Injection の仕組みでは、Injection されるサービス(Injectable)はProviderの登録と、Injectorからの参照の 2 箇所で、静的に参照される必要があります。

たとえどこからも Injection されないサービスでも、Provider を登録する時点で NgModule からの参照が発生するため、ビルド時に不要なコードをふるい落とすTree-Shakingの対象にすることができませんでした。

新しいアプローチ

Angular v6 では、@Injectableデコレータに機能追加をおこない、参照の方向を変更することで Tree-Shaking 可能な Injectable を作成できるようになりました。 次のように@Injectableデコレータの引数に、Injection を解決するスコープとなる NgModule のクラスを指定します。 useClass相当の場合はそのままで、useFactoryuseValue相当の場合はファクトリ関数を同時に設定できます。

このようにすることで、NgModule から参照される側だった Injectable が、NgModule を参照する側になります。 つまり、その Injectable を参照する Component や他の Injectable が存在しなければ、どこからも参照されず Tree-Shaking 可能になります。

何が嬉しいか

言わずもがな、使われていないサービスのぶんだけバンドルサイズを削減できる点が最大の利点です。 アプリケーションコード中には作成して使われないサービスというのは少ないと思いますが、 たとえば BrosersModuleCommonModule、あるいは Angular Material の NgModule などに providers として登録されているサービスが Tree-Shaking 可能になれば、 アプリケーションから参照している部分だけのコードをバンドルに含められるようになります。

また、アプリケーションコードにおいても AppModule に溢れかえる大量の providers 地獄を解決できるかもしれません。

かならず対応する必要はありませんが、シビアなバンドルサイズを要求されるプロダクトにとっては嬉しい新機能となるでしょう。