Angular2アプリをGitHubからAzureのWebAppにVSTSを使ってデプロイする

#目的

Angular2でフロントエンドアプリを作成し、GitHubにソースを保存して、そこからAzureのPaaSであるApp Serviceを利用してアプリをホストするための一連の作業の手順を解説します。

使用するサービスは以下になります。

* GitHub/git
* Angular2
* NPM
* Azure App Service
* Visual Studio Team Services (VSTS) - 別名Visual Studio Online
 
#Angular2アプリのソースを準備する

##GitHubレポジトリにブランチを作る

このステップでは、Angular2アプリのソースを保存するためのレポジトリとブランチを作成します。ただし、既存のレポジトリとブランチを使っても良いので、その場合はこのステップはスキップしてください。

私は[demoという名前の既存のGitレポジトリ](https://github.com/yoshiwatanabe/demo)を使用しました。そこに、新規でangular2-demoという名前のブランチを作成します。ブランチはmasterでもいいんですが、混乱を避けるためにangular2-demoという名前を付けることにしました。

以下のコマンドをローカルのdemoレポジトリに移動した後、実行します。

`git checkout -b angular2-demo`

これでローカルのdemoレポジトリに[新規のangular2-demoブランチ](https://github.com/yoshiwatanabe/demo/tree/angular2-demo)が作成されました。
次にangularのHelloWorldアプリを作成します。

##Angular CLI を使って簡単なHelloWorldアプリを作る

Angular CLIがすでにインストールされていることを前提に進めていきます。

まずはアプリを作成します。以下のコマンドでアプリを生成します。

`ng new helloworld --inline-style --inline-template --skiptest`

上のコマンドの `--inline-style --inline-template --skiptest`の部分はオプションで、コンポーネントのスタイルとHTMLテンプレートが個別に生成されるのを抑制します。`ng new helloworld`だけでも構いませんが、今回はなるべく分かりやすいように、生成されるファイルの数を抑えることにしました。

以下、コマンドの実行結果です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/a80e7d95-2e80-b337-6908-e75ad751454c.png)

これでangularアプリの準備は出来ました。
次にGitHubのレポジトリにHellowWorldアプリのソースをいったん保存します。

##とりあえずGitHubレポジトリにpush

この段階でとりあえずGitレポジトリに`git add`と`git commit`して、さらにpushしておきます（`git add`と`git commit`コマンドの詳細はここでは割愛します）。
angular2-demoブランチはまだローカルにしか存在しないブランチなので、以下のようなpushコマンドでGitHub側のレポジトリにangular2-demoブランチを作成しながら、上のステップで作成したHelloWorldアプリのソースをアップロードします。

`git push --set-upstream origin angular2-demo`

これでソースコードのベースが出来ました。ここからいくつか順番に変更を加えていきます。

##web.configをプロジェクトに加える

AzureのWeb Appには.NET特有のweb.configという設定ファイルを加えなければなりません。下のスクリーンショットを参考に、web.configファイルをHelloWorldアプリに加えます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/768eb0a3-37a3-e96d-92f2-c7248ac1156f.png)

web.configの内容はこちら。

```xml:web.config
<configuration>
    <system.webServer>
        <rewrite>
        <rules>
            <rule name="redirect all requests" stopProcessing="true">
                <match url="^(.*)$" ignoreCase="false" />
                <conditions logicalGrouping="MatchAll">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
                </conditions>
                <action type="Rewrite" url="index.html" appendQueryString="true" />
            </rule>
        </rules>
    </rewrite>
    </system.webServer>
</configuration>
```

このweb.configではAzure Web Appに対するHTTPレクエストが全てindex.htmlファイルに行くように設定しています。このindex.htmlはangularアプリの本体ということになります。

次に、このweb.configがビルド時に正しくコピーされるように設定します。

##web.configがコピーされるようにangular-cli.jsonを変更する

