} b.speaker::after { content: ":"; }
こんにちは、編集長の白石です。
本記事は、2016年9月に開催されたTechFeed Live#2 「React vs Angular 2」の模様をお伝えする記事の前編です(後編はこちら)。 TechFeed Live#2とは、「TechFeedを地上に出現させる」ことをコンセプトとした、テクノロジーの最新トレンドをエンジニア向けに紹介するというイベントです(TechFeedとは、「最先端が、ここにある。」をキャッチコピーとしたエンジニア向け情報収集アプリです)。本イベントは、ReactとAngularをより楽しく深く学ぶため、現代のWebアプリに求められる各種要件についてそれぞれを比較する…というアプローチを取りました。 (私は本イベントの企画と対談のモデレーターを務めました)
読み応えバッチリ、勉強になること間違いなし。今回はライブ感を重視し、あえてイベントでの(砕けた)口調も可能な限り再現してみました。 では皆様、どうぞお楽しみください!
React vs Angular 2対決開始!
shumpei 本日は、多くのお客様にご参加いただいて、大変うれしく思います。 今回のTechFeed Liveは、「React vs Angular 2」と題しまして、今をときめくコンポーネント指向のWebアプリケーション・フレームワーク2つを比較して学べる会を目指しています。
そのために、それぞれのフレームワークのエキスパートの方々にお集まりいただきました。
トークバトル参加者(順不同、敬称略)
(編集部注: 本記事では登壇者の皆様の希望により、以下ハンドルネームで呼称させていただきます)
React Side
Angular2 Side
モデレーター
- shumpei (白石 俊平) (HTML5 Experts.jp編集長)
また今回、フレームワークを比較するための項目を以下のように洗い出してみました。基本的にこの流れに沿って進めたいと思いますが、脱線は大歓迎ですので、皆さんご自由にご発言いただいて構いません。(編集部注: 前半は「テンプレート」まで)
- 開発⾔語
- アーキテクチャ
- ビルドツール
- ルーティング
- テンプレート
- スタイリング
- コンポーネント以外の処理
- ツールサポート
- テスト
- パフォーマンス
- サーバサイドレンダリング
では早速始めましょう!
開発言語
shumpei まずは開発言語について語っていただければと思います。Reactから聞いてみたいと思いますが、Reactを使った開発は基本的にどんな言語を使うのでしょうか?
koba04 基本的にはBabelを使って、ES6以降のコードをES5に変換しつつ開発しますね。でも、TypeScriptを使う人もいます。Babelの作者はFacebookにいたりするので、基本的にはBabelだと楽ですね。
shumpei なるほど。Angular 2のほうはいかがですか?
laco 基本的には開発言語はJS, TypeScript, あとDartがあります。
会場 (笑)
laco いや、Dartは笑いどころじゃないでしょう(笑)。 公式に推奨されているのはTypeScriptです。ES6書いてBabelでもいいし、ES5でも書けることは書けますが、結構キツイんで、基本的にはTypeScriptで書くのがデファクトになってます。
83 ちょっと待って下さい。結局なんの言語で書きますか、というのが重要で。Reactだったらどの言語、Angularだったらどの言語、っていう 質問がおかしい 。
shumpei そうですか…すいません。
83 大きいものだったらTypeScriptのほうがいいし、小さいものだったらAngular 2でもES6とBabelのほうがサクサク作れます。Angular 2はTypeScript専用だよね、ということはよく言われますがそれは違うと思います。
shumpei ちなみに、BabelでAngular 2を書くというのは全然ありなんでしょうか?
laco 全然ありですよ。そのためのプラグインも、 Shuhei Kagawaさんという方が作ってます 。Flowの記法とか使って、型があるように書けます。
あ、一つReactサイドに聞きたかったんですが、JSXってみんながみんな使うもんなんでしょうか?
yosuke_furukawa そうだと思います。ぼくもJSXなしでやってみようと思ったこともあるんですけど… 結論としては、(JSXが) ないとダメだなと (笑)。 結局HTMLっぽく書きたくなるんですよ。
ちなみにさっきの言語の話を少し深掘りしたいんですけど、言語は規模で決まるというのは確かにそのとおりだと思うんですが、一方でエコシステムとかを見ると、BabelをES6じゃない言語で書いてエクスポートしてる例ってあんまりないんですよね。
例えばTypeScriptでライブラリ書いてエクスポートしてるなんてあんまりない。なので、エコシステム全体としては、どっちの言語がより慣れているかという度合いはあるのかなと。そういう意味では、ReactはBabelでAngular 2はTypeScript、というのはあるんじゃないかと思います。
83 そうですね、そういう意味で言うと、(Angular 2も)公式サイトのチュートリアルとかも全部TypeScriptで書かれていたりするので、そういう住み分けとかは色がはっきりしているかなと思います。 ちなみにReact陣営に聞きたいんですけど、TypeScriptは「GoogleがMicrosoftと手を組んだ」なんてよく言われてますが、(React開発元のFacebookが開発している) Flowってどうなんですか?
yosuke_furukawa 実際、React自身はあんまりFlowでっていう話はないです。(Reactコンポーネントの) propTypesを、Flowで書けるようにしよう、って話は進んでるみたいですが。
「propTypesで型チェックをしていく」というのがあんまり綺麗じゃないというか、書き方として洗練されている気がしない。なのであれをFlow側に寄せていこうという活動はあるみたいです。
koba04 FacebookがFlowを強制してくるってことは全然ないですね。propTypeを置き換えるときも、FlowかTypeScriptか、好きなのを使えばいいという感じです。 そこは、フレームワークが特定の型システムに依存する必要はないので、好きに使っていけばという感じです。
shumpei ちなみに、ご存じない方もいらっしゃるかもしれないので、Flowってなんでしょうか?
koba04 Flowは、静的な型チェックをするためのライブラリです。まあ、思想としてはもっと踏み込んでいて、JavaScriptでハマりがちなコードとかを静的解析して、静的な型付け以外のチェックをやっていこうと。
そういう意味では、ESLintとかもカブる部分がありますね。例えばnullチェックをしているかどうかとかも確認できたりとか。静的型付け以上に、JavaScriptでハマりがちなエラーをチェックするためのツールという面が大きいかなと思います。
shumpei コードそのものは、JavaScriptで書くということですね。
アーキテクチャ
shumpei 次の話題はアーキテクチャについてですが、アーキテクチャというとぼんやりしてますね…。これぼくなんでこのお題を出したんだっけな。えーと…、あ、思い出した。Fluxとかの話をしようと思ったんだった。FluxやReduxなど、アーキテクチャに関してちょっとご説明をお願いしてもいいですか?
yosuke_furukawa 基本的にReactだけだと、イベントや状態を管理する仕組みがないんです。ReactってViewのライブラリなので。Webアプリって、APIサーバを叩いてデータをもらってきてそれをレンダリングするとか、そういうのが普通ですよね。そういうことをしようと思ったら、Reactだけじゃ厳しいんです。そういう時に、イベントを管理する仕組み、あと状態を管理する仕組みっていうのが必要になってくる。そういう時に必要になってくるのがFluxであったり、Reduxであったりというライブラリです。
Fluxはライブラリというよりは「思想」というか、デザインパターンに近いですね。イベントを管理するための、Observerパターンを言い換えたというか。あれねえ、何がすごいかって、名前を付けたのがすごいですよね。カッコいいですよね。名前の勝利です(笑)
そういう (Fluxという) 考え方が浸透してきたところにReduxっていうのが出てきて、今一番流行っているライブラリです。
ただひとつ間違えちゃいけないのは、ReactとFlux、ReactとReduxを組み合わせたからといって、Angularほどの「フレームワーク」といえるかというとそこまでいってない。 ただライブラリを組み合わせただけのものでしかなくて。さらに、その上で自分のレールを作っていく必要があるんじゃないかなとは思います。
shumpei なるほど、ReactはReactだけで完結しないと。一方Angular 2のほうは「One Framework」だそうですね。
83 Angular 2の話をする前に、AngularJS(AngularJS 1)のほうに一旦戻ろうかなと思うんですが。そもそも1のころは、エコシステムが「Angular World」だったと。
まだ今あるようなES6のモジュールとかがなかった時に、それでもモジュールの仕組みが欲しいとか、そういう要望があったと。なので、angular.module()
の中に書いていくというのがあったんですね。
で、それがあったからAngularはエコシステムに乗っていない、一方でReactは乗っているというような分断が起きはじめました。 それ自体は2年前くらいは正しかったのですが、そのイメージをAngular 2になっても引きずっている方がまだおられるんじゃないかというのが気になっています。
83 私はAngular 2を「フレームワーク」と言われることは好きじゃなくて、Angular 2は「ライブラリ」だと思っているんですよね。なんでかっていうと、Angular 2にデータを保存しておくものだったり、データのやり取りをするためのものっていうのが、別にAngular 2にはないんです。
Angular 2の特徴ってテンプレートとDIとかあると思うんですけど、実際にはAngular 2だけで全て事足りるかというとそうでもないし、そこは結構割り切ってAngular 2は好きなフレームワークと組み合わせられるようにもなっている。
その上で、Angular 2をどうやって使うかというと、RxJSがよく出てくると思います。RxJSはストリームやイベントを扱うためのライブラリで、FluxのObservableパターンと同じく、何か変化があるまでは動かない。 何か変化がemitされたときにsubscribeしてる側で値を書き換える。それでテンプレートの描画が変わると。そういう意味では、今時代の変化が、Observableパターンに来てるんじゃないかなと思います。
shumpei ちなみにこれ、ご存知だったらでいいんですけど、Angular 2とReduxを組み合わせてみた、みたいな話もあるんですけど、そうしたことをする利点とかってなんなのでしょうか?
83 私は実際それをやってみて、別のイベントで発表したこともあるのですが、ぶっちゃけそのときは相当disりまして(笑)。 Reduxをdisったわけじゃないんです。Angular 2とReduxという組み合わせをdisったんです。Reduxは中立なライブラリとは謳われているのですが、実際にはReactを前提として作られたライブラリなので、まあそうなるわな、という感じでした。
Angular 2とReduxの組み合わせがなぜいけてないかというと、DIとの相性が悪いんです。 ReactにはDIという考え方が全くないし、ReduxもDIを全く無視している設計になっている。
なので、Angular 2はDIできるのに、Reduxと組み合わせると、ReduxのReducerの中では一切DIできない。 何のためにDIができるAngular 2の中でReduxを使うのか。そこだけ別世界に飛ばされるような感じでした。
laco ざっくり言うとReduxにしてもFluxにしても、シングルトンなステートがあって、ステートの変更を検知してコンポーネントがデータを受け取って、コンポーネントがデータを書き換えて…っていうのをくるくるやるわけじゃないですか。
で、シングルトンってAngular 2だとDIで実現するんですよ。なので、Reduxいらないんですよね。仕組み、レールがすでにあって、あとはステートを持つやつを書くだけで、あとはDIでどうとでもなる。 だから、Angular 2は結局、DIでどうとでもなります。
shumpei Reduxと組み合わせたみたいな記事をたまに見かけるんですが、それはAngular 2に足りないものがあって、Reduxがそれを補うのかなとかって勝手に想像していたんですが、別にそんなことないよ、って感じでしょうか。
laco たぶんバズワード組み合わせただけじゃないかな、と(笑)
shumpei なるほど(笑)。ちなみに例えば、ReactとRxJSを組み合わせる、みたいなバズワードの組み合わせ方とかはないんでしょうか。
koba04 もちろんそこは自由にできて、ReduxとRxJSを組み合わせるためのredux-observableというのをRxJSの作者が作ってたりします。RxJSを使いたい場合はそういう選択肢もある。
ただ、APIからデータ取ってくるだけだったらObservable
(RxJS) 使う必要もなくてEventEmitter
で事足りるかもしれないし、そこは自由に選んでくださいという感じですね。
ビルドツール
shumpei 次はビルドツールですね。ここは意見を戦わせるところでもなくて、ただ紹介するだけでいいのかなとも思いますが、暴走や脱線は大歓迎です。 まずReactでは、ビルドツールには主に何を使いますか?
yosuke_furukawa 主にwebpackやBrowserifyですね。エコシステム全体がBrowserifyやwebpackを前提として作られたりしますので、それを使うのが普通です。コンポーネント志向なんで、コンポーネントを作ってexport/importするのが当たり前の世界になってます。
shumpei Angular 2サイドはいかがですか?
laco ここは何も変わらないですね。webpack使えますし、バンドル (編集部注: 複数のJavaScriptモジュールを1ファイルにまとめること) しないとブラウザでは使えないし。 そういえば、最近npmリポジトリから落ちてくる(npm installでインストールされる)のが、ESモジュールになったんですよ。(requireではなく) import / exportがそのまま書かれている。 なので、webpack2やRollupを使うとTree shaking (編集部注: 不要なコードを「振り落とし」、バンドルサイズを小さくすること) できるというのはありますね。
shumpei SystemJSっていうツールの存在も聞きますが。
laco (笑)
shumpei 笑っちゃうんですかw
laco ごめんなさい、ちょっと失笑です。あれはまだちょっと人類には早いって思ってます(笑)。
会場 (笑)
shumpei どこらへんが人類には早いんでしょう?
laco あれは世界がHTTP/2になるのを待って、出直してきてほしいツールです。importごとにリクエスト飛んだら、(HTTP/1だと)遅すぎて話にならないです。残念ながら。
shumpei 1ファイルにバンドルする機能とかはないんでしょうか?
laco ありますけど、それならwebpackのほうがエコシステムが育っているので、そちらでいいんじゃないかな。プラグインとか、Loaderとか。
yosuke_furukawa SystemJS待つくらいなら、ES Loader待ったほうがいい(笑)。
shumpei JSPMっていうのがあるみたいですが…、JavaScript Package Managerでしたっけ。
laco あー。あれ、いつまで存在してるんですか?
yosuke_furukawa その質問誰に聞いてるんですか(笑)。
shumpei なるほど、その程度の扱いということで(笑)。では、SystemJSは人類には早すぎるということで、Angular 2やってる方もwebpackやBrowserifyがいいんじゃないかなということですね。
laco Plunkerみたいなオンラインエディタ上でやるぶんには、SystemJS割と便利なんですけどね。ブラウザ上ではバンドルできないので。ただ、プロダクションでは使う用途ないですよね。
ルーティング
shumpei では次は、細かい話が混じって申し訳ないですが、ルーティングとかに関して言いたいことがあればお聞きしたいのですが。
yosuke_furukawa これは…Angularサイド圧勝じゃないですか?
shumpei そうなんですか?
yosuke_furukawa React完敗ですね。
laco ほんとか??(笑)
yosuke_furukawa そもそもルーティングって、React本体には機能がないんです。で、デファクトスタンダード的に使われているReact Routerっていうのがあるんですが、これみんなdisってる(笑) 。 とりあえず使ってみて、「これクソ使えねえな」みたいな話になるんですけど(笑)。
何が使えないかって言うと、ルーティングの時に最初にやってほしいことって「アクションを発火してほしい」んです。 APIを呼び出してデータを取ってくる、ということをしたいとみんな思うと思うんですが、そういうことをやってくれるような感じになってなくて、まず最初にコンポーネントをマウントしちゃうんです。コンポーネント指向なんで。
でも普通みんながやりたいのって、アクションだと思うんですが、それを書くための記法は今のところない。 なのでしょうがないから、真っ白なコンポーネント出してそこでイベント発火させて(データを)取りに行く…みたいなことをみんなやってるんじゃないかな。あんまりよくないです。
なので、ぼくの頭のなかではReact Routerは決定版にはなっていない。決定版になってないがゆえに、デファクトスタンダードとはさっき言ったけど、みんな野良ルーターみたいの作っちゃって、結果今あんまりよくない状態になっている。 …というところが「圧敗」ですね(笑)。
shumpei 圧敗(笑) では、圧勝側のご意見も聞きたいです。Angularサイドはいかがですか?
laco 今の話をすると、Angular 2もパスとコンポーネントを結びつけるものだという考え方は変わらないです。 ただ、コンポーネントがマウントされるときに呼び出されるフックポイントがあって、そこでリクエストを飛ばして、その結果を持ってマウントができるという仕組みがある。 あと、「ルーティングしてもよいかどうか」というcanActivateみたいな仕組みもあって、出ていくときの仕組みもあって。 そうしたイベントが全部RxJSに乗っていて、ルーティングが起きるときにはまずイベントが発火するので、使いやすくはなっています。
yosuke_furukawa そういう意味でいくと一応onEnterみたいなのはあるんだけど、そこでデータを拾いに行くのは、推奨しないってことになってまして…(笑)。
laco 今のAngular 2のルーターはとてもよくできているので、今のところは言うことない、っていうくらいの完成度になりました。
koba04 ぼくは個人的にルーティングにこだわりはないんですが、基本的にはここもライブラリに依存しなくてもいいんじゃないかな、とはずっと思っています。汎用的ないいルーターが出てこないのかな、とは思ってるんですが、あんまり出てこないですね。
laco 確かに。イベントだけ発火してくれればそれでいいですからね。
koba04 そう。ライブラリと関連しているところではないので。誰か作るチャンスだと思います。
shumpei ReactやAngularに関係ないルーティングのライブラリがあればいいのに、ということですね。
テンプレート
shumpei 前半最後のトピックになりそうですが、次は「テンプレート」です。これ盛り上がるのかな…お互いの記法がキモい、とかってdisりあっていただいてもかまわないんです(笑)。
83 JSXもキモい、Angular 2テンプレートもキモい、気に入ったキモいほう使え、って感じですね(笑)。
laco でもまあ、Angular 2のテンプレートはギリギリHTMLなので、既存のHTMLツールチェインには乗れるわけです。ちなみにJSXってファイル分けられるんですか?「.jsx」みたいなファイルあるんですか?
yosuke_furukawa 一応あります。Angular 2は分けられるんですか?
83 テンプレートの文字列を直接ソースコード中に書くのも、URLで外部ファイルを指定するのも、どちらも可能です。URLを指定した場合はAjaxで取ってきます。
yosuke_furukawa そこの通信(コスト)はいいんだ?
laco それはwebpackのプラグインで、URLをrequire()に変換してくれるやつがある(angular2-template-loader)ので、ありがたく使わせてもらってます。 あとひとつ気になるのは、JSXってXSSのサニタイズとかやってくれるんですか?
yosuke_furukawa …えっとですね。…Angularの圧勝です。
会場 (笑)
yosuke_furukawa 普通にpタグやdivタグの中に入れる文字列はサニタイズしてくれるんだけど、例えばaタグのhref属性とかに対しては、別に何もしてくれません。なので、(属性値に)javascript:〜
とかやろうと思えばできちゃう。
laco innerHTML
ぶち込みとかも?
yosuke_furukawa そうです。だから、innerHTML
使うときとか、URLをセットする場合とかは、注意しなくちゃいけない。 (URLから)javascript:
を省いてやる必要とか、XSS対策についてはケアが必要です。
shumpei React本体でそこら辺を対応しようという動きはないんですか?
koba04 JSXって結局ただのオブジェクトに展開されるんですけど、Symbol
とかを使って、外から知らないタグを差し込まれたりはしないようになってます。なので、渡された文字列をそのままReact Elementsとして展開するということは出来ないようになっていますけどね。
laco あ、あともう一つ。Web Components対応ってどうなってるんですか?
koba04 一応Custom Elementは書けるようになっています。あとは、DOMComponentに不正な属性を渡すと警告が出るようになっていて、それはCustom Elementをサポートするための布石です。なので、この後何らかの対応が入ってくるとは思います。
shumpei そろそろお時間ですので、これで前半を終わりにしたいと思います。後半も、引き続きよろしくお願いします。