Angular プロジェクトを新規作成したとき 生成されるファイルの役割を説明していく
サーバーサイドアプリケーションの動作確認やデモのために Angular を触っています。Angular は、 anglar-cli を用いることで、雛形の生成や開発に必要なファイルの追加といったことがコマンドラインから行えます。
「雛形を作ったときに一緒に生成されるファイルのことをよく知らないな」と思い、調べて記録することにしました。
バージョン情報
$ npm install -g angular-cli@latest $ ng version _ _ ____ _ ___ / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | | / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | | /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___| |___/ @angular/cli: 1.2.0 node: 8.1.0 os: darwin x64 @angular/animations: 4.2.5 @angular/common: 4.2.5 @angular/compiler: 4.2.5 @angular/core: 4.2.5 @angular/forms: 4.2.5 @angular/http: 4.2.5 @angular/platform-browser: 4.2.5 @angular/platform-browser-dynamic: 4.2.5 @angular/router: 4.2.5 @angular/cli: 1.2.0 @angular/compiler-cli: 4.2.5 @angular/language-service: 4.2.5
対象とするプロジェクト
angular-gstream-app
というプロジェクトを作ることにします。
$ ng new angular-gstream-app
$ tree -a -L 1 . ├── .angular-cli.json ├── .editorconfig ├── .gitignore ├── README.md ├── e2e ├── karma.conf.js ├── node_modules ├── package-lock.json ├── package.json ├── protractor.conf.js ├── src ├── tsconfig.json └── tslint.json
e2e, protractor.conf.js
$ tree -a -L 1 . ├── .angular-cli.json ├── .editorconfig ├── .gitignore ├── README.md ├── e2e # directory ├── karma.conf.js ├── node_modules ├── package-lock.json ├── package.json ├── protractor.conf.js # file ├── src ├── tsconfig.json └── tslint.json
これらのファイルは Protractor という Angular 向け E2E Test のためのツールで利用します。 E2E Test とはエンドツーエンドテストのことで、ウェブアプリケーションのコンテキストでは「ブラウザを起動し、実際にユーザーが利用する状況と同等の操作を行った結果をテストする」を指すようです。Angular ではプロジェクトを作成した段階ですでに実行可能なようになっています。
- e2e ディレクトリ
- protractor.conf.js
e2eディレクトリ
まずは e2e ディレクトリの中をみます。
tree -a -L 1 e2e/ e2e/ ├── app.e2e-spec.ts ├── app.po.ts └── tsconfig.e2e.json
app.e2e-sepc.ts
- app: app Component の
- e2e-spec: E2E Test を実行する
- ts: TypeScript ファイル
ということで、テストを実行したときに OK, NG 判定が行われるのはこのファイルです。新しいパターンのテストを追加しようと思ったら、このファイルを修正することになります。
app.po.ts
po とはどうやら Page Object を指すようです。つまりこのファイルは、ユーザーの操作をコードで表現することが役割です。ページ遷移やテキストの抽出、フォームへの入力など、ページでテストしたいアクションがあったら、まずはこのファイルを修正し、そのあと app.e2e-spec.ts
ファイルを修正します。Page Object の考え方は Selenium ブラウザテストツールを使っている方は馴染みがあるかもしれません。
tsconfig.e2e.json
tsconfig.xxx.json
が存在するディレクトリは、そのディレクトリが TypeScript プロジェクトであることを示します。ということは、この e2e
ディレクトリを、アプリケーションとは別の TypeScript プロジェクトとして実行している人がどこかにいるということになります。
protractor.conf.js
e2e ディレクトリを TypeScript のプロジェクトとして実行するための設定が書かれていました。ファイルの一部を抜粋すると、
onPrepare() { require('ts-node').register({ project: 'e2e/tsconfig.e2e.json' }); jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); }
このような記述があり、「 e2e/tsconfig.e2e.json
をルートとする TypeScript プロジェクトを ts-node
を使って実行せよ」という指示になります。後述しますが、 .angular-cli.json
に 「E2E Test 実行のときに protractor.conf.js を使え」という記述があるため、ng e2e
とコマンドを打つことで E2E Test が実行できるという理屈です。
ユースケース
E2E Test を実行する
$ ng e2e ...(中略)... [15:03:46] I/launcher - Running 1 instances of WebDriver [15:03:46] I/direct - Using ChromeDriver directly... Jasmine started angular-gstream-app App ✓ should display welcome message Executed 1 of 1 spec SUCCESS in 1 sec. [15:03:50] I/launcher - 0 instance(s) of WebDriver still running [15:03:50] I/launcher - chrome #01 passed
参考サイト
- Protractor: end-to-end test framework for Angular and AngularJS applications.
- Using Page Objects to Overcome Protractor's Shortcomings | ThoughtWorks
- tsconfig.json
.angular-cli.json
.angular-cli.json
は、 Angular のコマンドラインツール ng
コマンドを実行する際に利用する設定ファイルです。スキーマ情報はこちらにあります。主な記述を抜粋すると以下です。
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "project": { "name": "angular-gstream-app" }, "apps": [ { "root": "src", "outDir": "dist", "assets": [ "assets", "favicon.ico" ], "index": "index.html", "main": "main.ts", "polyfills": "polyfills.ts", "test": "test.ts", "tsconfig": "tsconfig.app.json", "testTsconfig": "tsconfig.spec.json", "prefix": "app", "styles": [ "styles.css" ], "scripts": [], "environmentSource": "environments/environment.ts", "environments": { "dev": "environments/environment.ts", "prod": "environments/environment.prod.ts" } } ], "e2e": { "protractor": { "config": "./protractor.conf.js" } }, "lint": [ { "project": "src/tsconfig.app.json" }, { "project": "src/tsconfig.spec.json" }, { "project": "e2e/tsconfig.e2e.json" } ], "test": { "karma": { "config": "./karma.conf.js" } }, "defaults": { "styleExt": "css", "component": {} } }
- "e2e": E2E Test のために利用する設定ファイルを指定します。プロジェクト生成時には "./protractor.conf.js" が指定されています。
- "test": Unit Test のために利用する設定ファイルを指定します。プロジェクト生成時には ./karma.conf.js" が指定されています。
参考サイト
- angular-cli
- angular/angular-cli: CLI tool for Angular
- angular-cli/schema.json at master · angular/angular-cli
.editorconfig
EditorConfig は、異なるIDE・エディタで共通して利用できる設定ファイルです。例えばインデントサイズや末尾空白を除去するといった設定を書けます。この設定ファイルを編集しリポジトリへ一緒にPushすることで、チームメンバー間のコードスタイルを維持することができます。私が普段利用している IntelliJ でも対応していました。
参考サイト
.karma.conf.js
Karma は、 Unit Test を実行するためのツールです。実行結果のレポートなど、たいていのツールはコンソールへ出力するところ、Karma はブラウザ上にレポートしてくれます。 ふつうは karma
コマンドで Unit Test を実行しますが、 Angular プロジェクトでは、 .angular-cli.json に設定を書くことで ng
コマンドから Karma を起動できます。
ユースケース
Unit Test を実行してブラウザ上でレポートを確認する
$ ng test 10% building modules 1/1 modules 0 active05 07 2017 10:19:35.023:WARN [karma]: No captured browser, open http://localhost:9876/ 05 07 2017 10:19:35.040:INFO [karma]: Karma v1.7.0 server started at http://0.0.0.0:9876/ 05 07 2017 10:19:35.041:INFO [launcher]: Launching browser Chrome with unlimited concurrency 05 07 2017 10:19:35.049:INFO [launcher]: Starting browser Chrome 05 07 2017 10:19:44.638:WARN [karma]: No captured browser, open http://localhost:9876/ 05 07 2017 10:19:44.871:INFO [Chrome 59.0.3071 (Mac OS X 10.11.6)]: Connected on socket BC8Gn7N2JRb61-WoAAAA with id 56513096 Chrome 59.0.3071 (Mac OS X 10.11.6): Executed 4 of 4 SUCCESS (0.308 secs / 0.276 secs)
これでブラウザが起動します。
参考サイト
package.json, package-lock.json
node.js の package 管理ツールである npm が使います。package.json がある ディレクトリで npm install
を実行すると package をインストールできます。
package-lock.json は、npm5 から導入されました。
$ npm -v 5.0.3
package-lock.json は、pakcage.json だけでは対処できない、開発時と本番リリース時でpackageのバージョンが異なる可能性がある という問題に対処するためのファイルです。package.json では、「パッチバージョンは最新のものをダウンロードする」「メジャーバージョンのみ固定し、あとは最新のものを使う」といった書き方が可能です(^2.0.0, ~2.1.4等)。わざわざ package.json を手で修正することなくコマンドひとつでアップデートできる一方、「開発時は v2.1.4 でテストしていたのに、リリース時になって v2.2.0 になり、これまで行ったテストが一部やりなおしになりそうだ…」といったシーンに遭遇します。package-lock.json は、依存 package 含め node_modules 以下にあるすべての package のバージョンを記録しています。開発者が明示的に npm update
を実行しない限りは、package-lock.json も変更されず、どの環境でも npm install
で導入される package は決まったバージョンになるというわけです。
package.json と同じように、package-lock.json もプロジェクトのリポジトリへ一緒に Push すると良いでしょう。
参考サイト
- package-lock.json | npm Documentation
- npm shrinkwrapを運用で使うためのコツ - Qiita
- npm v5 がリリースされた - from scratch
tsconfig.json
このプロジェクトが TypeScript プロジェクトであること示すと同時に、コンパイルターゲットやコンパイル時の設定を記載します。
{ "compileOnSave": false, "compilerOptions": { "outDir": "./dist/out-tsc", "baseUrl": "src", "sourceMap": true, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "typeRoots": [ "node_modules/@types" ], "lib": [ "es2016", "dom" ] } }
- compilerOptions.baseUrl: コンパイルターゲットのベースとなるディレクトリを指定します。ここでは
src
です。 - compilerOptions.target: コンパイル先の ECMAScript バージョンを指定します。ここではES5を指定しています。
- compilerOptions.typeRoots: コンパイル時に利用する型情報として使うファイルのありかを指定します。 "node_modules/@types" なので、各 package に含まれる型情報を使う、ということになりそうですね。
参考
- TypeScript-Handbook/tsconfig.json.md at master · Microsoft/TypeScript-Handbook
- Compiler Options · TypeScript
tslint.json
TypeScriptのための静的解析ツール TSLint の設定ファイルです。 ng
コマンドでプロジェクトを生成した場合 tslint.json も一緒に生成してくれます。そして、.angular-cli.json
によると、 ng lint
で tslint.json を使った静的解析をかけてくれるようです。コミット時に静的解析がかけられるよう、git の pre-commit hook で ng lint
を実行すると良いかもしれません。
$ ng lint Warning: The 'no-use-before-declare' rule requires type checking ERROR: /Users/wada.yusuke/.ghq/github.com/cm-wada-yusuke/developers-io-2017/angular-gstream-app/src/app/app.component.ts[9, 1]: Exceeds maximum line length of 140 Lint errors found in the listed files.
参考
おわりに
Angular だけでなく、多くのフレームワークでは、開発者が苦心することなくプロジェクトの雛形を作れるようになりました。効率が上がって便利な反面、自動生成されるファイルの意味を知っておかないと、いざ使うとなったときに正しい使い方ができなかったり、せっかく用意されているのに有効活用できずに開発を進めてしまうこともあります。今後もただ漫然と使っていくだけでなく、用意されたファイルや設定の意味を少しずつでも理解しながら開発していきたいと思います。