Experts.jp日本に、もっとエキスパートを。Experts.jp編集長)2017年4月24日0click0170こんにちは、編集長の白石です。ぼくは、自社で運営と開発をしているTechFeedというエンジニア向けニュースアプリにAngular(とIonic)を採用していることもあり、Angularの行方には強く関心を抱いています。一方で、日々の忙しさにかまけてなかなかアップデートを追えていなかったりもします。4.0がリリースされ、ng-conf(アメリカで開催されたAngularのカンファレンス)も終わった今は、Angularの最新情報を得るのに最適な時期!そこで、ng-japanの代表であり、ng-confにも参加されていたlacoさんに、Angularの最新トピックとテクニックについてお聞きしてきました。初心者向けの記事ではありませんが、大変濃くて面白い記事になりました!Angular使いの皆さま、どうぞお楽しみください。あまりにロングなインタビューだったので、さすがに記事分けました。今回の記事は後編です。次に、Angularのモジュールシステムについてもお聞きしたいです。はい、Angularのモジュールは、NgModuleといわれるもので、ECMAScriptのモジュールとは異なります。コンポーネントやサービスなど、Angularの構成要素をひとまとめにしたものです。モジュールと、実は大差ありません。Angularのアプリケーションは、モジュール単位で分割されます。モジュールには二種類あります。ひとつはアプリケーションのルートモジュール。アプリケーションを起動する際に必ず必要となるモジュールです。一つはフィーチャーモジュールといって、他のモジュールにインポートされて利用されることを前提としたモジュールです。サードパーティのライブラリや、アプリケーションを複数モジュールに分割したときなどに、フィーチャーモジュールを作ることになるでしょう。モジュールについてのベストプラクティスとかがあったら教えてください。ライブラリ作者としては、Angular関連のライブラリは、自身をモジュールとして提供するのがベストプラクティスになっています。アプリケーションをモジュールに分割する場合は、任意の単位でモジュールに分けて良いのですが、フィーチャーモジュール同士が依存しあわないような設計にするのがベストです。そのために、モジュール間で共通する処理をまとめた共通(シェアード)モジュールを作るようにして、依存関係を整理するのも重要です。モジュールを分割してルートモジュールを小さくすることで、起動時間も速められるんですよね。した場合は、起動に不要なモジュールは遅延ロードする必要があります。最初からすべてを読み込まないようにすることで、起動を速めるわけですから。遅延ロードはルーティングをベースとしているので、モジュール分割もルーティングの設計と不可分になります。具体的な方法としては、ルーターの設定でloadChildrenに別モジュールのパスを指定することで、自動的にAjaxを使ってモジュールを読み込んでくれます。画面遷移が発生してからモジュールを読み込むとユーザーを待たせてしまうので、遅延ロードするモジュールを先読みしておきたいという場合は、preloadという仕組みも使えます。Savkinという天才がいまして、彼によればもうルーターはほぼ完成の域に達しているそうです。安定しており、今後大きな変更が入ることはないと。それは心強いですね!機能も、APIの安定性も十分ということでしょうか。一つ、ちょっと気になってることがありまして。ぼくらはIonicを使ってアプリ開発を行っているのですが、IonicがなぜかAngularのルーターを使わずに、独自の仕組みになってしまっているんですよね。ルーターがそれほど高機能・高品質なのであれば、なぜIonicがそれを使わなかったのかな、と。Ionicの話なんで「知らない」ってお答えでも全然構わないのですが(笑)。それは、ルーターがDOMを置き換えることを前提に設計されているからだと思います。「トランジション」(遷移)です。IonicはモバイルアプリのようなUXを目指しているので、UIを次々に「スタック」していく。いう「トランジション」と「スタック」という、根本的な設計思想の違いがあるので、Ionicもルーターを活用できなかったのではないでしょうか。いうUIがスタックしていくようなタイプのアプリを作りたい場合は、Angularのルーターの対象範囲から外れてしまっているのかもしれませんね。Ionicだと、代わりDeepLinkerって仕組みが提供されてるんですが、これもあまりイケてるとは言えないので悩ましいんですよね...。AngularJSでは、パフォーマンスについて欠点を指摘されることも多かったように思いますが、現在のAngularではいかがでしょうか?パフォーマンスはかなり向上した、というのが定説ですが。Angular開発者の話だと、「Angularはもう充分に速いので、パフォーマンスについてはもうAngularに任せてくれ」というレベルに達しているそうです。ng-confでも、もうパフォーマンスについては「話にも上がらない」って状態でしたね。「話にも上がらないレベル」ってすごいですね。パフォーマンスについては開発者は何か気をつけておくとか、対策しておくことって必要ないんでしょうか。うーん、OnPushにするのは望ましいっちゃ望ましいのですが、全部のコンポーネントをそうするのは骨が折れますよね。はい、非同期処理終わったらいちいちChangeDetector.markForCheck()するのが面倒で面倒で(笑)。一概にOnPushにするというのも考えものかもしれませんね。デフォルトの変更検知アルゴリズムを使って、あとは「Angularを信じろ」(笑)。いうのもありじゃないかなあとは思います。フレームワーク自体は速いとしても、すべてがAngularで完結するわけではありませんから、Angular以外の部分には注意が必要かもしれません。HTTPによる通信だとか、Zone.jsだとかですね。ああ、Zone.jsとか、結構無茶してますよね(※)。気をつけるべきところありそうな。Angularに管理してほしくない非同期処理は、NgZone.runOutsideAngular()というメソッドで、Zone.jsの管理外で実行できるというのは知っておいていいと思います。スクロールやスワイプなど、小さくて大量に発生するUIイベントとかは、このメソッドを使えば高速化が期待できます。※デフォルトだと、変更検知処理(ChangeDetection)はコンポーネントツリーをすべて走査するが、OnPushを指定したコンポーネント(とそのサブツリー)は、ChangeDetectionの対象から外すことができる。ChangeDetectionは非常に高速なので、通常はデフォルトでよいとされている(参考)。※「Zone.jsとか、結構無茶してますよね」...Zone.jsは、setTimeout()や各種のDOMイベントなどをすべて乗っ取って、複数の非同期処理をまたいだ実行コンテキストを構築する。結局今はNode.js限定になりました。昔コミュニティ主導で作っていた時は違っていたのですが。昔はASP.NET向けの実装とかもあったみたいですよね。はい、でも今は組み込まれていません。以前のUniversalは、風呂敷を広げすぎて追いついてなかったんですよね。今はその反省を活かして、まずは最小限の機能を提供し、拡張についてはコミュニティに任せるという役割分担を目指しています。SSRの使い方は簡単で、@angular/platform-browserの代わりに@angular/platform-serverを使用して、bootstrapModuleFactoryの代わりにrenderModuleFactory()を呼び出すだけです。すると、レンダリング結果を文字列で受け取ることができるので、それをクライアントに返せばいい。