angular-cli.jsonはAngular CLI（ngコマンド）を使用する際の様々な設定を指定するファイルです。
ここに静的なアセットとしてweb.configを加えることで、ビルド時にディストリビューションの一部になるように設定します。

下のスクリーンショットに従って変更を加えてください。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/1e9a865e-4f39-9e89-35d4-36175147a5a8.png)

これでビルド後にweb.configがアプリのルートフォルダにコピーされるようになりました。

次に本番環境用ビルドscript（コマンド）を新規で加えます。

##本番環境用のビルドscriptをpackage.jsonに加える

このステップは必須ではなく、すでに定義されている`build`というscriptを使っても全く問題はないですが、後でVSTSのビルド定義を設定するときにより分かりやすいように、すでに設定されていたコマンドとは別に新規で設定します。

以下のスクリーンショットを参考にして、npmのコマンドとして新たにbuild-prodというscriptを加えます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/33e5b0af-8b33-8694-fc9a-5e34f04e6499.png)

`-prod`オプションを加えることで本番環境用のコードを生成するようにしています。

次に、新規で加えた`build-prod`scriptを実行して、生成されるコードを確認します。

##本番環境用ビルドscriptをローカルで実行してアウトプットを確認する

上の手順で設定したbuild-prodコマンドを以下のように手動で実行します。

`npm run build-prod`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/298621ec-930b-af54-3ebf-5cad3425fd23.png)

上のスクリーンショットでは、`dist`という名前のフォルダーが作成されているのが確認できます。これが本番環境用ファイルを格納しているフォルダーです。このことは後でVSTSのビルド定義を設定する際、もう一度出てきますから覚えておいてください。

次に、いったん本番環境のことは脇に置いておいて、ローカルで開発する環境を確認しておきます。

##HelloWorldアプリをローカルで開発・実行

Angular CLIで作成したangularアプリの開発は極めて簡単です。以下のコマンドを実行するだけです。

`npm start`

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/52486de6-45f9-5bec-5ae4-2249fee0457b.png)

これでAngular CLIがビルドして、そのアウトプットをメモリ上に保存したのち、軽量なウェブサーバーを実行してHelloWorldアプリをホストしてくれます。この一連の作業を`start`というscriptに対応している、Angular CLIのコマンドである`ng serve`が実行してくれます（package.json無いを"start"で検索してください）。

ここでブラウザから`localhost:4200`をリクエストするとHelloWorldアプリのページがロードされます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/2874afc1-141e-7f83-1fec-e565b086be06.png)

では、開発サイクルを真似て、簡単な変更をくわえて見ます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/bb9fa01f-4596-db0c-b298-096b20c1839e.png)

`ng serve`のおかげで、ファイルに変更があったのを感知して自動的にビルドしてくれます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/a651291c-e1ab-6be4-ef47-cf543bc692fb.png)

変更が反映されたのが確認できます。

これでangular2のHelloWorldアプリは完成しました。変更をGitHubレポジトリにPushしておきます。

`git push`

つぎに、HelloWorldアプリをホストするためのAzure App Serviceを作成します。

#Angular2アプリのホストを準備する

##AzureのApp Serviceを作成する

Azure App Serviceは既存のものを再利用しても構いません。なので、このステップはオプションです。私は個人ようのHotmailアドレスで作ったフリーのAzureサブスクリプションを使って、tw-angular01という名前でApp Serviceを作成しました。

この作業の詳細は割愛します。下のスクリーンショットはこの記事で使うApp Serviceです。App Service Planについては、Angularアプリはスタティックなアプリなので、無料のもの（非力なVMを他のユーザと共有するパターン）でも十分です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/1f3bd78a-084b-58a0-465a-d34cf811964f.png)

これでデプロイのターゲットになるAzure App Serviceの準備が出来ました。

次にVisual Studio Team Services（VSTS）のビルド定義を設定する一連の作業に移ります。まずは、VSTSとGitHubの連携を設定するところから始めます。

#Angular2アプリをホストにデプロイするためのビルド定義を準備する

