余白

https://blog.lacolaco.net/ に移転しました

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

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

github.com


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

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

現状の問題

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

f:id:lacolaco:20180301145501p:plain

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

新しいアプローチ

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

f:id:lacolaco:20180301145857p:plain

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

f:id:lacolaco:20180301150137p:plain

何が嬉しいか

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

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

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