今年の11/12にAngular11が公開されました。
今までずっとAngular5で開発を続けてきており、流石にそろそろアプデしないとなと思い、実際にやってみた所感と、初めて体感したレンダリングエンジンIvyについて書いていきたいと思います。
Angular5→Angular11にアプデした際の体感
Angular5と比較するとページの初期表示までの時間、ルーティングにかかる時間、ngFor等で動的生成されるDOM要素がレンダリングされるまでの時間が圧倒的に早く感じました。 体感的に早く感じたのは、Angular8からレンダリングエンジンがRender2からIvyに変わったことが恐らく大きいのではないかと思っています。
Ivyって何だろう
Angularの第3世代のレンダリングエンジンです。
Angular2~3がRender、Angular4~7がRender2、Angular8~11がIvyというレンダリングエンジンが使われています。
Render2→Ivyに変わったことによる改善点
- 開発者が記述するHTMLテンプレートがDOM要素に変換されるまでの処理がより効率化されたことで、レンダリングの速度が上がった。
- Angular CLIでコンパイル後のソースコードのフォーマットが変わり、可読性が上がった。
- Tree Shakingによりバンドルサイズが小さくなった。
DOM要素生成フローの違い
Render2、Ivy、両者でどのようにDOM要素が生成されているのかを比較してみます。
Render2の場合
- HTMLテンプレートを文字列として解釈し、テンプレートデータ(※)を生成
- テンプレートデータからDOM生成関数を生成
- DOM生成関数を実行し、実際にDOMをレンダリング
Ivyの場合
- HTMLテンプレートからテンプレートインストラクション(※)を生成
- テンプレートインストラクションを実行し、実際にDOMをレンダリング
※テンプレートデータ、テンプレートインストラクションは、いずれもjsで記述されたDOM要素生成の為に必要な情報が記述されたデータを指します。詳しくは次の項で説明します。
Ivyの方が手順が少ないですね。
テンプレートデータ、テンプレートインストラクションという単語が出てきましたが、 では実際にHTMLテンプレートからどのようなソースコードが生成されるのかも比較してみます。
HTMLテンプレートから生成されるコードの違い
Render2の場合
HTMLテンプレート
<div class="container"> Hello, Angular! </div>
コンパイルで生成されるソースコード(テンプレートデータ)
viewDef([ elementDef(0, 'div', ['class', 'container'], null, ...); textDef('Hello, Angular!', ...); ]);
Ivyの場合
HTMLテンプレート
<div class="container"> Hello, Angular! </div>
コンパイルで生成されるソースコード(テンプレートインストラクション)
elementStart(0, 'div', ['class', 'container']); text(1, 'Hello, Angular!', ...); elementEnd();
比較してみると、Renderは専用の関数からHTMLを定義するようなフォーマットである一方、
Ivyの方はHTMLをjsで翻訳したようなフォーマットになっており、可読性が上がっていますね。(div
要素の開始と終了が<div></div>
からelementStart(), elementEnd()
に置き換わっていることが直感的に分かるようになっています)
Render2ではテンプレートデータからさらにDOM生成のための関数を生成するという処理が必要ですが、Ivyはテンプレートインストラクション自体を実行して、DOMを生成します。
「HTML→js→js→DOM」が「HTML→js→DOM」という処理フローに効率化されたという感じでしょうか。 どうせjs同士でごちゃごちゃ処理するなら、いっそまとめてやればよくね?という発想ですね。
効率化と可読性の両方を満たす良いアップデートだと思います。
Tree Shaking
IvyではTree Shakingすることでバンドルサイズを落としてくれます。 開発者が記述していないコードはバンドルされません。
例えば、Angularにはバインドした変数を特定のフォーマットに変換できる「パイプ」という機能がありますが、テンプレート内でパイプを記述しなければ、パイプに関連する関数はバンドルされなくなります。
余談
実は恥ずかしながらTree Shakingの意味を今まで知らなかったので調べたところ、webpack等でバンドルする際に不要な未使用コードを削ることを指すそうです。 直訳すると「木を揺らす」ですが、そこから転じて「無駄をそぎ落とす」という意味になったらしい。
Wikipediaさんによれば1990年代に動的型付け言語であるLispの中で生まれた概念だそうで、プログラムにおける実行可能なフロー全てを関数呼び出しのtreeに見立てたことからきているとのこと。 https://en.wikipedia.org/wiki/Tree_shaking#:~:text=The%20idea%20of%20a%20%22treeshaker,never%20called%20can%20be%20eliminated.
あとがき
普段の開発では、自分が記述するソースコードにばかり目が向くことが多いのですが、 フレームワークの内側も調べてみることで、プロの方々による効率化の為のアプローチを知ることができますので面白いですね。
個人的にはAngularはReactと比較すると、ソースの記述そのものは冗長気味ですが、開発者の趣向の違いによる記法のブレは少ないように思いますので、負けずに広まっていってほしいなと思っています。 (根っこはjsなので、汚く書こうと思えばいくらでも書けることは書けますが…)