Angular2は「使える」フレームワークか?

こんにちは。pairsの開発を担当している太田です。

去年の12月にAngular2のbetaがリリースされましたね。
Screen Shot 2016-01-12 at 19.59.25

pairsのWebクライアントにはAngular1を使っています。
前々からAngular2は別物になる情報が出ていたので、ある程度覚悟していましたが、実際にbetaに触れてみて、これほんとに完全な別物だから移行じゃなくて再構築と考えるべきだな・・・と感じている次第です。(汗)
思えば、Railsもバージョンアップが激しくてよく追従するのが大変と言われてましたが、Angular2に比べれば全然やさしかったなあと思えます。(遠い目)

とはいえ、少し触ってみたところでは、

  • コンポーネントベースになったおかげで、モジュール分割が明確になり、UIを組み立てやすくなった
  • Web Componentsの仕様が取り入れられていて便利(shadow dom)
  • scopeやDirectiveのDDOなど独特で扱いにくかったものがなくなった
  • TypeScriptベースで実装されているので、コンパイラによるチェック・IDEを通じたコード補完を享受できる
  • RxJSが導入され、非同期処理をより柔軟に扱えるようになった

といった全体的によいフレームワークになっている手応えを感じています。

だからなおさら過去のネガティブイメージである

  • 独特な記法・概念を押し付けられる学習コストが高いフレームワーク
  • やり方がいろいろありすぎて、統一された設計・実装になりにくい
  • DirtyCheckの仕組み上、パフォーマンスに優位性がない

などから離れるために、2を名乗らずに新たなフレームワークとして登場させた方がマーケティング的にはよかったんじゃないか・・・などと余計なお世話を考えてしまいます(Angular1をご利用のみなさんにはわかって頂けるのではないでしょうか?)

ともあれ、Angular1のv1.5では2へ移行しやすくするための変更が取り入れられたりするようです。時間はかかりそうですが、これから移行を検討していくことになると思います。

この記事では、Angular2の概要を理解し、productionでの採用・Angular1アプリからの移行についても考えてみたいと思います。
(※ Angular2の2.0.0-beta.0で動作確認しています)

Angular2をザッと理解してみる

まずAngular2をザッと理解できるような情報を探してみました。

15分で分かったつもりになるAngular 2 概要/angular2
https://speakerdeck.com/kiharu/angular2

angular1脳で見るangular2

これらの資料からこのようなポイントが読み取れました。

  • 1と比較して劇的にスピードアップした
  • Component指向
  • TypeScriptで書かれている
  • データバインディングの記法・考え方が大きく変わった

vs Reactを考えてみる

AngularとReactはクライアントサイドWebで以前から比較されることが多いですが、Angular2になると関係性はどうなるのでしょうか。

Angular 2 versus React: There Will Be Blood
https://medium.freecodecamp.com/angular-2-versus-react-there-will-be-blood-66595faafd51#.kwge4x9vn

この記事では、ReactはJavaScript-Centricで、AngularはHTML-Centricだといっています。

Angular 2 continues to put “JS” into HTML. React puts “HTML” into JS.

これは確かにそうで、ReactではすべてをJSで書き切ることができるのに対して、AngularはHTMLを拡張した独自の記法を使う必要があります。これが学習コストが高いと言われる要因になっていて、Angular2になってもこの特徴は受け継がれています。

Reactにはシンプルさの優位性がありますが、あくまでビューのライブラリに過ぎないので、アプリを構築するための全体構成の設計や、XHR、非同期、pubsubなどの機能を他のライブラリに頼らなければならず、選定とintegrationが必要になります。これはJSエキスパートでなければハードルが高い作業ではないでしょうか。

対してAngularは学習コストが高く、独特な流儀にロックインされますが、その分フレームワークの恩恵によりコード量を少なくできたり、フルスタックフレームワークなので必要な機能はビルトインされているので開発自体に集中しやすいメリットがあります。

結局のところ、対照的なAngularとReactですが、それぞれのポリシー・アプローチの理解と今後の進展のwatchが必要だと思います。

Angular2でサンプルアプリをつくってみる

まずは公式の5 MIN QUICKSTARTをTypeScript版でやってみます。
https://angular.io/docs/ts/latest/quickstart.html
このチュートリアルを通じて、Angular2アプリの起動方法やComponentの作り方の雰囲気が分かります。

さらにこの5 MIN QUICKSTARTの成果物をベースにして、ReactのチュートリアルにあるコメントアプリをAngular2で実装してみます。
Screen Shot 2016-01-10 at 21.37.34
デモ:
http://sohta3.github.io/ng2_comments_sample/
リポジトリ:
https://github.com/sohta3/ng2_comments_sample

コメントアプリはこのような構成になります。
Untitled.png

まずはアプリの起動です。CommentBoxコンポーネントから起動します。

import {bootstrap}    from 'angular2/platform/browser'
import {CommentBox} from './comment_box'

