余白

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

Angular v2からv6までの変化をまとめてみた

rdlaboさんがしっかりGW明けにIonicの記事書いてくれたので、僕もAngularのv2からv6まで、3年弱の変遷についてまとめます。

Ionic 2 から 4 への、この2年間の進化を振り返る

前Angular v2時代

現行Angularの歴史を話し始めるとAngularDart 0.x-1.xからの話になります。 実はAngularDart v1は、停滞したAngularJSの改革をおこなうための、仮説検証の場でした。 僕がAngularDart 0.xから1.xを使って開発していたのが2014年末〜2015年あたりなので、だいたい3年半くらい前の話です。

ここで生まれた基本的な概念は今でもしっかりとAngularに残っています。例えば次のようなもの。

これらはDartの言語機能やWeb Components仕様の整備により実装できた新しいAngularの形で、これをAngularJSの次世代バージョンとして実現するために必要な言語機能の仕様が AtScript として誕生し、これをもとにAngular 2の開発が進められました。

結局その後は紆余曲折ありAtScriptは必要なくTypeScript+デコレータで実現することになりました。

Angular v2

2015年12月に、Angular v2はbeta.0をリリースし、2016年9月14日に2.0.0がリリースされました。

ちゃんと掘り下げると無限に長くなるので、この時期に導入された重要な概念をおさらいするだけに留めます。

オフラインコンパイル

現在ではAngularのAoTコンパイルは当たり前になっていますが、当時はじめて"オフラインコンパイル"というものが発表されたときは困惑しました。 あらためて当時のプロポーザルを見ると、まさにこれって今実装されようとしているngIvyそのものじゃないかと思いました。 これまでのAoTではまだ不十分でしたが、ついに3年越しの成就となろうとしてます。感慨深い。っていうかTobias氏が頭良すぎる。

lacolaco.hatenablog.com

Angular 2 offline template compilation - Google ドキュメント

https://ng2-info.github.io/2016/01/angular2-in-2016/#even-faster-angular-2-tobias

実際にAoTコンパイルが使えるようになったのはrc.2からでした。2016年5月のことなので、ちょうど2年前。ngcちゃんも2歳になりました。

AngularJSへの .component 逆輸入

AngularJSからAngular 2への移行をスムーズにするため、マインドセットを統一するためのAPI逆輸入がおこなわれました。 コンポーネントベースの設計になることで、コンポーネントルーターを起点としたマイグレーションが可能になる、という構想でした。

当時は angular-component-router 自体は失敗しましたが、考え方自体は今のngUpgrade APIと同じなので、やっぱりAngularコアチームは頭良いですね。

Animation API

この頃、Web Animations APIを元にしたAnimation APIを作ることが決まりました。今でもしっかり続いています。

Language Service

テンプレート内でコンポーネントの型情報を元に型チェックや入力補完をおこなう機能の提案がなされたのが実はbeta.5のころです。 実際に実装されて使えるようになったのは2.3リリースの頃ですが、いまでは開発中に無くてはならないものになっています。

https://ng2-info.github.io/2016/02/beta-5-has-released/#template-services-plan

Angular CLIとスタイルガイド

John Papa氏とMinko Gechev氏のふたりが草案を作ったAngular Style Guideは、いまでも公式ドキュメントとしてメンテナンスされつづけています。 そしてAngular CLIではそのスタイルガイドに沿ったコード生成をおこなっています。

SystemJSからwebpackへ

アルファ版のころから続いていたSystemJSベースのセットアップが、webpackベースに変わりました。 v6になった今でもAngular CLIはwebpackを利用していて、Tree Shakingなどいろいろな最適化ができているのでナイスな決断だったといえます。

Forms APIの改革

RCの中でもっとも大きく変わったAPIのひとつがFormsですね。テンプレート駆動フォームと、リアクティブフォームが明確に分割され、選択できるようになりました。 この頃はテンプレート駆動がメインで、リアクティブがオプショナルという立ち位置でしたが、いまやリアクティブがメインで、テンプレート駆動がオプショナルとなりつつあります。 パラダイムの変遷を感じます。

