🎆

Nuxt 3 サイトを Firebase Hosting にデプロイする方法

2022/08/17に公開

Nuxt 3 では、様々なホスティングサービスへのデプロイを最小限の設定で行えるよう、あらかじめいくつかの選択肢が用意されています。

https://v3.nuxtjs.org/guide/deploy/presets

今回は、その中から Firebase を利用してサイトを公開する方法をご紹介したいと思います。

※8/20追記:Google Cloud Runへのデプロイを実際に試した内容を踏まえて一部内容を加筆修正しました。

Firebase とは

Firebase は Google が提供しているmBaaSで、Web・アプリ開発をサポートする様々なサービスが利用できます。Google Cloud Platform(GCP)の一員でもあり、アカウントにはGoogleアカウントを利用します。

今回利用するのは HostingFunctions のみですが、他にも高機能NoSQLデータストア Firestore や、ログイン認証管理 Authentication など、様々な機能が提供されています。

https://firebase.google.com/

Firebase をデプロイ先に選ぶ場合の注意

Firebase上でNuxt3をデプロイする場合、従量課金制であるBlazeプランへのアップグレードと、支払い方法の登録が必須となります。

これはドキュメントにも記載があり、(SPAやSSGを使わない限り)現状はどうしようもないと思われます。クレジットカードを紐づけたくない、万が一のクラウド破産が怖いという方は、他のホスティングサービスをおすすめします。

Firebase へのデプロイ

Firebase プロジェクトの作成

Firebase プロジェクトの作成やHostingへのデプロイについてはちゃんとした手順がまとめられた記事がたくさん転がっているはずなので、ちゃんと理解したい方はそちらをご確認ください。

ここでは Google アカウントがあることを前提に、最小限の手順で進める方法をご紹介します。

まず npm install -g firebase-tools で Firebase CLIをローカルにインストール。

次に firebase login コマンドでアカウントにログイン。(ブラウザが自動で開くので、Googleアカウントでログインします)

そして firebase init hosting コマンドで初期化を開始。

=== 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.

? Please select an option: (Use arrow keys)
❯ Use an existing project 
  Create a new project 
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project 

Create a new project を選択するとCLI上でプロジェクトの新規作成を行えます。

あとは指示に従ってプロジェクト名を入力するとプロジェクトが作成されます。

🎉🎉🎉 Your Firebase project is ready! 🎉🎉🎉

Project information:
   - Project ID: ***
   - Project Name: ***

Firebase console is available at
https://console.firebase.google.com/project/***/overview
i  Using project *** (***)

今回は firebase init hosting を選択したので、このまま Firebase Hostingの設定に進みます。

基本的にはデフォルト設定のまま Enter を押していけば良いですが、既にGitHubリポジトリがある場合は、ここで GitHub Actions との連携を行うこともできます。その場合は以下の記事を参考にしてみてください。(firebase init hosting:github で後から設定することもできます)

https://zenn.dev/watarukun/articles/8f3e318bacf97cabf879

ローカルからデプロイするだけであれば不要です。

✔  Firebase initialization complete!

完了すると上記のメッセージが表示され、.firebaserc firebase.json public/index.html.github/workflows/firebase-hosting-merge.yml)といったファイルが自動で作成されます。

ただし、firebase.jsonpublic ディレクトリ内のファイルは、Nuxt3で自動生成されるものを使うのでいったん削除してください。.firebaserc は残します。

Nuxt 3 リポジトリの設定

https://v3.nuxtjs.org/guide/deploy/providers/firebase/

https://nitro.unjs.io/deploy/providers/firebase

基本はこちらのページに書いてあるそのままなのですが、微妙にわかりにくいところもあったので実際に。

Nuxt 3のサイト構築そのものについてはこの記事では取り扱わないので、初期化のみ行います。

https://v3.nuxtjs.org/getting-started/quick-start

npx nuxi init nuxt-app
code nuxt-app
yarn install

自動生成された nuxt.config.ts ファイルの nitro.preset に firebase を指定します。

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: "firebase",
  },
})

次に、必要なパッケージをあらかじめインストールします。

yarn add --dev firebase-admin firebase-functions firebase-functions-test

