【JAMstack】Next.js × Firebase で JAMstack なブログサイトを作る③[Hooks]


概要

本記事は、【JAMstack】Next.js × Firebase で JAMstack なブログサイトを作る②[ブログサイト]の続きとなっています。

本記事では、Firebase Functinosを使用して、Firebase Storageの記事に変更があった場合にVercelにデプロイリクエストを送るHook関数を作成します。
これによって、Vercelでリビルドが走り、そのときに変更された状態のFirebase Storageの記事を取得するので、ブログサイトも更新される寸法です。

プロジェクトの作成

Firebase Functions

Firebase Functionsのプロジェクトを作成しておきます。
※ Firebase自体のプロジェクトは、【JAMstack】Next.js × Firebase で JAMstack なブログサイトを作る②[ブログサイト]で作成したものを使います。

Hooks

firebase-toolsをインストールしていない場合は、インストールします。

npm i -g firebase-tools

作業フォルダを作成して、フォルダ内でコマンドプロンプトを使用して以下を実行します。

firebase init

初期設定は、以下のようにします。

  • Functionsを選択します。
  • 既存プロジェクトとして、Firebaseのプロジェクトを選択します。
  • あとは、使用言語としてTypeScript、Eslint(お好み)、npmの依存関係の設定をします。

Hooksの作成

パッケージ インストール

作成したプロジェクトに、使用するパッケージをインストールします。
パッケージは、functionsフォルダ内で管理されているので、そこにインストールします。

cd functions
npm i axios dotenv
  • axios:APIリクエストを送るときに使用します
  • dotenv:Node環境で環境変数ファイル(.env)を使用できるようにします

デプロイAPIの設定

Vercelにデプロイリクエストを送るためには、APIを取得してGETまたはPOSTする必要があります。
APIの取得は、Dashboardからできます。

Setting > Git > Deploy Hooks

プロジェクトに、取得したAPIアドレスを設定します。
functions以下に.envファイルを作成します。

functions/.env
VERCEL_DEPLOY_HOOK=https://api.vercel.com/v1/integrations/deploy/******

コーディング

ドキュメントに従いコーディングします。

コーディング部分は、長くなるので割愛します。成果物のGitHubリンクを参照してください。
対象のファイルは以下です。(すべてfunctions以下のファイルです)

  • index.ts
  • fetch/vercel.ts

要点であるHook関数は以下のように書きます。

index.ts
import * as functions from 'firebase-functions';

const region = 'asia-northeast1';
const objectBuilder = functions.region(region).storage.object();

/**
 * 記事を投稿したときのHook
 */
export const onPostArticle = objectBuilder.onFinalize(async object => {
    // デプロイ処理
});

/**
 * 記事を削除したときのHook
 */
export const onDeleteArticle = objectBuilder.onDelete(async object => {
    // デプロイ処理
});

デプロイ

以下を実行して、Firebase Functionsにデプロイします。デプロイには少し時間がかかります。

npm run deploy

動作確認

Firebase Storageに記事ファイル(Markdownファイル)をアップロードまたは削除して、VercelのDashboardでリビルド・デプロイが走っていればOKです。

成果物

まとめ

実装自体は簡単でしたが、Firebase Functionsへのデプロイがうまく行かなく沼りました。
権限が足りてないのかなーとか色々やりましたが、結局コーディング上の簡単なミスでした😂

Next >