Routerの改革

RCの中でもっとも大きく変わったAPIその2、Routerです。当時はてんやわんやでした。

AngularJS: Improvements Coming for Routing in Angular

Victor Savkin氏により実装されたRouter v3はその形をほとんど変えないまま今のv6まで続いています。 Victor Savkin氏はAngularコアチームの中でもとびきり頭が良い一人ですね。

NgModuleの導入

Angular 2のRCといえばNgModuleというくらい悪名高い破壊的変更です。いまでは当たり前ですが、これも当時は衝撃でした。

https://ng2-info.github.io/2016/07/preparing-for-ngmodule/

v6でも現役な、Angularの根幹のAPIですが、そのあり方は変わろうとしています。詳しくはv6のセクションで述べます。

Custom Elements対応

rc.6で追加されたのが CUSTOM_ELEMENT_SCHEMA です。Angularのテンプレート内でAngularが知らないカスタム要素を使うための機能です。 これによりWeb Components仕様に則って作られたCustom Elementsとの協調が可能となりました。 いまでも現役な重要機能です。

v4

半年後の2017年3月23日にv4.0.0がリリースされました。

AngularJS: Angular, version 2: proprioception-reinforcement

AngularJS: Angular 4.0.0 Now Available

v2.xからv4の中で変わっていったものたちを振り返っていきましょう。

Reactive Angularに向けた変化

この頃からリアクティブプログラミングをサポートするための変更が進み始めます。 *ngIf*ngForasync as 記法で非同期データと値を保持できるようになったのがv4のことです。今ではこれ無しのテンプレートは考えられないです。

<div *ngIf="userList | async as users; else loading">
  <user-profile *ngFor="let user of users; count as count; index as i" [user]="user">
User {{i}} of {{count}}
  </user-profile>
</div>
<ng-template #loading>Loading...</ng-template>

Angular Universalの刷新

ベータ版のころからサードパーティとして続いていたAngular Universalのコア部分をAngularコアチームが回収し、@angular/platform-serverとして再実装しました。 複雑になっていたAPIを整理し、renderModuleだけを提供するシンプルなパッケージに生まれ変わりました。 platform-serverはこの頃と今でもあま変わっていませんが、platform-serverを元にした新しいAngular Universalは独自に進化を続けています。

https://github.com/angular/universal

f:id:lacolaco:20180508103229p:plain

angular.ioのAngular化

v4.2のリリースにあわせて、ようやく公式ドキュメンテーションサイトのangular.ioがAngularで再実装されました。 いまでもコアチームによるAngularのPWA実装の例として活発にメンテナンスされています。

AngularJS: Angular 4.2 Now Available

Animation APIの改革

stagger()group() など複雑なアニメーションを実現するための新しいAPIがv4.2で導入されました。

A New Wave of Animation Features in Angular - yearofmoo.com

HttpClientの導入

@angular/common/http パッケージが公開され、新しいHTTPクライアントが使えるようになったのがv4.3です。

Angular 4.3 Now Available – Angular Blog

v5

v4から半年後、2017年11月2日に2回目のメジャーアップデートであるv5.0.0がリリースされました。

Version 5.0.0 of Angular Now Available – Angular Blog

Build Optimizer

v5の頃から、Angularは機能の追加よりもバンドルサイズの改善に注力する傾向が強まります。 Build Optimizerはwebpackのプラグインとして提供され、Angularのアプリケーションのバンドル時に様々な最適化をおこない、バンドルサイズを削減します。

AngularコンパイラのTypeScript Transformer化

AngularのテンプレートコンパイラがTypeScriptの標準拡張機能に準拠することにより、デコレータのコンパイル処理に介入できるようになりました。 これはテンプレートの最適化をおこなうための足がかりでもあり、テンプレート中の無駄な空白を除去してバンドルサイズを削減することなどが可能になりました。

また、AoTコンパイルの軽量化により、ng serve --aot が可能になったのもこの時です。

さらに、デコレータ内でアロー関数を使ってもAoTコンパイルできるようになったのもv5です。v2から長くやっている方はもしかすると無意識に避けてしまっているのではないでしょうか。

