Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ngUpgradeと移植戦略
Search
OKUNOKENTARO
March 21, 2016
Programming
6
4k
ngUpgradeと移植戦略
2016/3/21 ng-japan 2016の登壇に使用した資料です。
OKUNOKENTARO
March 21, 2016
Tweet
Share
More Decks by OKUNOKENTARO
See All by OKUNOKENTARO
トレタO/X アーキテクチャ移行記 Next.js App Router化への道のり / TORETA TECH UPDATE 1
okunokentaro
5
11k
Podcastを継続する技術 / refactoradio-240119
okunokentaro
1
170
Webアプリケーション設計の第一歩は ディレクトリの整理から / Encraft 1
okunokentaro
34
10k
JSONとJSON Schemaを改めて理解する / tokyo_study
okunokentaro
9
2.3k
それでもどうしてRecoilを使うのか / Harajuku.ts Meetup Recoil
okunokentaro
19
5.5k
TypeScriptは10年でこんなに進化しました / TechFeed Experts Night 11
okunokentaro
6
1.7k
Hasura.io RDBをサクサク作る方法はARやO/RMだけじゃなくなりました/hasura-io
okunokentaro
5
640
コードには型アノテーションよりも要件アノテーションを増やせ!/harajukuts2
okunokentaro
14
6.3k
10年と3ヶ月でWebサービスを作った話 / Piyogrammer Conference 2021
okunokentaro
2
1k
Other Decks in Programming
See All in Programming
AIの力でお手軽Chrome拡張機能作り
taiseiue
0
190
密集、ドキュメントのコロケーション with AWS Lambda
satoshi256kbyte
1
210
DROBEの生成AI活用事例 with AWS
ippey
0
140
クリーンアーキテクチャから見る依存の向きの大切さ
shimabox
4
900
Code smarter, not harder - How AI Coding Tools Boost Your Productivity | Angular Meetup Berlin
danielsogl
0
100
Datadog DBMでなにができる? JDDUG Meetup#7
nealle
0
120
負債になりにくいCSSをデザイナとつくるには?
fsubal
10
2.5k
Generating OpenAPI schema from serializers throughout the Rails stack - Kyobashi.rb #5
envek
1
310
Visual StudioのGitHub Copilotでいろいろやってみる
tomokusaba
1
190
ML.NETで始める機械学習
ymd65536
0
220
パスキーのすべて ── 導入・UX設計・実装の紹介 / 20250213 パスキー開発者の集い
kuralab
3
860
pylint custom ruleで始めるレビュー自動化
shogoujiie
0
140
Featured
See All Featured
Facilitating Awesome Meetings
lara
52
6.2k
Code Review Best Practice
trishagee
67
18k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
4
360
Music & Morning Musume
bryan
46
6.4k
4 Signs Your Business is Dying
shpigford
182
22k
For a Future-Friendly Web
brad_frost
176
9.6k
Java REST API Framework Comparison - PWX 2021
mraible
29
8.4k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Code Reviewing Like a Champion
maltzj
521
39k
Site-Speed That Sticks
csswizardry
4
400
Building Your Own Lightsaber
phodgson
104
6.2k
Imperfection Machines: The Place of Print at Facebook
scottboms
267
13k
Transcript
ngUpgradeと移植戦略 Mar 21, 2016 / ng-japan armorik83
はちさん 奥野 賢太郎 @armorik83 ng-kyoto代表 ChatWork株式会社
Qiita
ng-kyoto 4/10 渋谷ヒカリエ by teratail / ng-kyoto, ng-japan 4/16 サイボウズ大阪梅田オフィス
/ ng-kyoto, GDG神戸 ng-kyoto Angular 2ハンズオン勉強会 東西合同開催!!
お話しすること • なぜ移行戦略ではなく移植戦略なのか • 移植の前に現在地を知る • 移植の複数のフェーズ • Angular 1のこれって2ではどう書くの?
なぜ移行戦略ではなく 移植戦略なのか
その前に前提 • 業務としてAngular 2化を進めている上での知見 • 1と2は全く互換性のない同名の別フレームワーク というのは誤解 • UPGRADING FROM
1.X https://angular.io/docs/ts/latest/guide/upgrade.html • Angular 1から2へは移行可能
なのになぜ移植と呼ぶか • すべての手順を公式サイトの通りに進めるのは煩雑 • 世界中のAngularのコーディング・スタイルはバラバラ • 「ドキュメント通りに移行しなければ」と悩むより Angular 2流儀を覚えてイチから書いたほうが むしろ早い可能性もある
とはいえ移植はしんどい! • これを全て移植するのか…と憂鬱になる • できることなら移行したい • 楽に移行したい
段階的移植法 • 段階的移植法(armorik83命名) • 公式サイトの移行手順は活かしながら ある程度は移植(書き直し)する • 移行を複数のフェーズで捉える • 少しずつ移植を進めて
最終的には全てがAngular 2な状態へ
移植の前に現在地を知る
現在地はどこだ TypeScript Angular 2 ES2015 ES5 Coffee Script AngularJS 1.4,
1.5 1.3 1.2
TypeScript Angular 2 ES2015 ES5 Coffee Script AngularJS 1.4, 1.5
1.3 1.2 この距離で 移植難度が異なる 現在地はどこだ
言語をどうするか • CoffeeScriptが最も遠く TypeScriptが最も近い • ES5, ES2015の場合 「--allowJsを付けてJS, TSを混ぜてコンパイル」でも 動くので段階的TypeScript化でなんとかなる
• Angular 2はTypeScript専用ではないので ES5でも扱える
Angular 1.xのバージョン • 最新にするに越したことはない • 1.2を使っている場合 残念ながら移行への道のりは険しい • 一旦1.5まで移行してから2への段階的移植を 試みたほうがよい(もしくは諦める)
• 1.4を使っている場合 1.4 → 1.5は楽なのでまず1.5にして2化に備えておく
いまAngular 1をどう書くか • 手前味噌ですがAngularJSモダンプラクティスは 現在も有効 http://qiita.com/armorik83/items/5542daed0c408cb9f605 • AngularJS老化チェックの記事で現在のプロダクトの 老化度を測り若返らせる(1.5に寄せていく) http://qiita.com/laco0416/items/edfa917583af4593ad6c
1.5 Componentにすべきか • Angular 1.5から追加された angular.module().component() • 1.4までのDirectiveは1.5のComponentに 一旦移行してからAngular 2化すべきか?
1.5でのDirectiveの扱い • 現在のプロダクトで無理にDirectiveとComponentを 両方を混ぜる必要はない(好みの話) • 無理にすべて移行する必要も無い • ただしDirectiveを構造的に細分化しているなら不要だが そこの考慮が無い場合一旦Componentにしていくとよい •
$scopeを多用している場合、先にComponent化すべき • Angular 1.5を今から新しく始めるならば 最初からComponentを使うべき
移植の複数のフェーズ
移植戦略マップ TypeScript Angular 2 ES2015 ES5 Coffee Script AngularJS 1.4,
1.5 1.3 1.2 この箇所を細分化する
複数のフェーズ 1. 準備 2. ng2 Component作成 3. ng1 ServiceのUpgrade 4.
ng2 Componentへの機能移植 5. ng1 Serviceのng2 Service化 6. Router周り、bootstrap周りの移植
1. 準備 • 幾つものUIパーツで構成されるWebアプリケーションを想定 • チーム内で合意を得る、稟議を通す 稟議の通し方は様々だが、パフォーマンス改善は説得力ある • キャッチアップの社内勉強会、外部の勉強会に参加 •
branchを分ける、依存関係の修正 ビルド環境の調整など足回りを組み立てる • 一度Angular 2チュートリアルでミニアプリ開発を 試しておくと吉
2. ng2 Component作成 app-main app-nav app-contents app-nav-items app-contents-body ng1 Directiveと同要素名でng2
Componentを作成 とにかくガワを作る まだマウスやウインドウのイベント・ハンドリング移植はしない ng-ifやng-repeatは、ここで*ngIfや*ngForに書き直す app-main app-nav app-contents app-nav-items app-contents-body app-root
2. ng2 Component作成 ルートだけはng1 Directiveで そこに連なる要素をすべてng2 Componentにする ルートに置くng2 Componentを upgradeAdapter.downgradeNg2Component()でng1でも利用できるよう変換
app-main-ng2 app-nav app-contents app-nav-items app-contents-body app-root 変換 ng1の世界 ng2の世界
2. ng2 Component作成 テンプレートからng-appを除去 angular.bootstrap()形式にリファクタリングしておく さらにupgradeAdapter.bootstrap()に書き直すとng1内でng2を扱える app-main-ng2 app-nav app-contents app-nav-items
app-contents-body app-root 変換 ng1の世界 ng2の世界
3. ng1 ServiceのUpgrade • ng1 ServiceをupgradeAdapter.upgradeNg1Provider()に通して ng2で利用可能な状態にする • ng2 Componentにng1
ServiceをDIする • コードの書き方を詳細に話すと時間がないので割愛 • UPGRADING FROM 1.X https://angular.io/docs/ts/latest/guide/upgrade.html
4. ng2 Componentへの機能移植 • 機能をng1 Directiveからng2 Componentへ移植していく • コピペでいけるものもあるが、書き直す必要がある箇所もある •
ng1 Directiveにロジックをベタッと書かず あらかじめng1 Serviceから利用する形にしておくと だいぶこのフェーズは楽になる • ng2 ServiceはupgradeAdapter.bootstrap()で起動する 前にupgradeAdapter.addProvider()で登録しておく
ng1 Serviceをng2 Serviceに移植する 移植作業中はng2 Componentからng1 Serviceを使っておく 5. ng1 Serviceのng2 Service化
app-main-ng2 app-nav app-contents app-nav-items app-contents-body app-root Ng1APIService Ng1StorageService Ng2APIService 裏で移植作業 Ng2StorageService
必要な移植作業が終わったらng1 Serviceはお役御免となる app-main-ng2 app-nav app-contents app-nav-items app-contents-body app-root Ng1APIService Ng1StorageService
Ng2APIService 移植できた Ng2StorageService 5. ng1 Serviceのng2 Service化
ng2 Service化できたらng1 Serviceをng2 Serviceに付け替える テストで切り替え前後の挙動に変化が無いか担保できるとよし 最悪目視・手動操作で確認 app-main-ng2 app-nav app-contents app-nav-items
app-contents-body app-root Ng2APIService ng2化 Ng2StorageService 5. ng1 Serviceのng2 Service化
app-main app-nav app-contents app-nav-items app-contents-body app-root 6. Router周り、bootstrap周りの移植 ルート要素もng2化、アダプタを用いた接合部分もアダプタを外す ui-routerやbootstrap周りもAngular
2に移植 おそらくけっこう大変なフェーズ(うちもまだ辿り着いていない) app-main-ng2 app-nav app-contents app-nav-items app-contents-body app-root
Angular 1のこれって 2ではどう書くの?
Filterの使用 ng1 <td>{{movie.title | uppercase}}</td> ng2 <td>{{movie.title | uppercase}}</td> Angular
2ではFilterのことをPipeと呼ぶ Angular 1 to 2 Quick Refを読めば対応が表にまとめられているので必読 https://angular.io/docs/ts/latest/cookbook/a1-a2-quick-reference.html
Filterの定義 ng1 angular.module().filter("reverse", function(){}); ng2 @Pipe({name: "reverse"}) export class FilterPipe
implements PipeTransform { transform(value: string): string { return // } } Pipe Annotationを付けたclassにtransform()メソッドを実装する
Serviceの定義 ng1 angular.module().service("Service", function(){}); ng2 @Injectable() export class Service {
// } bootstrap(RootComponent, [Service]); Injectable Annotationを付けたclassをbootstrap第二引数に渡す または、DIしたいComponentのprovidersプロパティに渡す
イベントのハンドリング ng1 $element[0].addEventListener("mouseenter", function(){ this.color = "#0000ff"; $scope.$apply(); }); ng2
@HostListener("mouseenter", ["$event"]) onMouseenter($event: MouseEvent) { this.color = "#0000ff"; } 自身のイベントをハンドリングするなら @HostListener()をメソッドに付ける
$apply ng1 $scope.$apply(); ng2 ChangeDetectorRef.detectChanges() Zonesのお陰で基本的に手動での変更検知発火は不要 どうしても手動で再bindを走らせたいときは ChangeDetectorRefをDIし、detectChanges()を呼ぶ
$watch ng1 $scope.$watch("name", function(newVal, oldVal) { // }); ng2 ngOnChanges(changes)
{ console.log(changes["name"].currentValue); } ngOnChanges()にて可能
$watchCollection ng1 $scope.$watchCollection("obj", function(newObj, oldObj) { // }); ng2 ngDoCheck()
{ const changes = this.differ.diff(this.list); if (changes) { // } } 配列ならばIterableDiffers、オブジェクトならばKeyValueDiffersを用いて ngDoCheck()内で差分を検出することで可能 準備が面倒な上に処理負荷が大きめなので極力ngOnChanges()で済ませたい
One-time Binding ng1 {{::param}} ng2 @Component({ selector: "my-component", changeDetection: ChangeDetectionStrategy.OnPush,
template: `{{param}}` }) ChangeDetectionStrategy.OnPushを指定する その中で手動で再bindしたいときは ChangeDetectorRef.markForCheck()を呼ぶ
compile, link, destroy • ng1 DirectiveのlinkはngOnInit(), ngAfterViewInit()などの Lifecycle Hooksで代替可能 https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html
• $scope.$on("$destroy")はLifecycle HooksのngOnDestroy() で代替可能 • ng1 Directiveのcompileプロパティで行っていたフックは ng2 Componentでは代替不可 • ngOnInit()で近いことはできる jQueryを使って別要素を生成していたりすると移植困難
まとめ
なんとかなる
ありがとうございました ngUpgradeと移植戦略