Nuxt.jsで作ったSSRプロジェクトをFirebase hostingでデプロイする

# はじめに
今回、Nuxt.js（SSR）で作成したアプリをデプロイするのに苦労したのでその方法をこちらに残そうと思います。同じ苦しみを味わっている方の助けになれば幸いです。

# 諸々のバージョン
firebase: 7.19.1
nuxt: 2.15.7
node v14.16.0


# 前提： SPAとSSRでデプロイの方法が異なる

今回はNuxt.jsのSSRで作成したプロジェクトファイルをfirebase hostingでデプロイしています。同じNuxt.jsでもSPAの方は試していないためその点はご了承ください。

また、今回のデプロイに当たってこちらの記事を大いに参考させていただきました。
ありがとうございました！m(_ _)m

[SSRで作ったNuxtアプリをFirebase hostingで動的にデプロイする。 - Qiita](https://qiita.com/yagichan1102/items/c3f329da3a14c85c3a73)


# firebaseプロジェクトの作成
様々な記事ですでに詳しい解説があるのでfirebaseプロジェクト作成については割愛させていただきます。ちなみに今回私が利用したのは、firebase Auth, firestore, storageです。

firestoreのリージョンはus-centralで作成しています。

理由は下記参照。
[firebaseを使ってnuxtのサーバーサイドレンダリングを試す - Qiita](https://qiita.com/gosshys/items/000493a498a0668e0d85)

# 作成したプロジェクトのプランをSparkから従量課金のBrazeへ変更する

nodeバージョン10以降からBrazeでないとデプロイ時にエラーが出るようになったそうなので事前に変更しておきます。

# firebase CLIの導入

まだ未設定の方はデプロイに必要なfirebase CLIの設定をおこないます。

公式ドキュメント：
[Firebase Hosting を使ってみる](https://firebase.google.com/docs/hosting/quickstart?hl=ja#install-cli)

```
yarn global add -g firebase-tools
```

```
firebase login
```

Login Successfulといった表記が出たら成功！

# firebaseディレクトリのインストール

nuxtのプロジェクト直下に移動してターミナルで下記を入力。

```
firebase init
```

するとNuxtプロジェクト作成の時みたいにたくさん質問が出てくる。
※項目を選択するときはスペースを押します。

```
? Which Firebase features do you want to set up for this directory? Press Space to select features, t
hen Enter to confirm your choices. (Press <space> to select, <a> to toggle all, <i> to invert selecti
on)
❯◯ Functions: Configure a Cloud Functions directory and its files
 ◯ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys

? Please select an option: (Use arrow keys)
Use an existing project

? Select a default Firebase project for this directory: (Use arrow keys)
（自身がfirebaseに作成したプロジェクトが一覧で表示される）
今回デプロイしたいプロジェクトを選択。

? What language would you like to use to write Cloud Functions? (Use arrow keys)
JavascriptとTypescriptどちらかを選択。使ってる方の言語でOK。

? Do you want to use ESLint to catch probable bugs and enforce style? (y/N)
今回はNを選択。

? Do you want to install dependencies with npm now? (Y/n)
今回はYを選択

? What do you want to use as your public directory? (public)
distと入力。

? Configure as a single-page app (rewrite all urls to /index.html)? (y/N)
今回はNを選択。

? Set up automatic builds and deploys with GitHub? (y/N)
今回はNを選択。

✔  Firebase initialization complete!と出たら終了！
```

しばらくするとフォルダにfirebase.jsonと.firebaserc, distフォルダ, functionsフォルダが追加される。

# firebase.jsonの編集

下記コードをコピー。

デプロイ時にfirebase functionsにリライトする設定を付与。

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

上記のpublicという項目でhostingにデプロイするフォルダを決めている。
今回は最初の質問でpublicではなくdistフォルダ作成を指定しているのでdistと記載しています。

```
    "public": "dist",
```

ちなみに現在distフォルダの中身はこのようになっている。

```
dist
 -- 404.html
 -- index.html
```

# functionsフォルダ内のpackage.jsonを編集

nodeのバージョンがあっているか確認してください。

```functions/package.json
{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "serve": "firebase emulators:start --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "engines": {
    "node": "14"
  },
  "main": "index.js",
  "dependencies": {
    "firebase-admin": "^9.8.0",
    "firebase-functions": "^3.14.1"
  },
  "devDependencies": {
    "firebase-functions-test": "^0.2.0"
  },
  "private": true
}
```

プロジェクト直下の`package.json`の`dependencies`と`devDependencies` の内容を上記の`functionフォルダ内のpackage.json`に全てコピーする。

こちらの記事を参考。
[【Nuxt.js】SSRアプリケーションをFirebaseにホスティングするために行ったこと](https://zenn.dev/kokota/articles/cd2aa18365aa91)

その後、下記コマンドをたたいて依存ファイルをダウンロードする。

```
cd functions && npm install --save nuxt
```

ダウンロードが終わったら`cd ../`でプロジェクト直下に戻っておく。

# functionsフォルダ内のindex.jsを編集する

下記コードをコピペする。

```functions/index.js
const functions = require('firebase-functions');
const { Nuxt } = require('nuxt');
const nuxt = new Nuxt({
    buildDir: 'ssr',
    dev: false
});

exports.ssr = functions.https.onRequest(async (req, res) => {
    await nuxt.ready()
    return nuxt.render(req, res)
})
```

# プロジェクト直下のpackage.jsonのビルドコマンドを変更。

下記二つのコードを追加。
buildの方はすでに記載があるので上書きする。

```
"build": "nuxt build && npm run build:copy:ssr",
"build:copy:ssr": "rimraf functions/ssr && mkdirp functions/ssr && cp -R .nuxt/dist functions/ssr/dist",
```

# プロジェクトをbuildする

buildコマンドは、いくつか記事を読んだりして調べて下記の記述が書いてあったのですがそれでは動かず。別の方法でトライしています。

```
npm run build
```
<br>
色々と調べた結果下記の記事に辿り着きました。
[firebaseでnuxtのdeployをする(error対策込み)](https://ebookbrain.net/deploy-for-webapp/)

<br>
上記でSPAであれば`npm run build` だがSSRでは下記コマンドだと記述があり試してみる。

```
npm run generate
```

その後、下記コマンドを実行。
無事プロジェクトをプレビューできました。

```
firebase serve
```

`※コマンド実行後すぐにURLにアクセスするとうまく表示されないことがありました。場合によっては反映まで時差が生じることがあるようです。その際は、少し待てば問題なく表示されることがあります。`

<br>
上記で問題なく表示できればデプロイをする。

```
firebase deploy
```

しかし、下記エラーが発生、、、

```
Functions deploy had errors with the following functions:
        ssr(us-central1)

To try redeploying those functions, run:
    firebase deploy --only "functions:ssr"

To continue deploying other features (such as database), run:
    firebase deploy --except functions

Error: Functions did not deploy properly.
```

（色々ググって試してみましたが解決策が見つからず。）

大人しくコンソールの助言どおり。下記コマンドを叩く。

```
firebase deploy --except functions
```

すると、

```
✔  Deploy complete!

Project Console: https://~~~
Hosting URL: https://~~~
```

と、無事デプロイ先のURLが発行されました。