Node.js によるアプリを Firebase で Hosting する最短の道

# はじめに

Firebase のホスティング、優れものです。静的コンテンツはもちろんのこと、なんと Node.js による動的コンテンツまでホスティングできちゃいます。それも開発時とか小さなサービスなら実質無料でいけちゃう感じです。

理解するために、静的コンテンツと動的コンテンツのホスティングについて、実現までの最短の道を見て見ます。

ちなみに静的コンテンツだけで OK なら、以下の公式ガイドを参照すれば大丈夫でしょう。
https://firebase.google.com/docs/hosting/quickstart?hl=ja

# 準備

- Node.js と npm をインストールしてください。
https://nodejs.org/en/
この記事は、8.10.0 LTS で検証しています。

- Firebase のプロジェクトを用意してください。

- 手元のコンピュータに作業用のフォルダを作ってください。

- Firebase CLI をインストールしてください。

```
$ npm install -g firebase-tools
```

- Firebase のアカウントと紐付けてください。

```
$ firebase login
```

# アプリを初期化する

```
$ cd ＜作業用のフォルダ＞
$ firebase init
```

以下のような画面になります。Hosting と Functions を選択してください。


```

     🔥🔥🔥🔥🔥🔥🔥🔥 🔥🔥🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥     🔥🔥🔥     🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥
     🔥🔥        🔥🔥  🔥🔥     🔥🔥 🔥🔥       🔥🔥     🔥🔥  🔥🔥   🔥🔥  🔥🔥       🔥🔥
     🔥🔥🔥🔥🔥🔥    🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥   🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥
     🔥🔥        🔥🔥  🔥🔥    🔥🔥  🔥🔥       🔥🔥     🔥🔥 🔥🔥     🔥🔥       🔥🔥 🔥🔥
     🔥🔥       🔥🔥🔥🔥 🔥🔥     🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥 🔥🔥🔥🔥🔥🔥🔥🔥  🔥🔥     🔥🔥  🔥🔥🔥🔥🔥🔥  🔥🔥🔥🔥🔥🔥🔥🔥

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

  ＜作業用のフォルダ＞

? Which Firebase CLI features do you want to setup 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
```

いくつか選択肢が出て答えを求められます。下のように答えたとして話をすすめます。

```
? Select a default Firebase project for this directory: ＜Firebase のプロジェクト名＞
? What language would you like to use to write Cloud Functions? JavaScript
? Do you want to use ESLint to catch probable bugs and enforce style? No
? Do you want to install dependencies with npm now? Yes

? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? No
```

終了すると作業用フォルダは以下のような構成になっています。

```
.
├── firebase.json
├── functions
│   ├── index.js
│   ├── node_modules
│   ├── package-lock.json
│   └── package.json
└── public
    ├── 404.html
    └── index.html
```

public フォルダが静的コンテンツを入れるフォルダで、functions が動的コンテンツを入れるフォルダです。作業用のフォルダがからの状態から始めたとしたら、firebase-cli によって、ダミーのコンテンツが入っているはずです。
functions/index.js は何もしないコードになってるので、エディタであけてコメントを外して、下のようなコードにしてください。

```
const functions = require('firebase-functions');
exports.helloWorld = functions.https.onRequest((request, response) => {
 response.send("Hello from Firebase!");
})
```


# ローカルで確認

firebase はローカルでシミュレートする機能を持っていますので、この時点で確認してみます。

### 静的コンテンツ

```
$ firebase serve

=== Serving from '＜作業用のフォルダ＞'...

i  hosting: Serving hosting files from: public
✔  hosting: Local server: http://localhost:5000
```
http://localhost:5000 は以下のようになります。
![ST1.png](https://qiita-image-store.s3.amazonaws.com/0/73493/4a45da90-3a89-b6dc-9c0c-191c805e7ab6.png)

5000番のポートで静的コンテンツがホストされるようになります。

### 動的コンテンツ

```
$ firebase serve --only functions

=== Serving from '＜作業用のフォルダ＞'...

i  functions: Preparing to emulate functions.
Warning: You're using Node.js v8.10.0 but Google Cloud Functions only supports v6.11.5.
✔  functions: helloWorld: http://localhost:5000/＜Firebase のプロジェクト名＞/us-central1/helloWorld
```

http://localhost:5000/＜Firebase のプロジェクト名＞/us-central1/helloWorld は以下のようになります。
![ST3.png](https://qiita-image-store.s3.amazonaws.com/0/73493/5eddc205-25ed-6427-f953-1e556134aea8.png)

- 5000番のポートで動的コンテンツがホストされるようになります。

- index.js の中で export している、exports.helloWorld という名前が URL に現れます。

- Node.js のバージョンが高すぎ、みたいな警告出てます。気になるかたは、Nodeを v6.11.5 で。

### 混在

```
$ firebase serve --only hosting,functions

=== Serving from '＜作業用のフォルダ＞'...

i  functions: Preparing to emulate functions.
i  hosting: Serving hosting files from: public
✔  hosting: Local server: http://localhost:5000

Warning: You're using Node.js v8.10.0 but Google Cloud Functions only supports v6.11.5.
✔  functions: helloWorld: http://localhost:5001/＜Firebase のプロジェクト名＞/us-central1/helloWorld
```

5000番のポートで静的コンテンツが、5001番のポートで動的コンテンツがホストされるようになります。

# デプロイ

ローカルで確認したときとちょっとオプションが違うので注意！

- ローカル
 - 静的コンテンツ　無し
 - 動的コンテンツ　--only functions
 - 混在　　　　　　--only hosting,functions

- デプロイ
 - 静的コンテンツ　--only hosting
 - 動的コンテンツ　--only functions
 - 混在　　　　　　無し


```
$ firebase deploy 

=== Deploying to '＜Firebase のプロジェクト名＞'...

i  deploying functions, hosting
i  functions: ensuring necessary APIs are enabled...
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (31.21 KB) for uploading
✔  functions: functions folder uploaded successfully
i  hosting: preparing public directory for upload...
✔  hosting: 2 files uploaded successfully
i  functions: updating function helloWorld...
✔  functions[helloWorld]: Successful update operation. 
Function URL (helloWorld): https://us-central1-＜Firebase のプロジェクト名＞.cloudfunctions.net/helloWorld

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/＜Firebase のプロジェクト名＞/overview
Hosting URL: https://＜Firebase のプロジェクト名＞.firebaseapp.com
```

以下のアドレスでホストされるようになります。

静的コンテンツは　https://＜Firebase のプロジェクト名＞.firebaseapp.com
動的コンテンツは　https://us-central1-＜Firebase のプロジェクト名＞.cloudfunctions.net/helloWorld

# 最後に

ここまでくれば、あとは自由に public と functions フォルダに必要なものを入れていけばいいでしょう。

Express などのミドルが必要になるなど、ちょっと踏み込みたくなったら、[こちらの記事](https://qiita.com/seya/items/225f859d775b31047000)で本家のビデオを解説してるので、これも参照されるといいでしょう。

それではー