5分でAngularチュートリアルアプリをFirebaseにデプロイする方法

Angularの基礎を理解するのに役に立つ[Angularチュートリアルアプリ](https://angular.jp/tutorial)自体は、
Node.jsとAngular CLI環境が揃えば、簡単にローカルでは実行できます。
これをFirebase上にHostingさせることで、Firebaseが簡単に利用開始できる感覚を掴むことができます。

ポイントは、Angularコマンドでアプリプロジェクト依存関係解決とビルドを行い、さらにFirebaseにデプロイする情報をFirebaseコマンドで与えるということです。

# 前提条件
* Firebaseのアカウントが作成済みであること



# 環境準備
コマンドを実行するクライアント端末はMac、Win、Linuxでも問題ないはずですが、今回はMac環境で実行します。
## Node.jsのインストール
Angularを使用したアプリケーションではNode.jsが必要です。[^1]
[^1]: Angularでは分かりやすく開発するために、モジュールはts(TypeScript)ファイル、cssファイル、htmlファイルに役割を分離させて開発します。TypeScriptなので厳密な型チェックやクラスの概念を利用して、安全にプログラミングができます。しかし実際のデプロイ環境では、変換された可読性が低いjsファイル、cssファイル、htmlファイルで動作します。この変換をするためにNode.jsモジュールが必要になると理解しています。（間違っていましたらご指摘ください。）

https://nodejs.org/en/ からのNode.jsをインストールします。
2019.05.26時点では最新のLTSでOKです。公式が案内するバージョンについては以下を確認してください。

>Angularには、Node.js バージョン8.xまたは10.xが必要です。

https://angular.jp/guide/quickstart#prerequisites 

## Angular CLIのインストール
npm パッケージマネージャー(Node.jsのインストールに付属)で、Angular CLIをグローバル環境にインストールします。

```
sudo npm install -g @angular/cli --unsafe-perm
```
自分のMac環境ではsudoと--unsafe-permを入れないと以下のエラーが出ました。

```:エラー出力結果
npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/@angular/cli
```

バージョン確認コマンド

```
ng --version
```
```:出力結果
     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 7.3.9
Node: 10.15.3
OS: darwin x64
Angular: 
... 
~~
```


## Firebaseツールのインストール
同様にnpmコマンドでグローバル環境にインストールします。

```
sudo npm isntall -g firebase-tools --unsafe-perm
```

バージョン確認コマンド

```
firebase --version
```

```:出力結果
6.10.0
```
# ローカルでAngularチュートリアルアプリを動作させる
Firebaseで動作させるだけなら本来は不要です。
ただ、実際の開発では一般的にローカルで確認してから、Firebaseにデプロイすることになるので、ローカルでも一度動作させます。

## 完成されたチュートリアルアプリをダウンロード
チュートリアルなので、一歩一歩完成させていくシナリオなのですが、今回は最終版を直接動作させます。
https://angular.jp/generated/zips/toh-pt6/toh-pt6.zip からダウンロードし、解凍します。

アプリプロジェクトのディレクトリに移動します。

```
cd /Users/hogehoge/Downloads/toh-pt6
```

## 依存モジュールインストール

依存モジュールをローカル環境にインストールします。ローカル環境（プロジェクトディレクトリの配下）なのでsudoは不要です。

```
npm install
```
この例では/Users/hogehoge/Downloads/toh-pt6/node_modules 配下にビルドツールを含め依存するangularモジュールがインストールされます。


## ローカル環境で起動

ローカル環境でアプリ起動します。

```
ng serve --open
```

--openをつけているのでアプリ起動後に、勝手にブラウザで http://localhost:4200/ アクセスされると思います。


# FirebaseへAngularチュートリアルアプリをデプロイする
## Angularアプリの本番ビルド

``` 
ng build --prod
```

自分の環境ではなぜか以下のようなエラーが出るので、暫定策としてhero-search.component.en.tsを削除もしくはhero-search.component.en.ts.backなどにリネームして、ビルド対象にならないよう退避します。


```:出力結果                                                                                     
Date: 2019-05-26T14:43:03.047Z
Hash: 47992a2e3f00b82be305
Time: 9127ms
chunk {0} runtime.ec2944dd8b20ec099bf3.js (runtime) 1.41 kB [entry] [rendered]
chunk {1} main.9868d9b237c3a48c54da.js (main) 128 bytes [initial] [rendered]
chunk {2} polyfills.85f47f0bf59079cbc23a.js (polyfills) 130 bytes [initial] [rendered]
chunk {3} styles.167b12e8ea2d1f694d59.css (styles) 765 bytes [initial] [rendered]

ERROR in : Cannot determine the module for class HeroSearchComponent in /Users/hogehoge/Downloads/toh-pt6/src/app/hero-search/hero-search.component.en.ts! Add HeroSearchComponent to the NgModule to fix it.
```

上記のビルドコマンドによりdistディレクトリが生成され、可読性が低いjsファイルを含むデプロイ対象ファイルが確認できます。

```
$ ls ./dist
```
```:出力結果
3rdpartylicenses.txt			main.42fecdd23b351048f441.js		styles.167b12e8ea2d1f694d59.css
favicon.ico				polyfills.ef261426ad5a9ac404e3.js
index.html				runtime.ec2944dd8b20ec099bf3.js
```

## Firebaseへログイン
CLIでFirebaseへログインします。

```
firebase login
```

以下の使用状況データ収集の確認をされ、ブラウザでのGoogleアカウントを使用した認証画面に遷移します。

```:出力結果
[? Allow Firebase to collect anonymous CLI usage and error reporting information? No
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149690/3002b78a-e20a-56a6-063f-608767998a8c.png)

## プロジェクトのFirebase化

ローカルのアプリプロジェクトをFirebase向けに初期化します。

```
firebase init
```

以下の結果が表示され、アプリの特徴を選択します。
今回はリアルタイムDBも使用しないので、一番シンプルなHostingのみをSpaceキーで選択し、Enterキーで決定します。

```:CLIウィザード

     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

You're about to initialize a Firebase project in this directory:

  /Users/hogehoge/Downloads/toh-pt6

? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confirm your choices. 
 ◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
❯◉ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
```

Firebase側の公開プロジェクトを選択します。今回は新規に作成します。

```:CLIウィザード
=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add, 
but for now we'll just set up a default project.

? Select a default Firebase project for this directory: 
  [don't setup a default project] 
  my-project-xxxxx (my-project) 
❯ [create a new project]  
```

ローカルのアプリプロジェクトのどのディレクトリを公開するか入力します。
先程のビルドで生成したプロジェクト配下のdistディレクトリを指定します。

```:CLIウィザード
=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? (public) dist

```

SPAなのでyを選択します。

```:CLIウィザード
? Configure as a single-page app (rewrite all urls to /index.html)? (y/N) y
```

index.htmlはAngularのビルドコマンドで生成されているため、上書きはしません。（結果的には一つ前をNoにするのと同じかもしれません。）

```:CLIウィザード
? File dist/index.html already exists. Overwrite? (y/N) N
```

この作業により以下のデプロイに必要な情報を記載したfirebase.jsonファイルが生成されます。

```json:firebase.json
{
  "hosting": {
    "public": "dist",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}
```

## Firebaseへのデプロイ
Firebaseへdistディレクトリをデプロイします。

```
firebase deploy
```

```:CLIウィザード
=== Deploying to 'my-project-xxxxx'...

i  deploying hosting
i  hosting[my-project-xxxxx]: beginning deploy...
i  hosting[my-project-xxxxx]: found 7 files in dist
✔  hosting[my-project-xxxxx]: file upload complete
i  hosting[my-project-xxxxx]: finalizing version...
✔  hosting[my-project-xxxxx]: version finalized
i  hosting[my-project-xxxxx]: releasing new version...
✔  hosting[my-project-xxxxx]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/my-project-xxxxx/overview
Hosting URL: https://my-project-xxxxx.firebaseapp.com
```

表示されたURLへブラウザでアクセスします。
以下のような画面が表示できれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149690/f9f123ae-1e0d-3696-a234-ff380325e3d4.png)

Firebaseのコンソールページ側もこんな感じでデプロイ履歴が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149690/f4e3f84c-77ea-b2a7-cebd-9c508fcb5c55.png)


# 参考URL
[Angular チュートリアル - アプリケーションシェル](https://angular.jp/tutorial/toh-pt0)
[How to Deploy an Angular App to Firebase Hosting]
(https://www.youtube.com/watch?v=aICeVhu2mAE)
[Deploy An Angular App To Firebase In Minutes]
(https://www.youtube.com/watch?v=mF7FTWHS3ys)