これで設定は完了。 yarn build コマンドでビルドを行います。

✔ You can deploy this build using npx firebase deploy                               
Done in 29.42s.

このメッセージが出たらプリセット設定も正しく行われており、firebase.json が自動的に生成されているはずです。

firebase.json
{
  "functions": { "source": ".output/server" },
  "hosting": [
    {
      "site": "<your_project_id>",
      "public": ".output/public",
      "cleanUrls": true,
      "rewrites": [{ "source": "**", "function": "server" }]
    }
  ]
}

<your_project_id> を、Firebaseプロジェクト作成時に指定した名前で置き換えれば準備は完了です。

Firebase Hosting に デプロイする

あとは firebase deploy コマンドを実行するだけです。

Blazeプランに上げていない場合

Error: Your project ****** must be on the Blaze (pay-as-you-go) plan to complete this command. Required API artifactregistry.googleapis.com can't be enabled until the upgrade is complete. To upgrade, visit the following URL:

https://console.firebase.google.com/project/******/usage/details

最初に書いた通り、Sparkプランのままだと上記のメッセージが出てエラーになります。

コンソールに表示されたURLに移動して、Blazeプランへの変更を行ってから改めて firebase deploy を行います。

Could not find functions.yaml エラーが出たら

ところが私の環境だとこれでもエラーが出ました。

3.0.0-rc.8 バージョン時点でのものなので、既に解消されていたら無視してください)

Error: An unexpected error has occurred.
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

firebase-debug.log を見ると、以下のようなエラーが残っていました。

[debug] [2022-08-15T11:37:15.192Z] Building nodejs source
[debug] [2022-08-15T11:37:15.193Z] Could not find functions.yaml. Must use http discovery
[debug] [2022-08-15T11:37:15.204Z] Error: spawn ./node_modules/.bin/firebase-functions ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:282:19)
    at onErrorNT (node:internal/child_process:477:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)
[error] 
[error] Error: An unexpected error has occurred.

こちらのエラーで検索すると以下のissueが既に立っており、いくつかworkaroundが書いてあります。

https://github.com/nuxt/framework/issues/4961

私の場合は rm -rf .output/server/node_modules && firebase deploy というように、ビルド後、デプロイする前に .output 内の node_modules ディレクトリを削除することでエラーが解消されました。

この方法では一部の依存ライブラリが正しくアップロードされないことがわかりました。

エラーログとこのコメント を参考に、mkdir .output/server/node_modules/.bin && cp -r node_modules/.bin/firebase-functions .output/server/node_modules/.bin && cp -rfu node_modules/firebase-functions/ .output/server/node_modules コマンドを実行することで回避できました。

完了!

以下のようなコンソールが出て、5分程度でデプロイが完了しました。(Hosting と Functions を別々にデプロイする関係か、少し時間がかかります)

$ rm -rf .output/server/node_modules && firebase deploy

=== Deploying to 'project-id'...

i  deploying functions, hosting
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
i  artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled...
✔  functions: required API cloudbuild.googleapis.com is enabled
✔  functions: required API cloudfunctions.googleapis.com is enabled
✔  artifactregistry: required API artifactregistry.googleapis.com is enabled
i  functions: preparing codebase default for deployment
i  functions: preparing .output/server directory for uploading...
i  functions: packaged /home/****/****/****/.output/server (499.16 KB) for uploading
✔  functions: .output/server folder uploaded successfully
i  hosting[project-id]: beginning deploy...
i  hosting[project-id]: found 51 files in .output/public
✔  hosting[project-id]: file upload complete
i  functions: updating Node.js 16 function server(us-central1)...
✔  functions[server(us-central1)] Successful update operation.
Function URL (server(us-central1)): https://us-central1-project-id.cloudfunctions.net/server
i  functions: cleaning up build files...
i  hosting[project-id]: finalizing version...
✔  hosting[project-id]: version finalized
i  hosting[project-id]: releasing new version...
✔  hosting[project-id]: release complete

✔  Deploy complete!

Project Console: https://console.firebase.google.com/project/project-id/overview
Hosting URL: https://project-id.web.app
Done in 242.81s.

