Angular2とFirebase hostingでSPA開発環境を整える


Firebaseはリアルタイムデータベースに加え、認証、ノーティフィケーション等さまざまな機能を提供しており、それに加えホスティング機能で静的リソース(html, css, js, 画像など)を簡単にデプロイでき、SPA routing機能まで面倒を見てくれる。
そのため、Angular2 SPA、Progressive web appのホスティングサービスとして最適なものの一つと考えられる。

そこで、今回はAngular2とFirebase hostingでSPA開発環境を整える方法をステップバイステップで説明していく。
Dart版で説明しているがTypeScript版でも適宜読み替えて問題なく参考にできるだろう。


コードは以下。
https://github.com/ntaoo/ng2_firebase_gcp/releases/tag/v1.0

# Angular2のセットアップ

## Dart

もしDartのインストールが済んでいない場合はインストールする。
MacOSの場合は、

	brew tap dart-lang/dart
	brew install dart --with-content-shell --with-dartium
	brew linkapps dart

でインストール完了。

## Stagehand

Stagehandはyeomanのようなプロジェクトジェネレーター。

### インストール

	pub global activate stagehand
	

### Angular2プロジェクトのセットアップ		

	mkdir your_working_directory && cd your_working_directory
	stagehand web-angular
	pub get

# Firebase hostingのセットアップ

基本的には以下を参照のこと。以下の説明は、`firebase init`できる状態までセットアップできていることが前提。
http://qiita.com/potato4d/items/95eaf2e41404711e621e

`firebase init	`する。


	firebase init
		

そして、どのようなコンフィグにするかの質問に答えていく。	

#### Hostingを選択

	? What Firebase CLI features do you want to setup for this folder? 
	 ◉ Database: Deploy Firebase Realtime Database Rules
	❯◉ Hosting: Configure and deploy Firebase Hosting sites