##VSTSにGitHubのためのService Endpointを設定する

この一連のステップには二つの前提条件があります。

1. すでにVSTS（以前はVisual Studio Onlineとも呼ばれていました）のアカウントがある。
2. すでに利用したいプロジェクトをVSTS内で作成済み。

VSTSは以前はVisual Studio Onlineとも呼ばれていました。まだない人はMicrosoftアカウント（例：hotmail、outlook.com）等のメールアドレスを使って新規でアカウント作成できます。
プロジェクトについては、既存のものでもデフォルトで設定されているものでも構いませんが、私はsamplesという名前のプロジェクトを作成しました。

VSTSのURL： https://www.visualstudio.com/vso/

VSTSプロジェクトが準備できたら、以下のスクリーンショットを参考にGitHub service connectionの新規作成画面まで進みます。

プロジェクト・レベルの設定アイコン（歯車アイコン）からServicesメニューアイテムを選び・・・
![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/2ede66b7-8dcc-255b-62fe-0301433e088a.png)

New Service EndpointドロップダウンメニューからGitHubを選択する。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/24011e8d-399f-2b63-1b10-13cf42872ed5.png)

そうすると下のようなダイアログが表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/ea65ba1d-5d60-de08-2891-f737792396c6.png)

Authorizeボタンを押し、指示に従ってシングルサインオンで許可を与えます。
Connection nameはなんでもいいんですが、githubyoshiwatanabeにしました。これは後でまた使うので、分かりやすい名前を選びました。

これでVSTSとGitHubの連携に必要なService connection（Service endpoint)が作成されました。

次にVSTSのビルド定義を作成します。

##新規のVSTSのビルド定義を作成する

VSTSのビルド定義の新規作成の詳細は割愛します。やり方は、トップレベルのBuild & Releaseメニューを選択したら分かります。私はsamples-angular-cli-CIという名前を付けました。

ビルド定義へのステップの追加は、下で詳しく解説するので、今は空の状態でもいいです。

下のスクリーンショットのように、ビルド定義リストで表示される状態なら完了です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/4edeb622-13ea-650b-546c-004fabdcfcb5.png)

次に、下のスクリーンショットのように、順番に3つのビルドステップを含んだビルド定義を設定していきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/ec43de0e-004c-1170-2d8c-96e3a3b2bba2.png)

まずはビルド定義に、どこからソースをダウンロードするかを指定します。

##Build DefinitionのGet SourceステップをGitHub

ここでは、先に設定したVSTSとGitHubを連携させるためのService connectionを利用します。

以下のように、GitHubをソースのfromとして選択し、次にレポジトリとブランチを指定します。ブランチは、angular2-demoというブランチを指定していますが、masterなど別のブランチをつかっても構いません（もちろん、そのブランチにangular2アプリがあるとして、ですが）。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/d93caa05-bd8c-4b21-5e53-02b8f3504774.png)

下は、対応するGitHubからみたレポジトリとブランチです。一応念のため、コンテンツを確認しておきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/5295c79c-651d-a66a-7bb4-38f91fcf1849.png)

ここからは、３つのビルドステップをひとつずつ順番に設定していきます。まずはnpmパッケージをダウンロードするステップ。

##1番目のnpm installステップを設定する

以下のスクリーンショットを参考に、npm installコマンドを実行するステップを設定します。気を付けるのはWorking folder with package.json（「package.jsonを含む作業フォルダ」）のフィールドに正しいパスを指定することです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/59d4fc99-a989-6e2d-19f8-0cea47d32c35.png)

次にHelloWorldアプリをビルドするステップを加えます。

##2番目のnpm customステップを設定する

Angularアプリはnpmのscriptを実行することでビルドします。CommandにCustomを選ぶことによって、任意のscriptを実行することができます。ここでは、先に設定した`build-prod`scriptを実行させることで本番環境用のアウトプットを生成させます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/3979c4e9-e11b-0a57-f1a0-fe75a97cc09b.png)

