AngularJSをAngular移行するために調査したこと

AngularJSのアプリをAngularへ移行するにあたって何が必要になるのかを洗い出す必要がありました。
その時に調べたことをまとめておきます。
なお、この記事を書いた時点でAngular移行の作業はまだ着手開始から3週間ぐらいの状態です。


# 前提

ざっくりいうと、TypeScriptとWebpack使ってるんで一般的には相当Angular移行しやすい方だと思います。

## 移行するアプリの構成

ベースはこちらの記事の通り
http://tech-magazine.opt.ne.jp/entry/2016/07/27/190409#オプトのフロントエンド-case1

補足

- AngujarJSのバージョンは1.5
- ES Module対応済み


## コードベースについて
### 規模

行数
TypeScript: 21936行
html: 8596行

Controller:149個
Directive:70個
Filter:8個
Service:154個

### コードの老化チェック（？)

参考： http://qiita.com/laco0416/items/edfa917583af4593ad6c

- `restrict: 'E'`なdirectiveはあまり使われておらず、殆どの画面で`ng-controller="SomeCtrl as ctrl"`な書き方を利用している
    - routingで指定されたhtml templateの最初の要素で`ng-controller`が利用され、そのURLと1対1対応するControllerがある形
    - ただし、`$scope`などのグローバルが汚染された変数は殆ど使われておらず、component化するにあたって必要な修正は少ない
- 個別のコンポーネントについてはbindToControllerを利用したdirecitiveを利用している
- $scopeを利用した変数の取扱いは極小
- \$scope.$watchなども必要最低限

## 筆者について