本当はここから、キャッシュ設定やリージョンの変更などを行ってパフォーマンスを向上させることもできるのですが、この記事では割愛します。基本的には Nuxt 2 やそれ以外の Node.js フレームワークをFirebaseで動かす場合のアプローチがそのまま使えるはずなので、興味のある方は検索してみてください。

Nuxt 3 のデプロイ先に Firebase を選ぶべきか?

ここまで一通りの手順を見てきましたが、もし今Firebaseを使ったことがなくて、フラットにどの環境に Nuxt 3 サイトをデプロイするか迷っているという方がいたら、正直あまりオススメはできないかなと思いました。

https://zenn.dev/ytr0903/articles/21b794d0f5ef9f

昨日、Vercelでのデプロイ方法の記事も公開しましたが、設定不要だったVercelと比較すると設定がわかりにくく、その上でGCPとFirebaseという課金設定が必須というハードルがあるので、気軽に選べるとは言い難いです。

さらに Firebase Functions 特有の問題として、一定時間リクエストがなかった後のコールドスタートが非常に遅いという問題もあります。(これはそもそも Firebase Functions が SSR 用途として設計されていないので仕方ない部分はあるのですが、やっぱり遅いです)

https://zenn.dev/isamua/articles/firebase-functions-performance

https://zenn.dev/seisei/articles/7c02fdffa866a0

最小インスタンスやメモリなどの設定を変える方法もありますが、今回はBlazeプランになっていることもあり、意図せず料金が嵩んでしまう懸念があります。

どんな人におすすめか

まずは大前提として既にFirebase / GCP を利用している方、またはGCPを今後メインに利用していきたいと考えている方。

デプロイ先に Firebase を選択する最大のメリットは、アカウントやドメイン・請求などの管理をFirebase および GCP に一元化できる点になってくるかと思います。

今回の記事で説明した手順も、Firebaseプロジェクトの初期設定が含まれていたから煩雑に見えますが、既にFirebaseプロジェクトを所持している方にとっては全く苦ではないはずです。

あくまで「ホスティング特化のサービスに比べると初期設定がちょっと大変」というだけで、困るようなものではありません。既にBlazeプランのFirebaseプロジェクトをお持ちの方が、とりあえずNuxt3サイトをどこかに公開して試してみたいという場合にはかなり適しているのではないでしょうか。

あとは明確なデメリットになるのがコールドスタートですが、

  • 起動の遅さが気にならないか、多少お金がかかっても良い
  • もしくはFirebase FunctionsでSSRでの本番運用を行ったことがあり、そのあたりの制限を回避する知見がある
  • Nuxt3 が正式リリースされたら SPA や SSG に切り替えるつもりで、SSR はちょっと試せれば良い

といったケースであればそこまで問題にはならないかなと思います。

Google Cloud Run の選択肢を検討する

コールドスタートやBlazeプランといった Firebase Functions のデメリットが気になる場合、同じGCPでも Google App Engineや Google Cloud Run を使う方法があります。

https://zenn.dev/ytr0903/articles/81c8bed9a60702

https://zenn.dev/ytr0903/articles/b9dc28285c16e1

特にCloud Runは、Dockerベースでプリセットなしでも設定しやすく、Firebase Hostingとの連携もできるため非常に扱いやすく、個人的にはGCPにデプロイするのであればCloud Runをオススメしたいです。

とりあえず Firebase Functions で試して後からCloud Runに切り替えるということも簡単に行えるので、用途に合ったサービスを選んでみてください。

この記事がFirebase × Nuxt3でのサイト構築・公開を行おうとしている方の参考になれば幸いです!

参考

https://v3.nuxtjs.org/guide/deploy/providers/firebase

https://nitro.unjs.io/deploy/providers/firebase

これまでに書いたNuxt3関連記事

https://zenn.dev/ytr0903/articles/d0a91f6180d34e

https://zenn.dev/ytr0903/articles/8f4e3c0e529c6f

https://zenn.dev/ytr0903/articles/81c8bed9a60702

https://zenn.dev/ytr0903/articles/21b794d0f5ef9f

Discussion