追記: 最新では scope
が providedIn
に変わってます。
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
相当の場合はそのままで、useFactory
やuseValue
相当の場合はファクトリ関数を同時に設定できます。
このようにすることで、NgModuleから参照される側だったInjectableが、NgModuleを参照する側になります。 つまり、そのInjectableを参照するComponentや他のInjectableが存在しなければ、どこからも参照されずTree-Shaking可能になります。
何が嬉しいか
言わずもがな、使われていないサービスのぶんだけバンドルサイズを削減できる点が最大の利点です。
アプリケーションコード中には作成して使われないサービスというのは少ないと思いますが、
たとえば BrosersModule
やCommonModule
、あるいはAngular MaterialのNgModuleなどにprovidersとして登録されているサービスがTree-Shaking可能になれば、
アプリケーションから参照している部分だけのコードをバンドルに含められるようになります。
また、アプリケーションコードにおいてもAppModuleに溢れかえる大量のproviders地獄を解決できるかもしれません。
かならず対応する必要はありませんが、シビアなバンドルサイズを要求されるプロダクトにとっては嬉しい新機能となるでしょう。