初めてTypeScript&Angularに手を出すことになり、開発環境を構築しましたので初心者目線から構築手順をシェアします。
僕のMacには、HomebrewもVisual Studio Codeもすでにインストールされているので以下の手順はその前提です。また、全てのコマンドはVSCode内のターミナルから実行しています。なお、本記事で対象としているバージョンは以下の通りです。
- macOS: High Sierra 10.13.6
- Node.js: 10.12.0
- TypeScript: 3.1.3
- Angular CLI: 6.2.5
- Angular: 6.1.10
- Karma: 3.0.0
- Jasmine: 2.99.0
- VSCode: 1.28.1
Node.jsのインストール
まずNode.jsをインストールします。Node.jsが入っているかどうか分からない場合は、以下のコマンドでバージョンを確認します。バージョン番号が返されればインストールされています。
$ node -v
-bash: node: command not found
@kyosuke5_20 さんの MacにNode.jsをインストール を参考に、以下の3点に注意してしてインストールします。
-
nodebrew install latest
コマンドが失敗する
nodebrewで最新のnodeをインストールしようとした際に ”Failed to create the file” というエラーが発生した場合は、mkdir -p ~/.nodebrew/src
のようにディレクトリを作成しましょう。 -
インストールしたnodeにパスを通す
インストールしたnodeにパスを通す際に、permission deniedで書き込みできないことがあります。その場合は以下のようにsudoを使いましょう。
$ sudo echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
-
インストールしたnodeの有効化
インストール直後には使用するバージョンが有効化されていません。忘れずにnodebrew use %バージョン%
で使用するバージョンを指定しましょう。
TyepScriptのインストール
Node.jsのインストールが終わるとnpmが使えるようになります。以下のコマンドで TypeScript をインストールしましょう。
$ npm install -g typescript
Angular-CLIのインストール
続いてAngularのコマンドラインツールをインストールして、基本的な構成の初期プロジェクトを新たに作りましょう。新しいプロジェクトを作成すると一緒にAngularのライブラリ群もインストールされます。便利です。
$ npm install -g @angular/cli
以下のコマンドを使って基本的な構成でプロジェクトを作成します。プロジェクト名に"_"(アンダースコア)は使用できません。エラーになります。プロジェクト名の単語区切りはハイフンを使いましょう。
$ cd /path/to/projects
$ ng new %プロジェクト名%
プロジェクトフォルダができあがり、各種ファイルが初期状態で作られます。できあがったサンプルは以下のコマンドで起動しブラウザ上に表示させることができます。
$ ng serve --open
この画面が表示されたということは、環境面はバッチグーということになります。
ちなみにアプリを終了するには Control+C
です。
Visual Studio Codeおよびプロジェクトの設定
ここからは、TypeScriptアプリケーションの開発環境であるVSCodeで、機能拡張のインストールとプロジェクト環境セットアップを行ないます。
インストールした機能拡張
VSCodeには以下の機能拡張をインストールしてあります。実際にまだコードを書き始めていないのでこれから追加でインストールするかもしれませんが今の所は最小限の追加にとどめています。
-
Debugger for Chrome
Chromeでデバッグする際の必須ツールのようです。まだデバッグしたことがないのでよく分かっていません。 -
TSLint
TypeScript用の静的コード解析ツールです。TypeScript素人なのでコーディング規約から外れていないかツールに教えてもらわないとよく分かりません。
tsconfig.jsonの設定
tsconfig.json
ファイルには、TypeScriptをJavaScriptにコンパイルするための設定情報が含まれ、プロジェクトのルートに置かれます。oaTypeScript初心者の僕には内容を説明できないので @tomof さんの js STUDIO を参照してください。ちなみに、 tsc --init
を使用した場合と Angular CLI
の ng new
を使用した場合で、できあがるtsconfig.jsonは以下のように異なっているようです。
tsc --init
で作成されたtsconfig.json(コメントアウト除外)
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true
}
}
Angular CLIの ng new
で作成されたtsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"module": "es2015",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2017",
"dom"
]
}
}
この差がどう影響するのか今の僕にはよく分からないので、とりあえずAngular CLIが出力したデフォルトのまま使用してみます。また、この設定だとコンパイル済みのテストコード(〜.spec.ts)とソースコード(〜.ts)のコンパイル結果が、同じ出力ディレクトリに吐き出されそうで不安な気持ちになります。
2018年10月23日更新
@k3nNy_51rcy さんからコメント欄で解決策を教えてもらいました。ありがとうございました!
コンパイル時に
tsc
ではなくng build
を使えば、spec.tsファイルはビルド対象から外されて出力ディレクトリには出力されません。spec.ts
ファイルのビルドを除外する方法で著名なのは、tsconfig.json
に以下のような除外設定を書く方法ですが、これだとng test
実行時にダンマリになってしまいます。
tsconfig.json"exclude": [
"**/*.spec.ts",
],
ng build
はテストコードの除外設定があるtsconfig.app.json
を使い、ng test
は除外しない設定のtsconfig.spec.json
を使うという仕組み(angular.jsonの設定)になっています。ですからAngular CLIで作成したプロジェクトではルートのtsconfig.json
でテストコードの除外を設定する必要がなく、単純にng build
を実行するだけで万事解決です。
テストとソースのフォルダを分けるJava、プロジェクトそのものを分けるC#のテストに慣れた身からすると何となく嫌な感じがするのですが、それもTypeScriptプロジェクトの流儀だということなら慣れたいと思います。何事も食わず嫌いは良くないですしね。😅
task.jsonでビルドの設定
以下のようにコマンドパレットに"task"と入力するとリストが表示されるので、規定のビルドタスクを構成する
を選択します。
すると以下のリストが続けて表示されるので、プロジェクトルートのtsconfig.jsonを指す tsc:ビルド
を選択します。
すると .vscode/task.json
が以下のようなデフォルト状態で作成されます。
{
"version": "2.0.0",
"tasks": [
{
"type": "typescript",
"tsconfig": "angular-sample/tsconfig.json",
"problemMatcher": [
"$tsc"
],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
ここでターミナルから tsc
と入力するか、 Command+Shift+B
を入力するか、"ターミナル"メニューから”ビルドタスクの実行"を選択すると、tsファイルがビルドされ、 tsconfig.json
の outDir
に設定されているディレクトリ(上記例では dist/out-tsc
)にjsファイルが出力されます。
launch.jsonでデバッグ起動の設定
続いて、デバッグ起動の設定を行います。アクティビティバーでデバッグアイコンをクリックするとサイドバーに構成がありません
と表示されています。
該当コンボボックスをクリックすると、以下のようなリストが表示されるので該当のプロジェクト(この例では angular-sample
)を選択します。
さらに、コマンドパレットで、該当プロジェクトのデバッグで使用する実行環境を Chrome
と選択します。
すると、.vscode/launch.json
が以下のようなデフォルト状態で作成されますので、url欄のポート番号は8080ではなく4200に変えてください。これは後述するAngular Live Development Serverのデフォルトのリッスンポートが4200だからです。
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
// 8080を4200に変えること!
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}
ここまで設定が完了したら、まずVSCodeのターミナルに ng serve
と入力して "Angular Live Development Server" を起動します。"Complete Successfully" とういうメッセージがターミナル上に表示されたら、F5を入力するかデバッグ開始ボタンをクリックしてデバッグを起動してみましょう。
無事、Chromeで上記のようなページが表示されました。デバッグ時にいちいち ng serve
を実行するのは面倒ですが、一度起動してしまえばずっとそのままで良いのであまり気にならないかもしれません。
ユニットテストの設定
JavaでもC#でも、長年ユニットテストを書いてきましたしカバレッジも80%以上をキープしてきました。TypeScriptでも同じようにユニットテストを実施して品質を保証したいと思います。ありがたいことに、Angular CLIで作られたプロジェクトには、ユニットテストがすでに組み込まれていますので特に何も設定する必要がなく、ただ単に以下のコマンドでテストを走らせるだけです。
$ ng test
Chromeが自動的に起動してユニットテストを実行します。Chrome画面には以下のようにテスト結果が表示されますが、かなり見にくいのでなんとかしたいところです。
さらに、カバレッジを計測してくれるオプションがあります。ユニットテストの実行コマンドに以下のようなパラメーターを付加すると、カバレッジを計測して結果を coverage
ディレクトリにHTML形式で書き出します。
$ ng test --code-coverage
出力されるHTMLは以下のようなものになります。この例では、src/appの分岐条件網羅率がよろしくないという結果になっています。
一覧
具体的なコードを見てみると、app.component.tsに"22"の条件分岐があり"10"しかテストされていないことになっています。このソースのどこに条件分岐が22もあるのかと問いたい。小一時間問い詰めたい。(.jsの方を見ろというのはわかっています)
コード
賛否両論あると思いますが、はっきり言って見にくいです。C#でOpenCoverとかDotCover、JavaでCloverとかEclEmmaを使っていた身にはキツイです。HTMLのページで、カバーされていないと判定された箇所を確認し、該当のソースを開いて修正するというUXも好きになれません。
そこで、VSCodeの機能拡張から Coverage Gutters というプラグインをインストールします。これで以下のようにカバーされているか否か直接ソースコード上で確認できるようになり、かなり好みのUXになってきました。
さらにkarma.conf.js
の以下のセクションに手を加えると閾値を設定することができます。以下の例では全部80%以上であることを強制する仕様になります。
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true,
thresholds: {
statements: 80,
lines: 80,
branches: 80,
functions: 80
}
}
もし、一つでも80%を切っている項目があれば、Coverage for branches (45.45%) does not meet global threshold (80%)
のようなメッセージがターミナルに表示されます。
また、コードカバレッジを毎回ng test --code-coverage
で実行するのも面倒なので、angular.json
のtest
セクションに以下の記述を追加すると、テスト実行時に自動的にカバレッジも計測されるようになります。
"test": {
"options": {
"codeCoverage": true
}
}
最後にエンド・ツー・エンドです。ユニットテストではなく画面操作から一連の流れを、Seleniumを使用してテストする場合は以下のコマンドを実行します。
$ ng e2e
テストの初期化を行い、Chromeが起動してWelcome画面を表示した後、自動的にChromeが終了します。うちでは、エンド・ツー・エンドのテストはVSTSのUIテストを使うんだけど、ひょっとしたら中身は一緒かも?(よく分かってないので後で調べます)
終わりに
これで環境構築はひとまず終了です。テストコードがソースと同じ場所にあることや、インデントがスペース2つという文化、さらにコードカバレッジのコレジャナイ感に馴染まなければいけないと思うと気が重いですが、おいちゃんがんばります。