ExtensionからFunctionsコードベースおよびnpmパッケージへの移行
概要
Firebase Extensionを以下のいずれかに移行します:
- ローカルCloud Functionsコードベース(アプリ統合用の
functions/src/)。 - 公開可能なnpmパッケージ(V2関数をエクスポートする再利用可能なオープンソースパッケージ)。
ネイティブのCloud Functions機能(宣言的なIAM、パラメータ化された設定、SDKライフサイクルフック)を活用し、Destructuring Compatibility Shimを使用して第1世代トリガーを第2世代に最新化します。
移行ターゲットワークフロー
-
ターゲットA:ローカルFunctionsコードベース(エンドユーザーアプリ統合)
- 出力:
functions/src/の下のコード。設定は.env。 - デプロイ:
firebase deploy --only functions。
- 出力:
-
ターゲットB:公開可能なnpmパッケージ / 共有可能なパッケージ
- 出力:V2関数をエクスポートする再利用可能なnpmパッケージ。
- 設定:
exportsマップ、engines: { "node": ">=22" }、およびpeerDependencies: { "firebase-functions": ">=6.0.0" }を指定したpackage.json。 - 使用方法:利用者はパッケージをインストールし、
index.tsで関数を再エクスポートします(export * from "<package-name>")。
コアルールと制約
1. 宣言的なIAMとAPI(ゼロローカルオーバーヘッド)
手動のgcloudスクリプトやコンソールの指示ではなく、ネイティブのSDK宣言を使用します:
- 必要なGCP IAM権限には
requiresRole("roles/...")を使用。 - Google APIには
requiresAPI("service.googleapis.com", "Description")を使用。
2. グローバルパラメータアクセスの制限
- トップレベルのモジュールロードスコープで
.value()を呼び出さないでください。 - グローバルなSDKインスタンスは
onInit()または遅延ゲッター内で初期化します:import { defineString } from "firebase-functions/params"; import { onInit } from "firebase-functions/v2"; const dataset = defineString("DATASET_ID"); let client: BigQuery; onInit(() => { client = new BigQuery({ datasetId: dataset.value() }); });
3. V2の並行実行とコストパリティ
V2では並行実行(最大80リクエスト)が可能です。V1の単一並行実行の料金を維持するには、cpu: "gcf_gen1"を設定します。
ステップバイステップの移行手順
ステップ1:Extensionリソースの棚卸し
extension.yaml
params→defineString、defineInt、defineBoolean、defineSecret。apis→requiresAPI(...)。roles→requiresRole(...)。lifecycleEvents→afterFirstDeployおよびafterRedeploy。resources→ 第1世代トリガーを第2世代にアップグレード(onDocumentWritten、onTaskDispatched、onRequest)。
- ファイルとスクリプト:devDependencies、テストフレームワーク(
jest)、テストスクリプトを保持。
ステップ2:package.jsonの設定
name: "<package-name>"、engines: { "node": ">=22" }を設定。peerDependenciesを設定:"peerDependencies": { "firebase-admin": "^11.0.0 || ^12.0.0", "firebase-functions": ">=6.0.0" }- ESM/CommonJSおよびTypeScript宣言(
lib/index.js、lib/index.d.ts)を対象とするexportsマップを設定。
ステップ3:トリガーをV1からV2にアップグレード
- Firestore:
firebase-functions/v2/firestoreからonDocumentWrittenを使用。 - Tasks:
firebase-functions/v2/tasksからonTaskDispatchedを使用。タスクをエンキューする際にEXT_INSTANCE_IDを削除。 - HTTP:
firebase-functions/v2/httpsからonRequestを使用。 - レガシーな第1世代ハンドラが
(change, context)を期待する場合、Destructuring Compatibility Shim({ change, context }、{ snapshot, context })を適用。
ステップ4:ライフサイクルイベントの変換
Extensionのライフサイクルイベントをsrc/index.ts内のSDKライフサイクルフックにマッピング:
onInstall→afterFirstDeploy({ task: { function: "initTask" } })onUpdate/onConfigure→afterRedeploy({ task: { function: "setupTask" } })
ステップ5:パッケージREADMEとエクスポート手順
README.mdを生成し、以下を含めます:
- インストール手順(
npm install)。 - 再エクスポートスニペット(
export * from "<package-name>")。 - パラメータ化された設定
.env参照テーブル。 - 変更点(Extension vs パッケージ)比較テーブル。
注意:npm publishは絶対に実行しないでください。