Angular2を書くためのAngularJSの書き方

Angular2のリリースが刻一刻と近づいてきました。しかし世の中のプロダクトは、まだまだ大半がAngular1.xで開発されています。Angular2はコンポーネント指向が徹底されていたり、TypeScriptが推奨の開発言語であるなど、Angular1から大きく変わっており、一見すると移行は容易ではありません。

しかしAngular1.xの最新バージョンである1.5では、Angular1から2への移行をスムーズに行うために、Angular2を見据えたコーディングが行えるようになっています。この記事ではAngular2への移行をスムーズにするための、Angular1の書き方を紹介していきます。

【編集部注】
※この記事は、2016年3月21日に開催された「ng-japan 2016」のセッション「Angular2を書くためのAngularJSの書き方」についての、講演者自身によるレポートです。講演内容に加えて、講演者自身による解説や追記によって、よりわかりやすく詳細な記事に仕上げていただきました。
※本記事では、AngularJSをAngular1、 AngularJSの2系をAngularと表記しています。

セッションの講演資料と動画はこちらになります。

講演資料

講演動画(2:03:46付近から始まります)

Angular1の歴史と背景

Angular1は、今から4年前の2012年6月に、バージョン1.0.0がリリースされました。この4年間に、Windowsなら8->10、Macで10.8->10.11、Androidで4->6、iOSで6->9という変化がありました。バージョンアップが比較的遅いとされるOSでも、4年の間にこれほど大きなバージョンアップが行われているのです。

現在のIT業界では、4年とはこれほど長い期間です。また4年前のWebを振り返ってみますと、当時はBackbone.jsなどのMVCフレームワークが全盛期でした。Angularはリリースされてから大きな人気を博し、世界中の数多くのプロジェクトで採用されました。

しかし月日は流れ、2014年にReactが発表されてからは、Angular1の人気にも陰りが訪れます。コンポーネント指向を採用したReactの優れた設計が広く支持されたこと、Angular1はパフォーマンスがあまりよくないということもあり、Reactを採用するプロジェクトも増えてきました。

そこでパフォーマンスを大きく改善し、アーキテクチャが刷新されたAngular2が今年中にリリースが予定されています。しかしAngular2は変更点が多く、普及には時間がかかることが予想されます。そのため、Angular1.xは当分サポートされることが決定しています。

Angular1とAngular2の違い

Angular1とAngular2の違いは多岐にわたります。その中でも代表的な違いを以下に挙げます。

  • 主な開発言語がJavaScriptからTypeScriptへ
  • Two-wayデータバインディングを廃し、One-wayデータバインディングへ
  • 従来のスコープに代わり、コンポーネントがUIの状態を保持する(コンポーネント指向)
  • テンプレートの文法が変更
  • 従来のng-routerからコンポーネントルーターに
  • 従来の文字列ベースのDI (Dependency Injection)から、型によるDIに

対象ブラウザに関して

Angular1.5は、残念ながらIE8以前では動作しません。IE8以前を対象とする場合は、Angular1.2を利用する必要があります。もしIE8を対象にしなくてよいのであれば、Angular1.5へのアップデートが強く推奨されます。

JavaScriptからTypeScriptへ

Angular2では、メインの開発言語がTypeScriptに変更されました。

簡単に経緯を説明しますと、もともとAngular2を開発する際、JavaScriptのスーパーセットであるAtScriptという言語を同時に開発していました。

AtScriptの実体は、アノテーション付きのTypeScriptと言ってよいものでしたが、開発は難航。2015年3月にTypeScriptが(アノテーションに近い機能である)デコレーターの実装を表明すると、Angular2はTypeScriptへと移行したという流れがあります。

実際には、Angular2にとってTypeScriptは必須ではなく、JavaScriptやDartでも開発は可能です。しかしTypeScriptを利用すると多くのメリットがあるので、TypeScriptの使用が推奨されています。

ちなみに、TypeScriptというのは以下のような特徴を持った言語です。

TypeScriptの特徴

  • 型がある
  • インターフェースがある
  • モジュールインポートがある
  • 仕様がしっかりしている
  • JavaScriptのスーパーセットである
  • TypeScriptはそのままではブラウザでは利用できないのでコンパイル(JavaScriptへの変換)が必要

BrowserifyやWebpackを使おう

皆さん、GruntやGulpと言ったタスクランナーを既に使われている方は多いと思います。Angular1.5 / 2の開発では、TypeScriptのimport文を使用してモジュール間の依存性を記述していくため、こうした依存関係を解決して実行可能なプログラムを生成できるツールが必要です。

そうしたツールにはBrowserifyやWebpack、System.jsなどがあり、import文やCommonJSのrequire()関数などを解釈し、依存関係を解決した上で、ファイルを一つにまとめる機能を持ちます。