### 作成済みのFirebase Projectを選択(もしくは新規作成)

	? What Firebase project do you want to associate as default? 
	  [don't setup a default project] 
	❯ ng2-firebase-gcp (ng2-firebase-gcp) 
	  [create a new project] 
						
						
						
### Database Rules設定用ファイルを選択

特に変更の必要がないので、ここではそのままenterを押す。

	? What file should be used for Database Rules? (database.rules.json) 
						
						
### Public directoryの設定 						
Public directoryがデプロイ対象になる。デフォルトでは`public` directoryが作成される。今回はDartをJSにコンパイルしてデプロイしたいので、`build/web`にしておく。後からconfigを書き換えることも簡単にできる。

	? What do you want to use as your public directory? (public) build/web											
	
### SPA(single-page app)として設定

デフォルトではNOなので、yを入力してSPA用としてセットアップする。リライトルールが設定される。簡単親切である。
しかし、これはAngularDart開発のワークフローから見るとあくまでbuildしてJSにコンパイルした後のコードをホスティングする際、およびローカルで動作確認する際の設定。AngularDartでの開発時のSPA用リライト設定については後述する。

	Configure as a single-page app (rewrite all urls to /index.html)? (y/N) y	

### デプロイをしてみる
	
	firebase deploy
	
で、`build/web`がデプロイされる。(このコンテンツはAngularDartをJSにコンパイルする際には消されることになる)
	
	firebase open hosting:site
	
で、サイトのURLをブラウザで開く。

![Screen Shot 2016-08-16 at 1.04.33 PM.png](https://qiita-image-store.s3.amazonaws.com/0/8065/fcc57f5f-3b75-a978-2c1c-151ea215f5d7.png "Screen Shot 2016-08-16 at 1.04.33 PM.png")

とブラウザに表示されたら成功。デフォルトでhttpsである。もちろん[Custom Domainを設定する](https://firebase.google.com/docs/hosting/custom-domain)ことも可能。

**簡単すぎる...すごい。**

# Angular2アプリをデプロイする

ここからが本番。
とりあえずstagehandで生成したままの状態でデプロイまでしてみる。

## pub serve

	pub serve
	
で開発サーバーが立ち上がる。
MacOSの場合は`/Applications/Chromium.app`を起動する。これがDartVMが載ったChromiumで、Dartiumと呼ばれている。

![Screen Shot 2016-08-16 at 1.21.48 PM.png](https://qiita-image-store.s3.amazonaws.com/0/8065/4f9c856b-ce38-3aec-6018-690598f30597.png "Screen Shot 2016-08-16 at 1.21.48 PM.png")

ChromeなどのDartVMが載っていないブラウザでURLを開くと、その際に開発サーバーは自動的にJSにコンパイルしてくれる。

## pub build
	
	pub build
	
でJSにコンパイルできる。デフォルトでは`build`ディレクトリに生成される。`build/web`にコンパイル後にAngular2アプリを動作させるファイルが全てある。今回は既にFirebaseのセットアップ時にデプロイ対象を`build/web`にしている。

## firebase deploy

	firebase deploy	
	firebase open hosting:site
	
で無事にデプロイされてAngular2DartのJSにコンパイルされたコードが動作していることを確認する。

![Screen Shot 2016-08-16 at 1.31.18 PM.png](https://qiita-image-store.s3.amazonaws.com/0/8065/c27990bd-1807-575b-8408-fd93b50dee6a.png "Screen Shot 2016-08-16 at 1.31.18 PM.png")

	
# SPA用の設定

## Local Reverse Proxy Server

前述のとおり、firebaseとは別に開発時のSPA用URL Rewriteの設定をする必要がある。さもないと/index.html以外のURLでページをRefreshすると404になってしまい開発効率が非常に悪い。そのため別途Reverse Proxy Serverを立ててSPA用の設定をする必要がある。
Nginx、Apache等、どのようなserverを使っても良い。自分はNginxを使用しているのでその設定を載せておく。

```nginx.conf
# nginx.conf on reverse proxy for local SPA dev.
# Nginx installed by macOS Homebrew.
# Please rewrite paths and ports for your dev env.

# Start: nginx -c $PWD/nginx.conf
# Stop: nginx -s stop

events {}

http {
    include       /usr/local/etc/nginx/mime.types;
    default_type  application/octet-stream;

    access_log  /usr/local/var/log/nginx/access.log;
    error_log  /usr/local/var/log/nginx/error.log;

    # SPA dev server. On Dart web dev, it is usually pub dev server.
    upstream spa {
        server localhost:9910;
    }

    server {
        listen       9900;
        server_name  localhost;

        # Any files with extension.
        location ~ .+\.[^.]+$ {
            proxy_pass http://spa;
        }
        # Fall back to a entry point for bootstrapping SPA with pushState mode (a.k.a html5 mode called in Angular1).
        location / {
            proxy_pass http://spa;
            try_files $uri /index.html;
        }
    }
}
```

nginx.confをプロジェクトディレクトリ直下に配置し、それを読み込ませてnginxを起動する。

	nginx -c $PWD/nginx.conf

## Angular2側の設定

`<base href="/">`を追加する必要がある。

```html:web/index.html
  <head>
    <meta charset="utf-8">
    <title>client</title>
    <base href="/">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">

    <script defer src="main.dart" type="application/dart"></script>
    <script defer src="packages/browser/dart.js"></script>
  </head>
```

また、SPAとは関係がないが、stagehandのテンプレートに含まれていないcharsetとmeta tagをここでついでに追加しておいた。

また、app_componentに動作確認用のrouting設定とrouting対象componentsを追加した。実際のコードは[GitHub](https://github.com/ntaoo/ng2_firebase_gcp/releases/tag/v1.0)で確認できる。

## SPA pushState routingの動作確認

前述のnginx.confでは、reverse proxy serverをlocalhost:9900に、Angular2の spa dev serverをlocalhost:9910に設定している。

	pub serve --port=9910		

でpub dev serverを起動し、Dartiumで http://localhost:9900/some にアクセスする。

![Screen Shot 2016-08-17 at 4.20.11 AM.png](https://qiita-image-store.s3.amazonaws.com/0/8065/be5683aa-328a-746e-4999-a55414f4c384.png "Screen Shot 2016-08-17 at 4.20.11 AM.png")

リクエストがpub dev serverにforwardされ、pushState routingが機能し、/someでreloadしても正常に起動することを確認できた。


#### pubにSPA用のoptionが追加されるかも
	
この辺りの推奨のセッティングはそのうちangular.ioに記載されるはず。pubにSPA用のoptionが追加されるかもしれず、その場合は単純な用途ではreverse proxy serverを別途準備する必要がなくなるかもしれない。


# デプロイ

Firebase hostingにデプロイして、ChromeなどのブラウザでFirebaseのSPA設定が機能していることを確認する。

	pub build
	firebase deploy
	firebase open hosting:site
	
![Screen Shot 2016-08-17 at 4.46.11 AM.png](https://qiita-image-store.s3.amazonaws.com/0/8065/71cc5a78-799e-be50-ec5a-779e83866707.png "Screen Shot 2016-08-17 at 4.46.11 AM.png")


簡単便利。


# ここまでのコード

https://github.com/ntaoo/ng2_firebase_gcp/releases/tag/v1.0

# 続編
- AngularDartとFirebase Authentication
(http://qiita.com/ntaoo/items/5ac40ce8cecf9402169c)

# そのうち書くかもしれないこと
- Firebase databaseの使用
- GCP backend serversとの連携
- Offline web application(Progressive web app)化
- ClientとServerでのコード共有