下は、対応するpackage.json内のbuild-prodというscriptです。Angular CLIのコマンド`ng build -prod`になっていることを確認します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/0e974334-777d-3268-df98-70224ec2ba2d.png)

これで「ソースをGitHubからダウンロードする」→ 「npmパッケージをインストールする」→「HelloWorldアプリをビルドする」という作業ステップが設定されました。

最後は、ビルドされたHelloWorldアプリをAzureのApp Serviceにデプロイするだけです。

##最後のステップ、Azure App Serviceへのデプロイを設定する

正しいAzureサブスクリプションを選択して、目的のApp Serviceを指定します。
ここでもっとも注意すべき点は、Package or Folderのフィールドに、helloworld/distと指定するところです。特に「dist」というフォルダを含んでいることを確認します。このフォルダはng build が実行された際に自動的に作成されるように設定されています。ローカルでng serveが実行された場合は生成されません（かわりにメモリ上にビルドされたファイルが保存されます）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/11472e6d-0025-eea2-0bd3-43cd62ce551b.png)

これでビルド定義の作成が完了しました。次は実際にビルド定義をキューしてビルドエージェントに実行をさせるだけです。

##ビルド定義をキューする

ビルド定義の画面からQueueボタンを選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/8fc67573-5307-c0a2-b5e9-e72712a91960.png)

エージェントにはHostedを選びます。ブランチも、今まで設定に使ってきたangular2-demoを指定します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/d38864ce-9eed-e612-79de-7e4e6abe1edc.png)

下のスクリーンショットは、ビルドがキュー（順番を待っている状態）された様子です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/c761aafb-210e-d93b-b2c2-e5110729635d.png)

下は、ビルドが成功した様子です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/41803960-06a7-abc8-baa8-889cc675183e.png)

最後のステップ（Azure Web Appにデプロイする）まで成功しているので、この段階でAzure Web AppにHelloWorldアプリがデプロイされて、表示可能な状態になっているはずです。

##Azure Web ServiceのURLを表示

実際にHelloWorldアプリを表示します。URLが分からない場合は、以下のようにAzure App ServiceのページからURLを取得できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/4754b774-38bb-34d1-f848-f8596148c91e.png)

ブラウザでURLのページをロードします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/10d59bf9-cdcd-777c-a361-a96d638e2cab.png)

うまく表示されました。GitHubレポジトリからのビルドとデプロイに成功しました。

これで設定は完了ですが、さらにGitHubのブランチに変更が加えられた（PushやPullリクエストによって）場合に、自動的にビルド→デプロイを行うContinuous Integrationの設定もやってましょう。

##Continuous IntegrationオプションをONにする

ビルド定義に戻って、Triggersの設定からContinuous IntegrationをEnabledにします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/d7d2e5b8-bdba-5222-702e-f0138ee74bf5.png)

HelloWorldアプリのソースに、ちょっとだけ変更を加えます。以下ではページのメッセージに"with CI"という文字列を加えました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/9d136a41-79fe-b832-4e33-61b55c522a81.png)

最後に、Gitで、add、commit、そしてpushします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/a98b7650-a929-055c-9a72-35bc8e4f2957.png)

この段階でビルド定義を見ると、自動的に新しいビルドがキューされているのが分かります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/194ee5eb-82fc-b22a-9e77-6e6fa75d3b27.png)

ビルドが完了したころを見計らってページを再ロードしてみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/103139/99feca34-281f-83c8-37e9-f2650b928d44.png)

pushした内容が反映されているのが分かります。この仕組みで、HelloWorldアプリの変更をGitHubのブランチへの変更だけで自動化しました。

実際のページ： http://tw-angular01.azurewebsites.net/

#まとめ
長くなりましたが、こんな感じでAngular2のフロントエンドアプリをAzureでホストできます。他のもっとシンプルな方法もあるかもしれませんが、Continuous Integrationも含めて設定をすれば、デプロイまでの作業が完全に自動化できるので、設定する甲斐はあると思います。