TypeScriptからのコンパイルなどもプラグインとして提供されており、今後のAngular開発には必須のツールとなっています。

Angular1.5のコードを眺める

Angular2とAngular1の違いや開発に必要な情報が一通り揃ったところで、実際にAngular1.5のコードを眺めてみましょう。 以下は、画面に「Hello」と表示するだけのプログラムです。

Angular1のコードには違いないように見えますが、これまでとは何かが違いますね。

実際上のコードはTypeScriptで書かれており、importclasspublicなどのアクセス指定子など、素のJavaScriptでは使えない文法が多く使われています。

DirectiveからComponentへ

Angular2から、コンポーネントという概念が登場します。それに合わせて、Angular1.5でもコンポーネントが利用できるようになりました。Angular1のディレクティブに比べて、簡単に作ることができます。

DirectiveとComponentでの設定値の違い

Directiveには先述したComponentと呼ばれるDOMの生成と他にAttributeに設定する処理ng-repeatやng-showなども同じ方法で作成しています。

そのため、Componentを作るには設定が過多気味であり、Angular2へ移行する場合に必要なものと不必要なものをより分けた作成メソッドを新たに追加されました。

以下の表が元々のDirectiveメソッドと追加されたComponentメソッドとの設定の違いとなります。

DirectiveComponent
bindingsNoYes (binds to controller)
bindToControllerYes (default: false)No (use bindings instead)
compile functionYesNo
controllerYesYes (default function() {})
controllerAsYes (default: false)Yes (default: $ctrl)
link functionsYesNo
multiElementYesNo
priorityYesNo
requireYesYes
restrictYesNo (restricted to elements only)
scopeYes (default: false)No (scope is always isolate)
templateYesYes, injectable
templateNamespaceYesNo
templateUrlYesYes, injectable
terminalYesNo
transcludeYes (default: false)Yes (default: false)

引用:https://docs.angularjs.org/guide/component

Angular1のパフォーマンス問題

Angular1のパフォーマンスが良くない理由ですが、その原因を挙げてみましょう。

  • Two-wayデータバインディングが重い
  • 状態の監視に伴うオーバーヘッド
  • dirty check
  • $digest loop

では、どうしたらよいのでしょうか?以下の様なアーキテクチャが推奨されていますが、Fluxアーキテクチャによく似ています。

one-way

では、このアーキテクチャに従ったコードのサンプルを紹介します。

まずはアプリケーションのエントリーポイントとなるHTML(index.html)です。これは、angular.bootstrap()を呼び出しているだけで、特に変わったことはしていません。ただし、list-cmpというタグを使用していることは覚えておいてください。

以下がサービスのコードです。このサービスは、アプリケーションのデータを保持しており、データの操作を行うことが可能です。

以下は、index.htmlで使用されていたlist-cmpタグ(コンポーネント)の実装です。内部で、さらにlang-cmpというタグ(コンポーネント)を使用しています。

また、Angular1で多用されていた$scopeはもう使われておらず、代わりにコンポーネントのコントローラーの参照である$ctrlが使用されています。基本的には、$scopeはもう使用してはならないものとして考えましょう。

最後に、lang-cmpタグの実装です。上のコードで指定されていたlang-changelang-deleteと言った属性が、langChangelangDeleteといったプロパティに対応しています。

コンポーネント指向のディレクトリ構造

コンポーネント指向になったことから、コンポーネント単位にまとめると見通しがよくなります。

テストについて

Angular2ではテストの基本セットがJasmineとなっていますので、Jasmineだと学習コストは少なくなります。

ルーティング

Angular1ではngRouteよりもui-routerがよく使われていると思いますが、Angular2では性能と管理が簡単なComponentRouterが登場します。 Angular1.5用のComponent Routerが用意されています。

まとめ

このセッションで学んだことを最後にまとめます。

  • Angular1のプロジェクトでもTypeScriptを使おう
  • タスクランナーを利用しましょう
  • Webpackやbrowserifyを利用しましょう
  • DirectiveからComponentに変更しよう
  • controllerの廃止
  • Scopeは原則利用しないように
  • Two-way data-bindingよりOne-way data-binding
  • コンポーネント単位でファイルを整理しよう
Powered byNTT Communications

tag list

アクセシビリティ イベント エンタープライズ デザイン ハイブリッド パフォーマンス ブラウザ プログラミング マークアップ モバイル 海外 高速化 Angular2 AngularJS Chrome Cordova CSS de:code ECMAScript Edge Firefox Google Google I/O 2014 HTML5 Conference 2013 html5j IoT JavaScript Microsoft Node.js Polymer Progressive Web Apps React Safari SkyWay TypeScript UI UX W3C W3C仕様 Webアプリ Web Components WebGL WebRTC WebSocket WebVR