Angular 4アプリケーションをAngular 6に移行する
初めまして! カブクでアルバイトをしている長瀬です。普段はWebフロントエンド関連の業務をしています。
先日、Angular 4.3.6で動いていたアプリケーションを6.1.0へ移行した際に得られた知見を共有します。Angular/Angular CLI 6への移行に関する日本語記事は、すでに以下をはじめとするすばらしい記事が世に出ています(私も参考にさせていただきました)。
- Angular CLI v1.7からv6.0へのマイグレーションについて (for v6.0.0-rc.2)
- lacoさんの記事
- angular-cliの移行作業がまとまっている
- Angular6に移行メモ
- 5.2 -> 6.0の移行
- ngx-bootstrapなど、外部パッケージ関連の移行作業についても触れられている
この記事では、上記の記事で紹介されている内容(移行手順や移行により改善されたこと)に加えて、
– swagger-codegen(openapi-generator)を利用している場合に便利かもしれないtips
– Node.js向けにのみビルドされた、古いJSライブラリを使っている場合に必要となるかもしれない対応
を紹介します。同じような構成の方の参考になれば幸いです。
なお、Angularはすでに予定通り7.0.0-rc1をリリースしています。(移行作業を始めてから色々あり、だいぶ時間が経ってしまいました…)今後アップグレードを検討されている方はAngular7のリリース状況をチェックするようにしてください。
tl;dr
- Angular 4.3.6 -> Angular 6.1.0でビルド時間とバンドルサイズが大幅に改善された
- OpenAPI 2対応のswagger-codegenを利用しており、サーバサイドの実装の都合等でOpenAPI 3への移行ができない場合は、custom templateを使うと良い
移行のモチベーション
そもそも、移行はなぜ必要だったのかというと、
- Angular 4は2018/09/23でLTSが終了する
- Angular 6は2019/11/03までLTSが継続する
- Angular 5.0.0のリリースには@angular/coreやコンパイラのパフォーマンス改善が含まれており、これを利用したい
- これまでのリリースでAngular, angular-cliに追加された機能を使えるようにしたい
という理由があったためです。また、Angularが依存しているRxJSなどのライブラリもメジャーアップデートがされており、それらに追従したいというモチベーションもありました。
やること
冒頭に挙げたfa11enprinceさんの記事でも紹介されているのですが、Angularには移行前・移行後のバージョンを指定すると移行作業のチェックリストを生成してくれる便利ツールがあります。
主にこれを利用して移行作業を進めていきました。ただし、update.angular.ioが教えてくれる手順はあくまで大まかなものであり、タスクによっては別途作業の詳細を調べる必要があるかもしれません。以降は私が移行作業で詰まった内容の一部を紹介します。
@angular/cliのアップグレード
update.angular.ioが教えてくれたタスクの1つに、"angular-cliをアップグレードし、angular.json(旧angular-cli.json)を新しい形式に書き換える"というものがあります。
丁寧にコマンドまで紹介してくれているのですが、このコマンドを使うよりも、冒頭で紹介したlacoさんの記事で紹介されているやり方を使うほうが良いです。
まずプロジェクトローカルのAngular CLIをアップデートする
yarn add --dev @angular/cli@^6.0.0-rc.2
ng update
コマンドでプロジェクトをv6用にマイグレーションする
ng update @angular/cli --migrate-only --from=1.7.3
いずれの操作でもangular-cli.json
が自動で新フォーマット(angular.json
)に変換されるのですが、--from=
というフラグでバージョンを指定してやると移行に失敗する(設定の一部が引き継がれず漏れてしまう)可能性が低くなるためです。
今回移行したアプリケーションはかなり細かく angular-cli.json
を設定していたため、--from
を指定してもなお引き継がれなかった設定があり、schema.jsonを読んで手動で設定ファイルを編集しました…
(schema.json
は文字通りangular.json
のスキーマについて記述したJSONファイルで、プロパティのdescriptionやtype等がわかります。エディタでの開発者支援や、今回のように設定ファイルを編集する際の参考にもなります。)
RxJSのアップグレード
Angularが依存しているRxJSも、メジャーアップデートによりbreaking changesがありました。よって既存のコードの修正が必要になるわけですが、@angular/cliと同様に、rxjs-tslint
パッケージが提供するcliコマンドによってある程度は自動で修正してくれます。
npm install -g rxjs-tslint
rxjs-5-to-6-migrate -p src/tsconfig.app.json
自動で修正してくれなかった箇所については、頑張る必要があります…
swagger-codegenを利用している場合の対応
弊社では多くのプロダクトにswagger-codegenを利用しています。今回移行するアプリケーションでは、swagger-codegenのAngular2用テンプレート(APIのスキーマに基づいて、TypeScriptの型定義等のファイルを自動生成するためのコード)を利用していました。当然移行に際してテンプレートもAngular6に対応する必要があるのですが、作業当時はswagger-codegenがAngular6に対応していませんでした(この記事を執筆し始めた日の5日前に対応されました)。
このとき、openapi-generatorというswagger-codegenのフォークは早くもAngular6に対応しており、当初はswagger-codegenからopenapi-generatorに移行してそのテンプレートを利用するつもりでした。しかし、APIサーバ側で利用しているPython向けのOpenAPIツールである、Yelp/bravado-coreがOpenAPI 3に対応していませんでした。よって、当時の段階では移行は不可能だとわかりました。
そこで、swagger-codegenのカスタムテンプレートという機能を利用して、OpenAPI 2互換のswagger-codegenでも、Angular6に対応したコードを自動生成できるようにしました。
swagger-codegenにおけるカスタムテンプレートの利用
カスタムテンプレートの解説については、すでにこちらなど多くの優れた日本語記事が公開されています。大まかに言うと、既存のテンプレートの一部を上書きして使えるようにする機能です。
今回は、RxJS, Angularのアップデートによって破壊的変更があった箇所を修正するなどの用途で使いました。
テンプレートファイルはあるディレクトリ(custom_tmpl
とします)にまとめて配置し、次のようにして使います。
java -jar ${SWAGGER_CODEGEN} generate -i spec.json -l typescript-angular -o ./ng_client -c config.json -t custom_tmpl
-l
でテンプレートの種類を指定し、-t
でカスタムテンプレートファイルが存在するディレクトリを指定しています。
カスタムテンプレートファイルは、-l
で指定したテンプレートのうち、上書きしたいテンプレートファイル名の拡張子を.mustache
に置き換えたファイル名で書いていきます。たとえば、テンプレートのpackage.json
をAngular6向けに書き換えたカスタムテンプレートはpackage.mustache
となり、以下のような内容になります。
{
"name": "{{{npmName}}}",
"version": "{{{npmVersion}}}",
"description": "swagger client for {{{npmName}}}",
"author": "Swagger Codegen Contributors",
"keywords": [
"swagger-client"
],
"license": "UNLICENSED",
{{#useNgPackagr}}
"scripts": {
"build": "ng-packagr -p ng-package.json"
},
{{/useNgPackagr}}
{{^useNgPackagr}}
"main": "dist/index.js",
"module": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": {
"build": "ngc",
"postinstall": "npm run build"
},
{{/useNgPackagr}}
"peerDependencies": {
"@angular/core": "^6.1.0",
"@angular/http": "^6.1.0",
"@angular/common": "^6.1.0",
"@angular/compiler-cli": "^6.1.0",
"core-js": "^2.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "^6.2.2",
"zone.js": "0.8.14"
},
"devDependencies": {
"@angular/compiler-cli": "^6.1.0",
"@angular/compiler": "^6.1.0",
"@angular/core": "^6.1.0",
"@angular/http": "^6.1.0",
"@angular/common": "^6.1.0",
"@angular/compiler": "^6.1.0",
"@angular/platform-browser": "^6.1.0",{{#useNgPackagr}}
"ng-packagr": {{#useOldNgPackagr}}"^1.6.0"{{/useOldNgPackagr}}{{^useOldNgPackagr}}"^2.4.1"{{/useOldNgPackagr}},{{/useNgPackagr}}
"rxjs": "^6.2.2",
"zone.js": "0.8.14",
"typescript": "~2.9.2"
}{{#npmRepository}},{{/npmRepository}}
{{#npmRepository}}
"publishConfig": {
"registry": "{{{npmRepository}}}"
}
{{/npmRepository}}
}
他のテンプレートファイルについても、RxJSのpipe()
を使うよう書き換えるなどして、Angular6 compatibleなカスタムテンプレートを用意しました。
その他の依存パッケージのアップグレード(およびそれに伴う修正)
TypeScript
RxJSのほかにAngularが依存しているパッケージとして、TypeScriptがあります。
Angular 2.x, 4.xなどのバージョンから移行する場合は、それに伴ってTSのバージョンも大きく上がる場合があり、コンパイルエラーが発生する可能性もあります。そうした場合には tsconfig.json
で一時的に当該ルールを無効にするなどして応急処置をするとよいでしょう。
Node.jsのshimに依存した古い外部ライブラリ
angular-cliは、内部でwebpack/node-libs-browser
を利用してNode.js向けライブラリが使えるようにしていました。しかし、移行後の6.xではこのshimが導入されなくなっており、いまだにブラウザ向けビルドを提供していないライブラリ(古いまま更新されていないOSSのライブラリなど)のビルドに失敗するという現象が確認されました。具体的にはjszipというライブラリです。
対処法として、当初はjszipが依存していたNode.jsのstream
をそのまま依存に追加していたのですが、ほかのエンジニアの方がjszipのソースコードに以下のような記載があることを教えてくれました。
We use "readable-stream" to get a consistent behavior between nodejs versions but bundlers often have a shim for "stream". Using this shim greatly improve the compatibility and greatly reduce the final size of the bundle
バンドラがstream
のshimを提供する場合は、互換性とバンドル後のファイルサイズの点でそちらを使うべきだとあります。node-libs-browserのREADMEを読むと、stream
のshimはsubstack/stream-browserify
のようですので、代わりにそちらを依存に追加しました。
成果
移行により、期待していたコンパイラの性能向上が反映されているか検証しました。
移行前 | 移行後 | |
---|---|---|
ビルド所要時間(s) | 116.49 | 37.72 |
main.bundle.jsのファイルサイズ(MB) | 2.0 | 1.3 |
コンパイラのパフォーマンスアップが有意に効いているようです。なお、移行したアプリケーションのコンポーネント数は115個でした。
最後に
移行作業は思っていたよりたいへんで一筋縄ではいかない作業もありましたが、カブクの優秀なエンジニアの皆様の助けをお借りし、なんとか移行作業を終えられました。日本でAngularの最新バージョンに食らいつき続けている会社さんは珍しいと思います(特にAngularJS -> Angularの移行は骨が折れるので…)。
カブクではAngular6で開発したいエンジニアを大募集中! だそうです!
その他の記事
Other Articles
関連職種
Recruit