Nuxt 3 サイトを Firebase Hosting にデプロイする方法
Nuxt 3 では、様々なホスティングサービスへのデプロイを最小限の設定で行えるよう、あらかじめいくつかの選択肢が用意されています。
今回は、その中から Firebase
を利用してサイトを公開する方法をご紹介したいと思います。
※8/20追記:Google Cloud Runへのデプロイを実際に試した内容を踏まえて一部内容を加筆修正しました。
Firebase とは
Firebase は Google が提供しているmBaaSで、Web・アプリ開発をサポートする様々なサービスが利用できます。Google Cloud Platform(GCP)の一員でもあり、アカウントにはGoogleアカウントを利用します。
今回利用するのは Hosting
と Functions
のみですが、他にも高機能NoSQLデータストア Firestore
や、ログイン認証管理 Authentication
など、様々な機能が提供されています。
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
で後から設定することもできます)
ローカルからデプロイするだけであれば不要です。
✔ Firebase initialization complete!
完了すると上記のメッセージが表示され、.firebaserc
firebase.json
public/index.html
(.github/workflows/firebase-hosting-merge.yml
)といったファイルが自動で作成されます。
ただし、firebase.json
と public
ディレクトリ内のファイルは、Nuxt3で自動生成されるものを使うのでいったん削除してください。.firebaserc
は残します。
Nuxt 3 リポジトリの設定
基本はこちらのページに書いてあるそのままなのですが、微妙にわかりにくいところもあったので実際に。
Nuxt 3のサイト構築そのものについてはこの記事では取り扱わないので、初期化のみ行います。
npx nuxi init nuxt-app
code nuxt-app
yarn install
自動生成された nuxt.config.ts
ファイルの nitro.preset
に firebase を指定します。
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
が自動的に生成されているはずです。
{
"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が書いてあります。
私の場合は 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 サイトをデプロイするか迷っているという方がいたら、正直あまりオススメはできないかなと思いました。
昨日、Vercelでのデプロイ方法の記事も公開しましたが、設定不要だったVercelと比較すると設定がわかりにくく、その上でGCPとFirebaseという課金設定が必須というハードルがあるので、気軽に選べるとは言い難いです。
さらに Firebase Functions 特有の問題として、一定時間リクエストがなかった後のコールドスタートが非常に遅いという問題もあります。(これはそもそも Firebase Functions が SSR 用途として設計されていないので仕方ない部分はあるのですが、やっぱり遅いです)
最小インスタンスやメモリなどの設定を変える方法もありますが、今回は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 を使う方法があります。
特にCloud Runは、Dockerベースでプリセットなしでも設定しやすく、Firebase Hostingとの連携もできるため非常に扱いやすく、個人的にはGCPにデプロイするのであればCloud Runをオススメしたいです。
とりあえず Firebase Functions で試して後からCloud Runに切り替えるということも簡単に行えるので、用途に合ったサービスを選んでみてください。
この記事がFirebase × Nuxt3でのサイト構築・公開を行おうとしている方の参考になれば幸いです!
参考
これまでに書いたNuxt3関連記事
Discussion