bootstrap(CommentBox);

CommentBoxはindex.htmlに書いておきます。

<br />Loading...

最上位のコンポーネントであるCommentBoxコンポーネントです。
テンプレートで子コンポーネントのCommentListコンポーネントへcommentのリストを渡しています。また、CommentFormコンポーネントから発火されたaddCommentイベントに反応してonAddCommentメソッドを実行します。これは追加されたコメントを表示します。
渡すプロパティは[](カギカッコ)で囲み、受け取るイベントは()で囲むAngular記法になっています。

@Component({
	selector: 'comment-box',
	template: `
            <div class="commentBox ui container">
                <h1>Comments</h1>
                <comment-list [comments]="comments"></comment-list>
                <comment-form (addComment)="onAddComment()"></comment-form>
            </div>
	`,
	directives: [CommentList, CommentForm],
	providers: [CommentService]
})
export class CommentBox implements OnInit {
	comments = [];

	constructor(private _commentService: CommentService) {
	}

	fetchComments() {
		this._commentService.fetchComments().then(comments => this.comments = comments);
	}

	ngOnInit() {
		this.fetchComments();
	}

	onAddComment(params: any) {
		console.log('[CommentBox] onAddComment')
		console.log(params);
		this.fetchComments();
		console.log(this.comments);
	}
}

CommentListコンポーネントです。親コンポーネントから渡されたcommentsをngForで回してCommentItemを生成しています。

@Component({
	selector: 'comment-list',
	template: `
            <div class="commentList ui divided items">
                <comment-item *ngFor="#comment of comments" [comment]="comment"></comment-item>
            </div>
	`,
	directives: [CommentItem]
})
export class CommentList {
	@Input() comments: Comment[];
}

CommentItemコンポーネントです。親から受け取ったcommentの内容を出力します。

@Component({
    selector: 'comment-item',
    template: `
        <div class="commentItem item">
            <div class="content">
                <div class="commentAuthor header">{{ comment.author }}</div>
                <div class="description">{{ comment.text }}</div>
            </div>
        </div>
    `,
    styles: [`
	.commentItem {
	  margin-bottom: 20px;
	}
  `],
})
export class CommentItem {
	@Input() comment:Comment;
	public children: string;
}

CommentFormコンポーネントでは、PostボタンのclickでhandleSubmitメソッドを実行して、ユーザーが入力した内容を追加します。
ユーザー入力があるauthorとtextは2way-bindingにするため、カギカッコ+カッコ記法を使います。

@Component({
	selector: 'comment-form',
	template: `
            <div class="commentForm">
                <input type="text" [(ngModel)]="author" (change)="handleAuthorChange()" placeholder="Your name" />
                <input type="text" [(ngModel)]="text" (change)="handleTextChange()" placeholder="Say something..." />
                <input type="submit" value="Post" (click)="handleSubmit()" />
            </div>
	`,
	styles: [`
	.commentForm {
	  margin-top: 50px;
	}
  `],
})
export class CommentForm {
	@Output() addComment = new EventEmitter();

	author = "真田幸村";
	text   = "真田丸できました。";

	constructor(private _commentService: CommentService) {
	}

	handleAuthorChange(): void {
		console.log('[CommentForm] handleAuthorChange');
	}

	handleTextChange(): void {
		console.log('[CommentForm] handleTextChange');
	}

	handleSubmit(): void {
		console.log('[CommentForm] handleSubmit');

		if (!this.text || !this.author) {
			return;
		}

		this._commentService.add(new Comment({author: this.author, text: this.text}));
		this.text = '';
		this.author = '';

		this.addComment.emit("added");
	}
}

Angular2を使っても大丈夫?

コンポーネントベースになり、scopeをはじめとする1のややこしさを捨てたAngular2はいい感じに仕上がってきていると感じられました。
1のときにはGoogle自体がAngularをドッグフーディングしてないじゃないかという批判がありましたが、2はすでにAdWordsやGoogle Fiberなどのプロダクトに採用されているそうです。
そういう面からも2の完成度は高いと言えます。個人的にはスクラッチ開発であれば今すぐAngular2を採用してもよいのでは!ぐらいの温度感があります。

そして既存のAngular1アプリからの移行ですが、公式の移行ガイドはかなりの長編になっており、一筋縄では済まなそうな雰囲気がプンプンしています(笑)。本当に変化が大きいため、すでにproductionで稼働しているコードを移行するのは正直腰が引き気味になりますが、Angular2への移行パスは後付けな形で取り入れられた経緯があり、それだけフレームワーク開発側がコストをかけても1からの移行を重要視する決断をしたとも言えるため、トライする価値は十分あるのではと考えています。
移行についても実際に試した内容をお伝えしたいと思います。それではまた。

  • このエントリーをはてなブックマークに追加

Recommend

ユーザー数300万!pairsのインフラの裏側チラ見せします。

UIデザインの悩みどころ「アイコンどうする問題」