イベント駆動AngularJS / 今から書くAngular 2.0

59
イベント駆動AngularJS Angular勉強会#3 GDGKobe - Apr 29, 2015

Transcript of イベント駆動AngularJS / 今から書くAngular 2.0

イベント駆動AngularJSAngular勉強会#3 GDGKobe - Apr 29, 2015

Who

• 奥野 賢太郎 @armorik83

• 京都市

•  

AngularJS勉強会#1に参加して5ヶ月 AngularJSのお仕事いただきました

Angularと私• 2013年秋、AngularJS 1.2とTypeScriptに出会う

• 2014年6月、この勉強会の第一回に参加

• 2014年後半、『AngularJSアンチパターン集』や『モダンAngularJS』といった記事が割と受け入れられる

• AngularJSが嫌われてる? といった風潮とReact.jsの流行に過敏になる

• 突然のAngularJSのお仕事

• 2015年3月、東京でのng-japanに出席 ←いまこの辺

なので、先日やったAngularJS 1.3の話します

まずはDemo

http://likr.github.io/interactive-sem/

SPA開発と学習コスト• 1画面完結

DBのAPI、ページのルーティングは無い

• 実質納期は1ヶ月程度

• グラフ描画ライブラリはD3.jsベース(ここは作ってない) UIのデザイン・実装を担当 ほぼスクラッチ

• 自分にはAngularJSの知識が占めていたので、これを採用

AngularJSの良さって• もともと『HTMLを拡張した構文』を採用していた点が

好きだった

• 自分がWebデザイナ由来で".html"が並んでる安心感 みたいなところはある

• JSXはどうにも抵抗が大きかった(React.createElementがあるよ! ってのもちょっと違ってて)

Reactのヘビーユーザではないので、フェアな比較ではない

でも遅いんでしょ?• AngularJS 1.2はたしかに遅かった

• 1.3でマシになった

• 一覧表示などで、むやみにDOMを更新しなければ十分

• ジャブジャブ使うときは気にする必要がでてくる とにかく速い方がいい! 魂が震えない! という人には向いてない

• 最適化についてはdigest loopでググれば知見が山ほど

初心に返った

• 雑にHTMLに{{}}を並べて書いて

• Controllerをパパっと書いたらもうバインドできてる! 嬉しさ!!

• この「すぐできる感」がAngularJS

でも雑にやると破綻するのがAngularJS

APIが多すぎ?

• 散々言われてるけど、APIが散らばってるのは事実 • ひとつのことを実現するのに3, 4通りあるのは当たり前

• 内部を成り立たせるコアAPIはpublicになっている • 逆にそこを直接叩けるのは強み

$compile, $templateCache, $injectorなど

Angular 2.0

今後1.x系どうやって使おう

• 2014年10月に墓標が乱立

• あれだけ並べられたら、さすがにどうしよう

• とりあえずRIPされてるものは使わない

モダンAngularJSの実践• 2.0を見据えてどうするかは

『モダンAngularJS』のスライドでけっこう話した

• ng-controller, service不使用

• jQuery不使用

• いい機会なので本当にうまくいくか実践するhttp://www.slideshare.net/armorik83/angularjs-141206

この時にあった懸念

• $scopeは無くなる

• 値の共有を、意識せずに親子取り放題にすると死

• 何も考えずに$broadcast, $onで飛び交わせても死

なにか良いイベントの扱い方は…

そうか…! Fluxだ!

Flux

• Facebook社が提唱するアーキテクチャこういう名前のライブラリ・フレームワークがあるわけではない

• React界隈では、もはや常識

• うちはAngularJSだから…と気にしないのは勿体無い設計手法として触れておくべき

Fluxに関する資料• 昨年末くらいから、じわじわ増えてはいた

近どっと増えた

• おすすめしたいのは以下

• 今話題のReact.jsはどのようなWebアプリケーションに適しているか? @hokaccha

• 社内勉強会でReactとFluxについて喋ったinside.pixiv.net

• 10分で実装するFlux@azu_re

いつもの図

AngularJSでやるなら

引用 http://azu.github.io/slide/react-meetup/flux.html

AngularJSでやるなら

引用 http://azu.github.io/slide/react-meetup/flux.html

DIRECTIVES

具体的な話• ng-route使ってる

設計段階で必要なかったけど、拡張余地のため

• ng-routeではControllerは指定しない

• 単一のDIrectiveのタグのみ置くfunction RouteConfig( $routeProvider: ng.route.IRouteProvider ) { $routeProvider .when('/', {template: '<tag></tag>'}) .otherwise({redirectTo: '/'}); }