Component({
  provider: [{provide: SOME_TOKEN, useFactory: () => null}]
})
export class MyClass {}

ロケール依存パイプの刷新

v5で最も衝撃の強かった変更はdatenumberなど、ロケールに依存する組み込みパイプの全面刷新です。 それまではWeb標準仕様のI18n APIに準拠して実装されていましたが、バグが多くブラウザ間の実装の差異に悩まされていたため、それをやめてAngular内部にロケールデータを持つことになりました。

https://github.com/angular/angular/blob/master/CHANGELOG.md#i18n-pipes

Zone.js非依存化への歩み

v5では、Angularアプリケーションの実行時にZone.jsを使わない選択肢が選べるようになりました。

platformBrowserDynamic()
  .bootstrapModule(AppModule, {ngZone: 'noop'});

バンドルサイズの軽量化や、エキスパートな開発者による独自のパフォーマンスチューニングを可能にするための機能です。

Angular MaterialとCDK

ついにようやくAngular MaterialがStableになり、そのコアであるComponent Dev Kit(CDK)も公開されました。

Angular 5.1 & More Now Available – Angular Blog

Angular CLIのPWAサポート

Angular CLIがService Workerの生成や、Angular Universalを利用したApp Shellのレンダリングなどをサポートし、Angular for PWAの風が吹いてきました。 v6では ng add @angular/pwa だけでPWA化が済んでしまうほどになりました。

Angular Progressive Web App Guide

v6

そして2018年5月4日、6.0.0がリリースされました。

Version 6 of Angular Now Available – Angular Blog

Angular Elements

v6といえばAngular Elementsです。 まだまだ実験的なAPIではありますが、AngularのコンポーネントをCustom Elements化できる機能が公開されています。

https://angular.io/guide/elements

アプリケーションのためのフレームワークだったAngularから、WWWの世界へ進出していくための大きな一歩です。

Angular CLIの大改革

Angular CLIがv1.7からv6へアップデートし、かなり大きな進化を遂げました。

アプリケーションだけでなくライブラリ開発も可能になり、ng updateコマンドやng addコマンドなど新しい機能もたくさん追加されました。

新しいDI機構

NgModuleの導入以来ずっと変化のなかったDI機能に、新しい仕組みが導入されました。

Tree Shakable Providers と呼ばれる機能により、DIでプロバイドされる@InjectableなクラスをNgModuleのprovidersに渡さなくてもよくなります。 代わりに、@Injectable({providedIn}) という新しいAPIで、自身がプロバイドされるモジュールのスコープを持つようになります。

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class MyService {
  constructor() { }
}

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

https://angular.io/guide/dependency-injection#tree-shakable-providers

静的な参照がNgModuleから消えるため、Tree Shakingによって実際にコンストラクタの型パラメータとして参照されているクラスだけがバンドルに含まれるようになります。

RxJS v6

Angular v6が依存するRxJSのバージョンもv6にアップデートされました。 RxJSのメンテナであるBen Lesh氏もAngularコアチームに入ったことによりスムーズに連携できるようになった印象です。

RxJS v6はTree Shakingサポートによってバンドルサイズを大きく減らすことができるため、Angularにとってもかなり嬉しいアップデートです。


まとめ

結構長くなりました。 v2以前からv6まで変化の流れを追ってみましたが、今あるAngularの機能の大半はv2のころのままですね。 新し目の機能についても構想自体はv2以前からのものもあり、2.0.0以降の変化は主に開発者支援や、バンドルサイズ削減に貢献するものがほとんどだなというのがわかります。

  • v2: フレームワークとしてのAngularの完成
  • v4: フレームワークのブラッシュアップ
  • v5: プラットフォームとしてのAngular: Material, CDK, PWAサポート
  • v6: プラットフォームの拡大: Angular Elements

といった感じでしょうか。

今後もAngularはフレームワークとしてだけでなくプラットフォームやエコシステムとして広がっていくこと間違い無しなので、マクロな視点で見ていくのが大事ですね。