- Angularは程々に書ける(ので、今回の調査にあたって事前のキャッチアップは特にしてない）
- Upgradeは当然初めて（つらい


# 調べたこと

## UPGRADING FROM ANGULARJS
何はともあれまずは公式Doc
https://angular.io/docs/ts/latest/guide/upgrade.html

ここでは主に`@angular/upgrade`の使い方を調べました
移行プロセスについて記述がありますが、運用始まってるサービスで使えるシロモノではないと判断し、そこら辺は流し読み程度にとどめました。

概ね以下の情報を得たはず。

- AngularJSとAngularのハイブリッドアプリとして動かす方法
- Componentの相互運用
- Serviceの相互運用
- Filter/Pipeの相互運用が出来なさそうなこと
- AoTコンパイルが可能であること


## その他、ng1 -> ng2移行についての記事など

### [ngUpgradeと移植戦略](https://speakerdeck.com/armorik83/ngupgradetoyi-zhi-zhan-lue)
はちさん( @armorik83 )さんの移行スライド
21~31ページに記載されている、ng1からng2への移行期についての具体例が大変参考になりました。
このスライドから具体的にうちのプロジェクトに適用したらどうなるかをイメージしてみて、メリデメを考えてみたりしました
このスライドだと、Component周りはビッグバンリリースになるだろうと感じたので、そのまま利用は難しそうとアタリを付けました（確か）


### [Migrating an AngularJS App to Angular - Part 1](https://auth0.com/blog/migrating-an-angular-1-app-to-angular-2-part-1/)
公式Docよりは実践的な移行チュートリアル的記事
ざっと眺めたところ、これ使うとやっぱりビッグバンリリースになりそうだったのでロクに内容読んでません
いやそんなフルスクラッチで作れたら苦労しないでしょ・・・という気持ちになりました（こなみかん


### [Two Approaches to Upgrading Angular Apps](https://blog.nrwl.io/two-approaches-to-upgrading-angular-apps-6350b33384e3)
段階的Upgradeに関しての2つの移行方針を紹介し、それぞれのメリデメをまとめた記事。

ざっくりまとめると、

- Vertical Slicing: Routing単位で移行
    - スコープが片方のフレームワークで閉じるのでデバッガブルでやりやすい（ng1,2のComponentが1画面に混ざらない）
- Horizonal Slicing: 末端のComponentから移行
    - 改修範囲が狭くなるので順次リリースが簡単にできる

という感じ。
この記事にたどり着いた時点で、この記事で言われているVertical Slicingな方針で考えていたので、そのやり方で良さそうという自信が持てた気がします


## 既存のコードベースのうち、移行にあたって障害になりそうな部分の調査

主にリファクタの方針を定めるための調査。
既存のコードベースによってここのボリュームが全然違うはずなので、残しておいてもあまり参考にはならないとは思いますが一応書き記しておきます。

### そもそも良くないコードを探して修正

共通で利用すべきComponentが使われていない等

### 老化チェックの記事の理想地点へ到達できていないところ

これに関しては後から`ng-controller` -> component -> ng2の手順を追うより`ng-controller` -> ng2の方が手間が少ない箇所が多いと判断して作業中断してます
ng2化するにあたってcomponent記法使ってても結局書き直すじゃん、という話ですね

### $compile,link使ってるところ

**滅ぼせ**
...とはいえ、bindToControllerにしてもControllerのconstructorに単純に移動するだけのものは特に手を付けないことにしました(老化チェック〜の項目と同じ理由より

### `ng-controller`が入れ子になっている部分

流石にこれはComponent化しないとダルい

例：

```html
<div ng-controller="ParentCtrl as ctrl">
  <div ng-controller="ChildCtrl as childCtrl">{{childCtrl.hoge}}</div>
</div>
```

### $http周り

Angularには`$httpProvider`によるHTTPリクエスト時の共通の処理を定義する機構はないという認識だったため、移行のために何らか考える必要がありそうでした

それっぽい記事( http://www.adonespitogo.com/articles/angular-2-extending-http-provider/ )があったので、これを参考に自前のHttpServiceを定義すれば良さそうという見立てをしました

余談ですが、このプロダクトではhttpリクエスト飛ばすServiceを受ける側はほぼ.success/.errorを利用しています
AngularJS1.6だとこの.success/.errorは削除されたAPIになってるんですが、無理にこの対応をしていたら完全に無駄足だったのではと思ってます（ng2化するなら.then/.catchにしていたところでどっちにせよ手直しが必要なので）

### `angular`から生えてるUtility関数使ってる部分の調査

意外と使われてた・・・だるい・・・copyとかforEachとか便利だもんね。。。
代替手段はまあなんでもいいと思ってますが誰かいいのあったら教えてください（雑

### filter周り

ng2のPipeにはfilterやorderByがないため、これらの機能を使っている場所ではデータを持っている側でフィルタリングやソートを実装する必要がある

### ライブラリの利用状況など

bower.json内でAngularJSに依存してるライブラリをピックアップして、使用箇所を特定、移行に際してどのぐらい障害になりそうかを調査
移行作業に入った段階で乗り換え先を調べれば充分っぽいのと、事前に調査必須っぽいのを仕分けするのが目的です
この調査により主にangular-bootstrapとangular-ui-selectが壁であることがわかりました（自明

なお、具体的な移行先ライブラリについてや移行時の記述の方法は後回しにしてます（記事を書いた時点でまだ調査中）
-> どうせリファクタで時間かかるので後回しにしても害はないため

### エントリポイントの構成

エントリポイントのhtmlはサーバサイドでtemplateをレンダリングしたものという構築、かつサーバ側の変数がしれっと混ざっていたり、その他SPA的にはあんまりない仕様が混ざり込んでいました。
angular-cliが使えるようなプレーンなhtmlにする必要がありそうだということと実際にどうすればいいかの設計などをしました

## 実際にハイブリッドアプリの起動を試す

具体的にどうコードを書けば動くのかを調査するために、プロダクトのコードでハイブリッドアプリを動かしてみました。
ここではビルドの構成などは超雑でもかまわないからとりあえず動かして調査、が目的になります
これによって考えた方針の検証や、実際に手を動かしてみて移行作業についてより具体的にイメージを持てました

やったこと

- 各種Angularのパッケージのインストール
- tsconfigの調整
    - `emitDecoratorMetadata`をtrueにしたり
- bootstrapingのコード、`NgModule`、`Component`とpolyfill郡を用意
- 実際に1ページだけ置き換えをしてみる
    - 仮なので他のComponentとかはコメントアウトしたりしまくってとりあえず最低限動かすだけ


# まとめ

というわけでAngular移行のために調べたことをまとめました。
実際の移行方針決定はほぼここで調べた結果を元に行っています。
その方針の内容や、ng1->ng2の具体的な書き方などは別途まとめようと思います