Root Directive• View, Dispatcher, StoreでいうViewの部分

• グラフ描画ライブラリの都合で、Storeはどうしても2つにする 必要があった

• 利用者の行動 → Dispatcher → Store → View → 即Action Dispatcher → グラフ描画ライブラリ → View

• Q. 2周って無駄じゃね?

• A. そうやってViewが複数と相互にやりとりしていたのが従来のMVW、流れは常に1方向に限定する 2周するEmitの速度は全く気にするレベルではない

複数のStore• 複数のStoreってやってもいいの? という不安があった

近の資料だと、この辺もうちょっと分かりやすい

• SOでFacebookの中の人が複数Storeの可能性を回答していたので、大丈夫そう

• 今回は、全ての操作がグラフ再描画と結びつくので、グラフ描画に使う値の格納Storeと、描画ラッパーStoreの二段構えで回る

http://stackoverflow.com/questions/26597311/flux-multiple-store-instances

Flux模倣の実装• 全てTypeScriptで記述

• CommonJSのrequire()で記述、Browserifyでビルド

• Emitterにはビルトインの$broadcast, $on $emitは上下関係での挙動の違いが複雑になるので不採用

• Dispatcherのイベント名は全て定数管理"constant.ts"を作ってまとめておく

• APIとしては、StoreからDispatcherはaddHandlers() StoreからDirectiveに対してはaddListener()を備える

つまりはこう

引用 http://azu.github.io/slide/react-meetup/flux.html

DIRECTIVES

StoreがDispatcher#addHandlers() を呼ぶ

DirectiveがStore#addListener()を呼ぶ

Directiveが$broadcast()を呼んでDiapatcherに$on()を実装

子Directive• 子DirectiveはStoreのシングルトンを持ってはいけない

• 持っていいのはRootのみ

• 子Directiveが出来るのはActionの発行→Dispatcherへ

• 値はすべて共有せず、isolated scopeにする

• すべてに'&'を指定しreadonlyにする[ここらでDirective Scope] [検索]

出てきそうな疑問

• Fluxは仮想DOMを扱うReactだからこそ効いてくる アーキテクチャなのでは?

• AngularJSでFluxなんてやったら遅いのでは?

自分の解釈• Fluxをやってもやらなくても、$digestが回り続ける

AngularJSでは、この走査を減らす工夫の方が重要

• Fluxを採用しなくてもガンガン回ってドンドン遅くなる 設計は十分に起こりうる

• それより、$scopeのグローバル共有問題やイベント煩雑問題をどう解決するかが課題だった

結果

• 流れが一方向なので MVWより「どこに何を実装すればよいか」が明確

• アプリ内各所にイベントが飛び散らない

• いい感じでした

全部解説するのは大変 なんとオープンソースなので、気になった方は読んでみて

https://github.com/likr/interactive-sem

まだ時間ある?

もうちょっと喋ります

今から書くAngular 2.0Angular勉強会#3 GDGKobe - Apr 29, 2015

Who

• 奥野 賢太郎 @armorik83

• 京都市

•  

Angular 2.0

• Angularの新バージョン

• 2014年10月 ng-europeにて、方向性が発表2015年3月 ng-confにて、具体的な発表

• AngularJS 2.0とは呼ばずAngular 2.0 for JavaScriptと呼んでいる

進捗どうですか• https://github.com/angular/angular にて開発中

• 現在2.0.0-alpha.21これをDeveloper Previewと位置付けている

• さっきハンズオンでやったComponent Routerは Angular 2.0ではビルトインされる予定 どっちのRepoで続けるか揉めてた

• AngularJS 1.x系は1.4がRC1で控え、1.5の開発も予告

@Decorators

• Angularチーム開発の拡張構文AtScriptで採用

• 2015年3月、AngularチームとMicrosoftが協力しAngularはTypeScriptで実装されることが決定

• DecoratorsはTypeScript 1.5.0-alphaに急に追加された構文

@Decorators• ECMAScriptの仕様策定としてはまだまだ

ミーティングでの議題にのぼってる段階(具体的にはES7 Stage 1 Proposal)

• Babelでは--optional es7.decoratorsで利用可能

• TypeScript 1.5.0-alphaでは、もう利用可能TypeScript 1.5.0-betaというのも控えてた

• Angular側が想定してる構文と仕様にすれ違いがあって正直まだグラグラしてる 4月中だけでいくつバグが直ったか…

Qiitaで割とガチにまとめました [Qiita Decorators] [検索]

http://qiita.com/armorik83/items/e3a0ce67f569ddc4b432

Angular 2.0とDecorators@Component({ selector: 'greet', injectables: [Greeter] }) @View({ template: `{{greeter.greet('world')}}!`, directives: Child }) class HelloWorld { greeter: Greeter; ! constructor(greeter: Greeter) { this.greeter = greeter; } }

API今覚えておくならこの辺• @Component - いわゆる1.xでのDirectiveに相当

• @View - TemplateHTMLなどを記述、1.xのDirectiveの設定が @Componentと@Viewに分かれたイメージ

• @Decorator - restrict: 'A'(HTML属性として使う)のDirectiveに相当

• @Viewport - ng-ifやng-repeatなどの制御Directiveが実装しやすい らしい、まだあまり触れてない

• @Parent, @Ancestor - 親Directiveを使う、1.xでのrequireに相当

早速やりたい方は 5min Quickstartからhttps://angular.io/

とはいえ、まだ急いでやらなくていいですDecorators構文の仕様が安定していない、挙動もちょくちょくバギー

でも今後移行とか考えると つらくない?

Cresc Toccata

• クレス・トッカータ

• npm install --save toccata

• 今日もう少し安定して使えるところまで進めたかったAngular 2.0が想像以上にバギーだったので難航

Cresc Toccata• Decorators構文を採用したTypeScriptユーザ前提の

ライブラリ

• AngularJS 1.3.14以上に対応できるよう開発中

• Angular 2.0とAPIに互換性を持たせて提供

• AngularJS 1.x系でもAngular 2.0の「書き方」で開発ができる

• Toccata<伊>とは「急な変化と流れを持つ即興的な音楽」を意味する音楽用語で、即興、試し弾きという意味がある

Cresc Toccataimport {* as angular} from 'angular'; import {* as toccata_} from 'toccata'; !const toccata: Toccata = toccata_(angular); const {Component, View, bootstrap} = toccata; !@Component({ selector: 'hello' }) @View({ template: `<p>Hello!</p>` }) class HelloController { constructor() { // noop } } !bootstrap(HelloController);

このソースで AngularJS 1.3.15が動く

Cresc Toccataimport {* as angular} from 'angular'; import {* as toccata_} from 'toccata'; !const toccata: Toccata = toccata_(angular); const {Component, View, bootstrap} = toccata; !@Component({ selector: 'hello' }) @View({ template: `<p>Hello!</p>` }) class HelloController { constructor() { // noop } } !bootstrap(HelloController);

ここをAngular 2に差し替えても動く

要はAdapterパターン

なぜ作ろうと思ったか• AngularチームもMigratorの話をしていたが、いつになるか分からない

• ぶっちゃけAngularチームのAPI策定、微妙なところがあるので Migratorは信頼しきってない(上出来だったら万々歳)

• オレオレではなく、常にAPI互換を念頭に今のうちからアダプタ実装を開始しておく

• 手元に既に複数のAngularJSプロジェクトが控えているこれを2.0リリース後に一斉に移行させるのはしんどい →今のうちに、分かるところから始めたい でも安定した1.x系で運用したい

移行ビジョン• Toccata独自のDecorators APIとして

@NgController, @NgDirectiveの2つをサポートする

• まずは今動いているAngularJSからコピペで この独自Decoratorsに移す

• そこから段階的にAngular 2.0互換のAPI @Component, @Viewに置き換える

• 終的にはToccataを外して、Angular 2.0のみの 運用にもできる

• 一歩一歩着実に、せーのでやらずに済ませたい!

予定機能• 前半に話したFluxは、毎回実装するのが面倒なので

Angular用Flux実装としてEmitterとAbstract Storeを組み込む

• Angular 2.0はJSソースだけでなくHTML面でも構文に変化がある <input type="text" #name (keyup)>

• toccata-convという変換ユーティリティを現在開発中

• 規則性のある構文なので普段は2.0の構文で書いて、1.x系の構文に変換できるよう準備を進めている

• 適化先輩に教わりながら複雑なパターンのテストを追加している段階

• 分かりやすいサンプルとして公式のTodoアプリをToccataで書く

今後、様々なAngularの勉強会・ハンズオンなどでユーザの意見を聞きながら

Toccataにフィードバックしていきます

Angular 2.0への移行が嫌だから… と離れていく姿はもう見たくないんだ!

Follow me!

• @armorik83

• Angular 2.0の動向をキャッチしてTwitter, Qiita, 勉強会等で伝えていくので是非フォローしてみてください

• Toccataの進捗も伝えていきます もし気になったら覗いてみてください

ありがとうございました

Angular勉強会#3 GDGKobe - Apr 29, 2015 ©2015 Crescware