本指南說明如何將擴充功能從已淘汰的 Firebase Extensions 環境遷移至函式,讓使用者在自己的 Cloud Functions 中安裝及部署,以用於 Firebase (第 2 代) 程式碼集。
建議採用這個遷移路徑。Firebase會維護含有官方 npm 對應項的擴充功能清單;本指南會逐步說明如何建立擴充功能。
在本指南中,我們將使用 Stream Cloud Firestore to
BigQuery
extension (firestore-bigquery-export) 做為執行中的範例。每個章節的結尾都會提供工作範例,說明遷移前後的擴充功能外觀,以及 @firebase-function-kits/firestore-bigquery-export 套件。
註冊即可取得更多資訊,並獲得擴充功能遷移作業的相關協助
如有從 Firebase Extensions 遷移的問題,請傳送電子郵件至 firebase-extensions-migrator-support-external@google.com 與我們聯絡。此外,我們也會在指南中新增有關封裝、測試及發布第 2 代函式的資訊時,透過電子郵件通知這個群組。
如要加入這個群組,請傳送訊息至 firebase-extensions-migrator-support-external+subscribe@google.com, 系統會回覆一封會員資格要求電子郵件。請務必回覆該電子郵件,不要點選「加入這個群組」按鈕。
事前準備
如要按照本文完成遷移作業,請使用 Cloud Functions 的下列功能:
參數化設定。 您在
extension.yaml中宣告的每個參數,都會成為套件程式碼中定義的參數。宣告式 IAM 角色和必要 API。您在
extension.yaml中宣告的每個角色都會成為requiresRole(...)呼叫,而每個 API 都會成為套件程式碼中的requiresAPI(...)呼叫。部署時,Firebase CLI 會將宣告的角色授予受管理執行階段服務帳戶,並代表您啟用宣告的 API。Cloud Functions 程式碼集的生命週期事件。Cloud Functions 程式碼集現在支援生命週期事件,類似於 Firebase Extensions。使用生命週期掛鉤
afterFirstDeploy(...)和afterRedeploy(...)宣告安裝和更新時的設定。這些會取代您在extension.yaml中宣告的lifecycleEvents。
將 Firebase Extensions 來源遷移至第 2 代函式
(選用) 使用 Firebase 代理程式技能自動遷移
您可以使用官方 extension-to-functions-codebase AI 代理程式技能,自動執行步驟 1 至 8 (清查資源、觸發升級、參數和密鑰轉換、宣告式 IAM、生命週期掛鉤,以及產生套件 README)。
安裝技能
如果您或 AI 程式設計助理 (Firebase 中的 Gemini、Cursor、Claude Code、GitHub Copilot) 尚未安裝技能,請使用技能 CLI 執行下列指令:
npx skills add firebase/agent-skills --skill extension-to-functions-codebase
在專案中安裝技能後,AI 程式碼助理就會自動遵循遷移規則和轉換步驟。你可以使用下列提示:
「請按照extension-to-functions-codebase技能中的指示,將這個 Firebase 擴充功能遷移至可發布的第 2 代函式套件。」
1. 清查擴充功能
首先,請清查擴充功能:列出擴充功能宣告、運送及記錄的所有項目,確保第 2 代函式中定義了每個行為的目的地,且遷移作業不會遺失任何項目。
請檢查下列各項,並記下發現的內容:
extension.yaml,用於宣告參數、函式、事件、IAM 角色、必要 API、密鑰和生命週期掛鉤。functions/,其中包含函式程式碼、依附元件、建構設定、觸發條件和工作佇列函式。README.md、PREINSTALL.md和POSTINSTALL.md,其中包含設定步驟、警告和帳單注意事項。scripts/,其中包含任何匯入、回填、IAM、修復或遷移公用程式,以及您隨擴充功能出貨的任何其他工具。
然後,針對 extension.yaml 中的每個項目,決定在 npm 套件中的位置:
將使用者設定轉換為 Cloud Functions 參數 (步驟 4)。
將密鑰轉換為 Cloud Functions 密鑰 (步驟 4)。
將 IAM 角色轉換為
requiresRole(...)宣告 (步驟 6)。視需要將必要的 Google API 轉換為
requiresAPI(...)宣告 (步驟 6)。將安裝和更新掛鉤轉換為
afterFirstDeploy(...)和afterRedeploy(...)宣告 (步驟 7)。將執行個體 ID 從
EXT_INSTANCE_ID轉換為FIREBASE_KIT_INSTANCE_ID(步驟 4)。
範例:將 Stream Cloud Firestore 移至 BigQuery
讀取 firestore-bigquery-export/extension.yaml 和 functions/ 會產生下列廣告空間:
在extension.yaml |
數量 / 價值 | 用途 |
|---|---|---|
params |
25 (COLLECTION_PATH、DATASET_ID、TABLE_ID、DATASET_LOCATION、VIEW_TYPE 等) |
Cloud Functions 參數 (步驟 4) |
apis |
bigquery.googleapis.com |
requiresAPI(...) (步驟 6) |
roles |
bigquery.dataEditor、datastore.user、bigquery.user |
requiresRole(...) (步驟 6) |
resources |
1 個事件觸發條件 (fsexportbigquery) + 工作佇列函式 (initBigQuerySync、setupBigQuerySync) |
匯出的套件函式 (步驟 3) |
lifecycleEvents |
onInstall → initBigQuerySync;onUpdate / onConfigure → setupBigQuerySync |
afterFirstDeploy / afterRedeploy (步驟 7) |
| 執行個體 ID | 未使用 (沒有 EXT_INSTANCE_ID 讀取) |
沒有可遷移的項目 |
scripts/ |
import/ (候補廣告),gen-schema-view/ |
保留為指令碼 (不在本文討論範圍內) |
分析。擴充功能未宣告任何 type: secret 參數,因此步驟 4 中沒有任何密鑰需要遷移。事件觸發程序已是第 2 代,只有工作佇列函式仍為第 1 代 (與步驟 3 相關)。
2. 更新 package.json
更新擴充功能的 package.json 檔案。如果只遷移一個擴充功能,這可以是根 package.json。如要在單一存放區中遷移多個擴充功能,請為每個擴充功能提供專屬套件。
最低 SDK 版本:將 firebase-functions >=
7.4.0 和 firebase-admin >=
14.2.0 宣告為依附元件。同時也請將 firebase-functions 版本宣告為同層級依附元件,確保使用者 Cloud Functions 專案的 SDK 版本與您撰寫程式庫時使用的版本相同。
{
"name": "<package-name>",
"version": "1.0.0",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
}
},
"engines": {
"node": "22"
},
"peerDependencies": {
"firebase-functions": "^7.4.0"
},
"dependencies": {
"firebase-functions": "^7.4.0",
"firebase-admin": "^14.2.0"
}
}
範例:將 Stream Cloud Firestore 轉移至 BigQuery
變更前。擴充功能的 functions/package.json 為私有,會命名擴充功能 ID,並將 firebase-functions 宣告為直接依附元件:
{
"name": "firestore-bigquery-export",
"main": "lib/index.js",
"private": true,
"dependencies": {
"@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
"firebase-admin": "^14.2.0",
"firebase-functions": "^6.3.2"
}
}
變更後。可發布的套件:範圍名稱、exports 對應和 firebase-functions 已移至 peerDependencies:
{
"name": "@firebase-function-kits/firestore-bigquery-export",
"version": "0.1.0",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
}
},
"engines": {
"node": "22"
},
"peerDependencies": {
"firebase-functions": "^7.4.0"
},
"dependencies": {
"@firebaseextensions/firestore-bigquery-change-tracker": "^2.0.4",
"firebase-admin": "^14.2.0",
"firebase-functions": "^7.4.0"
}
}
3. 將第 1 代函式升級至第 2 代
如果擴充功能仍匯出第 1 代函式,請將每個觸發條件轉換為第 2 代對應項目。從 firebase-functions/... 模組匯入,並在觸發選項中傳遞執行階段設定。
請參閱Cloud Functions第 2 代升級指南。 值得注意的是,您可以使用第 2 代修補的事件解構功能,盡量減少重寫作業,並避免重寫函式邏輯,因為第 2 代 SDK 會將 v1 參數公開為事件物件中的欄位,讓您使用解構/具名參數,並維持商業邏輯不變。
變更前。第 1 代:
import * as functions from "firebase-functions/v1";
export const sync = functions.firestore
.document("{collectionId}/{documentId}")
.onWrite(async (change, context) => {
await handleWrite(change.before, change.after, context.params);
});
變更後。第 2 代:
import { onDocumentWritten } from "firebase-functions/firestore";
export const syncV2 = onDocumentWritten(
{ document: "{collectionId}/{documentId}" },
async ({ change, context }) =>
await handleWrite(change.before, change.after, context.params)
);
如需第 1 代和第 2 代函式之間的完整差異清單,請參閱Cloud Functions版本比較。
4. 轉換擴充功能參數和密鑰
參數
您在 extension.yaml 中宣告的每個參數都會成為 Cloud Functions 參數。
轉換直接環境讀取:
const collectionPath = process.env.COLLECTION_PATH;
到 Cloud Functions 參數:
import { defineString } from "firebase-functions/params";
import { onDocumentWritten } from "firebase-functions/firestore";
const collectionPath = defineString("COLLECTION_PATH");
// Pass the param directly when used as a placeholder (e.g. trigger path)
export const sync = onDocumentWritten(
{ document: collectionPath },
async (event) => {
// Call .value() to read the string inside a handler
const path = collectionPath.value();
await handleWrite(path, event);
}
);
如要讀取處理常式內的字串,請使用 collectionPath.value();如要使用預期會出現預留位置的項目 (例如函式觸發路徑),請直接使用 collectionPath。
Firebase CLI 會探索參數,並從 .env、.env.<projectId> 讀取參數值,或在部署期間提示使用者。保留相同的參數名稱,以便沿用現有安裝項目的值。
請務必不要變更程式碼中宣告的參數名稱。擴充功能遷移作業會自動保留現有的使用者參數值,但前提是名稱不變。
範例:將 Stream Cloud Firestore 轉移至 BigQuery
變更前。在 extension.yaml 中宣告的參數,在 config.ts 中讀取為原始環境變數:
# extension.yaml
- param: COLLECTION_PATH
label: Collection path
type: string
required: true
// functions/src/config.ts
collectionPath: process.env.COLLECTION_PATH,
變更後。一個 defineString;CLI 會探索並從 .env 讀取:
// src/config.ts
import { defineString } from "firebase-functions/params";
collectionPath: defineString("COLLECTION_PATH", {
label: "Collection path",
// We now support "nonEmpty: true" to ensure a value other than the empty string
// is entered, analogous to "required: true" in extension.yaml
input: { text: { nonEmpty: true } }
}),
參數名稱不變,因此現有的 .env 仍可正常運作。
執行個體 ID
擴充功能會從擴充功能執行階段插入的 EXT_INSTANCE_ID 讀取執行個體 ID。函式套件會從 FIREBASE_KIT_INSTANCE_ID 讀取例項 ID,Firebase CLI 則會為每個套件例項設定例項 ID,並將其對應至 firebase.json 中 instances 地圖的例項鍵。CLI 會在部署時探索、在模擬器中,以及在已部署的函式中提供這項資訊。
執行個體 ID 不是參數,因此請勿使用 defineString 宣告。事實上,FIREBASE_... 是 .env 檔案中的保留前置字元,因此使用者無法在該處設定或覆寫。CLI 插入的值不會顯示在參數系統中。直接從環境讀取:
// Before
const instanceId = process.env.EXT_INSTANCE_ID;
// After
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
只有在將套件部署為套件時,系統才會設定變數。如果您的程式碼也部署為獨立程式碼集 (請參閱步驟 9),請將其視為選用項目,或在缺少時快速失敗並顯示清楚的訊息。如果擴充功能將執行個體 ID 顯示為面向使用者的參數,您必須移除該參數,因為 Firebase CLI 現在擁有該值。
工作範例:刪除使用者資料
(Stream Cloud Firestore to BigQuery 擴充功能不會讀取執行個體 ID,因此沒有任何內容可遷移。(刪除使用者資料擴充功能會使用這個 ID 為 Pub/Sub 主題命名)。
變更前。在 config.ts 中以原始環境變數的形式讀取,並加上 Extensions 用於資源的 ext- 前置字元:
// functions/src/config.ts
discoveryTopic: `ext-${process.env.EXT_INSTANCE_ID}-discovery`,
deletionTopic: `ext-${process.env.EXT_INSTANCE_ID}-deletion`,
變更後。process.env讀取FIREBASE_KIT_INSTANCE_ID的簡單範例,用於兩個一般參數,讓使用者可以覆寫主題名稱:
// src/config.ts
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
// Non-empty defaults so Pub/Sub trigger bindings resolve during deploy
// discovery without freezing an empty topic name into the manifest.
discoveryTopicName: defineString("DISCOVERY_TOPIC_NAME", {
default: `kit-${instanceId}-discovery`,
}),
deletionTopicName: defineString("DELETION_TOPIC_NAME", {
default: `kit-${instanceId}-deletion`,
}),
預設值不得為空白,因為觸發程序繫結會在探索期間解析。空白預設值會寫入部署資訊清單,做為主題名稱。此外,這個套件還能防禦在套件環境以外執行的作業。如果缺少變數,模組層級的預設值會評估為 kit-undefined-discovery,因此設定載入器會失敗,並顯示說明錯誤:
// ...
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
if (!instanceId) {
throw new Error(
"FIREBASE_KIT_INSTANCE_ID is not set. It is provided automatically to " +
"kit instances by firebase-tools >= 15.32.0; deploy or emulate this " +
"kit with a supported CLI version."
);
}
// ...
處理常式首次解析設定時,系統會執行這項檢查,因此缺少變數會產生明確的執行階段錯誤,而不是函式無聲無息地繫結至 kit-undefined-* 主題。如要拒絕部署作業本身,請在模組範圍執行檢查,以便在探索期間執行檢查。由於 CLI 會從 firebase.json 衍生執行個體 ID,因此沒有可設定的 INSTANCE_ID,也不需要在多個執行個體之間保持同步。
密鑰
在 extension.yaml 中,您可以使用 type: secret 宣告密鑰。擴充功能執行階段會儲存並繫結這些值,因此擴充功能程式碼可以直接讀取 process.env.PARAM_NAME。在典型的 Cloud Functions 程式碼集,您會明確宣告及繫結每個密鑰:
import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/https";
const apiKey = defineSecret("API_KEY");
export const fn = onRequest({ secrets: [apiKey] }, handler);
將擴充功能遷移至 npm 套件/套件後,機密參照就會在使用者 .env 檔案中管理。請務必不要變更程式碼中宣告的密碼名稱。遷移期間,系統會一併遷移使用者密碼。
實際範例:從 Cloud Firestore 觸發電子郵件
變更前。MAIL_COLLECTION 和 SMTP_PASSWORD 會在 config.ts 中讀取為原始環境變數:
# extension.yaml
- param: MAIL_COLLECTION
label: Email documents collection
type: string
default: mail
required: true
- param: SMTP_PASSWORD
label: SMTP password
type: secret
// functions/src/config.ts
mailCollection: process.env.MAIL_COLLECTION,
smtpPassword: process.env.SMTP_PASSWORD,
變更後。一個 defineString 和一個 defineSecret;CLI 會同時探索這兩者,並從 .env 讀取:
import { defineString, defineSecret } from "firebase-functions/params";
import { onDocumentWritten } from "firebase-functions/firestore";
const mailCollection = defineString("MAIL_COLLECTION", {
label: "Email documents collection",
default: "mail"
});
const smtpPassword = defineSecret("SMTP_PASSWORD", { label: "SMTP password" });
export const processQueue = onDocumentWritten(
{ document: `${mailCollection}/{documentId}`, secrets: [smtpPassword] },
async (event) => {
const collection = mailCollection.value();
const password = smtpPassword.value();
// ...
}
);
5. 遷移內部工作佇列呼叫
部分擴充功能會使用 Firebase Admin SDK,從函式程式碼內部將工作加入自己的工作佇列。這與接收已派送的工作不同 (請參閱「升級函式」和「轉換生命週期掛鉤」一節)。這裡的程式碼是呼叫 queue.enqueue(...) 的生產端。
舊版 Admin SDK 需要擴充功能傳遞自己的擴充功能例項 ID 做為第二個參數,才能指定相同擴充功能中的工作佇列函式。自 firebase-admin 14.2.0 起,這項設定既非必要,也不建議使用。Task Queue API 現在預設會以相同環境中的工作佇列為目標 (例如擴充功能或套件)。建議您在程式碼中移除這個參數,無論是做為擴充功能還是獨立函式,都是安全無虞。移除這項參數可確保可攜性及向前相容性。
佇列呼叫的其他部分 (包括 locations/<region>/functions/<name> 資源路徑、工作負載和重試邏輯) 則維持不變。
如要進一步瞭解如何使用 Cloud Tasks 將函式加入佇列,請參閱「使用 Cloud Tasks 將函式加入佇列」。
變更前。第 1 代擴充功能:
import { getFunctions } from "firebase-admin/functions";
const queue = getFunctions().taskQueue(
`locations/${config.location}/functions/syncBigQuery`,
process.env.EXT_INSTANCE_ID, // extension instance ID, injected by the runtime
);
await queue.enqueue(taskData);
變更後。第 2 代擴充功能:
import { getFunctions } from "firebase-admin/functions";
const queue = getFunctions().taskQueue(
`locations/${process.env.FUNCTION_REGION}/functions/syncBigQuery`
);
await queue.enqueue(taskData);
如果佇列呼叫的目標是加上前置字元的程式碼集,則探索到的函式名稱也會加上前置字元 (例如 orders-syncBigQuery);請參閱「查看並安裝替代函式套件例項」和「以函式套件形式測試」。
6. 宣告必要 API 和 IAM 角色
將擴充功能的 IAM 和 API 需求從 extension.yaml 移至程式碼:
import { requiresAPI, requiresRole } from "firebase-functions";
requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");
使用宣告式安全機制時,Firebase CLI 會為程式碼集建立或更新受管理執行階段服務帳戶,並授予所有已宣告角色的聯集。向使用者說明程式碼集中的所有函式都會以這些角色執行,除非最終 API 支援範圍較窄的模型。
範例:將 Stream Cloud Firestore 轉移至 BigQuery
變更前。在 extension.yaml 中宣告;擴充功能執行階段已啟用 API,並將角色授予受管理帳戶:
apis:
- apiName: bigquery.googleapis.com
roles:
- role: bigquery.dataEditor
- role: datastore.user
- role: bigquery.user
變更後。在程式碼中以 requiresAPI 和 requiresRole 宣告:
import { requiresAPI, requiresRole } from "firebase-functions";
requiresAPI(
"bigquery.googleapis.com",
"Needed to write changelog rows and views"
);
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/datastore.user");
requiresRole("roles/bigquery.user");
7. 轉換生命週期掛鉤
如果擴充功能呼叫 getExtensions().runtime() (例如 setProcessingState 或 setFatalError),請刪除這些呼叫,因為從正常部署的第 2 代函式呼叫時,這些呼叫會擲回錯誤。生命週期狀態現在由 afterFirstDeploy 和 afterRedeploy 驅動,因此不會使用這個狀態追蹤功能。
使用者安裝、更新或重新設定擴充功能時,Firebase Extensions 可以執行設定。在 npm 套件中,以程式碼宣告對等的生命週期動作。
一次性設定:
import { afterFirstDeploy } from "firebase-functions/lifecycle";
import { onTaskDispatched } from "firebase-functions/tasks";
export const runInitialSetup = onTaskDispatched(async (request) => {
await initializeResources(request.data);
});
afterFirstDeploy({
task: {
function: "runInitialSetup",
body: {}
}
});
更新設定或程式碼:
import { afterRedeploy } from "firebase-functions/lifecycle";
afterRedeploy({
task: {
function: "runInitialSetup",
body: { reconcile: true }
}
});
讓生命週期動作具備等冪性。如果調度或執行失敗,使用者可能需要手動重新執行:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME
範例:將 Stream Cloud Firestore 轉移至 BigQuery
變更前。lifecycleEvents,原因是擴充功能執行階段:extension.yaml
lifecycleEvents:
onInstall:
function: initBigQuerySync
processingMessage: Configuring BigQuery Sync.
onUpdate:
function: setupBigQuerySync
processingMessage: Configuring BigQuery Sync
onConfigure:
function: setupBigQuerySync
processingMessage: Configuring BigQuery Sync
變更後。在程式碼中宣告;工作會在首次部署時提供 BigQuery:
import { afterFirstDeploy, afterRedeploy } from "firebase-functions/lifecycle";
afterFirstDeploy({ task: { function: "initBigQuerySync" } });
afterRedeploy({ task: { function: "setupBigQuerySync" } });
佈建作業是冪等作業,因此重新執行會協調資料集、資料表和檢視區塊。
使用者可以按 firebase functions:lifecycle:run afterFirstDeploy
CODEBASE_NAME 鍵手動重新執行。
8. 為使用者設定文件
撰寫套件 README,至少說明下列事項:
- 套件要求的
.env值。 - 套件所需的密鑰,以及如何遷移現有的密鑰值。
- 套件透過
requiresRole(...)宣告的 IAM 角色。 - 套件啟用或需要的 Google API。
- 套件宣告的生命週期掛鉤,以及如何手動重新執行這些掛鉤。
- 帳單附註。
- 與原始擴充功能相比,有哪些變更。
- 套件如何取得執行個體 ID (由 CLI 設定的
FIREBASE_KIT_INSTANCE_ID),以及所有執行個體的函式都以kit-<instanceId>-前置字元部署。
範例:將 Stream Cloud Firestore 移至 BigQuery
套件 README 會傳送具體的「變更內容」表格:
| 疑慮 | 以擴充功能形式 | 如 @firebase-function-kits/firestore-bigquery-export |
|---|---|---|
| 設定 | 擴充功能參數 | Cloud Functions 透過 .env 傳送參數 |
| IAM | 擴充功能授予 | requiresRole(...),在部署時套用 |
| 佈建中 | 擴充功能生命週期工作 | afterFirstDeploy 項工作 (共 afterRedeploy 項) |
| 函式名稱 | ext-<instanceId>-fsexportbigquery |
fsexportbigquery (可選擇加上前置字串) |
| 執行個體 ID | EXT_INSTANCE_ID 擴充功能插入 |
FIREBASE_KIT_INSTANCE_ID,由 CLI 從 firebase.json 設定 |
9. 測試第 2 代函式
現在您應該會有第 2 代函式,部署後行為與擴充功能的新安裝項目相同。下一步是驗證並修正過程中意外發生的任何問題。
如要呼叫 setGlobalOptions 設定預設區域或 CPU 等全域選項,您必須以獨立的第 2 代函式部署套件。當套件以 npm 套件的形式安裝時,使用者會在包裝程式碼中呼叫 setGlobalOptions 來設定這些參數,如果發生兩次,系統就會發出警告。您可以檢查 FIREBASE_KIT_INSTANCE_ID 環境變數,確保安全地呼叫這個函式:
import { setGlobalOptions } from "firebase-functions";
if (!process.env.FIREBASE_KIT_INSTANCE_ID) {
setGlobalOptions({
region: "us-east1",
maxInstances: 10,
});
}
請務必使用 firebase-tools
>= 15.32.0,並將轉換後的第 2 代函式部署至測試專案,搭配適當的資源測試其行為。如果您已設定測試專案來測試擴充功能,請執行下列指令:
firebase deploy --only functions
填寫精靈顯示的參數值提示,方式與在擴充功能的 Firebase 控制台中填寫安裝表單相同。
範例:將 Stream Cloud Firestore 移至 BigQuery
我們會驗證 Cloud Firestore 到 BigQuery 的端對端同步:
- 在 Firebase 控制台的 Cloud Firestore 頁面中,建立您設為
COLLECTION_PATH(users) 的集合 (如果還沒有的話)。 - 建立名為
bigquery-mirror-test的文件,其中包含任何欄位和值。 在 Google Cloud 控制台的 BigQuery 頁面中,查詢原始變更記錄表。其中應包含記錄文件建立作業的單一資料列:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`查詢最新檢視畫面,系統應會傳回唯一存在的文件 (
bigquery-mirror-test) 的最新變更事件:SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`刪除 Cloud Firestore 中的
bigquery-mirror-test文件。該項目會從最新檢視畫面中消失,且DELETE事件會附加至原始變更記錄表。您可以使用下列指令檢查單一文件的完整記錄:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog` WHERE document_name = "bigquery-mirror-test" ORDER BY timestamp ASC
與測試擴充功能的不同之處:
- 觸發條件會部署為
fsexportbigquery(部署為一般第 2 代函式而非套件時,沒有前置字元),而不是ext-<instanceId>-fsexportbigquery。在 Cloud Functions 資訊主頁和記錄中尋找該名稱。 - 現在,您的程式碼會在 Firebase Local Emulator Suite 中以一般函式執行。您可以使用
.env.local設定要在模擬器中使用的參數值。您也可以使用firebase-functions-testSDK 進行程式碼單元測試,詳情請參閱「Cloud Functions 的單元測試」。 - 佈建作業不再由 Extensions 執行階段驅動。如果部署後缺少變更記錄表格,請手動重新執行設定工作:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME。這項工作是等冪的,因此重新執行工作會協調資料集、表格和檢視區塊。 - 參數值來自
.env,而非安裝表單,因此.env完成後,firebase deploy的重新執行作業不會有互動。
10. 在 npm 發布函式套件
確認擴充功能已轉換為第 2 代函式後,您可以將候選版本發布至 npm,並使用下列任一指南進行端對端測試:
將套件發布至 npm 後,即可使用 firebase functions:kits:install 安裝,並列為擴充功能的官方替代項目。
強烈建議您先發布候選版本。套件是依據套件名稱和版本安裝,因此預先發布版本可讓您針對登錄檔測試實際安裝流程,而不會向使用預設 latest 標記安裝套件的使用者公開未完成的套件。
發布前:
- 選擇套件名稱。有範圍和無範圍的名稱都適用 (請參閱上方的指南)。請注意,範圍套件預設為私有,因此請傳遞
--access public。 - 建造並檢查船隻。
main和types會指向編譯後的輸出內容 (在我們的範例中為lib/),因此該目錄必須納入發布的 tar 檔案。使用.npmignore或files允許清單,並使用npm pack --dry-run檢查結果。執行建構作業的prepublishOnly指令碼可防止發布過時的輸出內容。
package.json 新增功能,預設確保發布安全:
{
"files": ["lib", "README.md", "CHANGELOG.md"],
"publishConfig": { "access": "public", "tag": "next" },
"scripts": {
"build": "tsc -b",
"prepublishOnly": "npm run build && npm test"
}
}
"publishConfig": { "tag": "next" } 欄位可確保純文字 npm
publish 絕不會覆寫 latest。
發布候選版本:
舉例來說,如要在本機將版本從 0.0.2-rc.3 遞增至 0.0.2-rc.4
(如果 package.json 位於存放區根目錄,這會在 Git 中提交及標記):
npm version prerelease --preid rc
如要發布候選版本並在 npm 上以 next 標記註冊 @your-org/your-kit@0.0.2-rc.4:
npm publish
npm 網站可能需要幾分鐘才會顯示新版本;npm view 會直接讀取登錄檔:
npm view @your-org/your-kit versions dist-tags
完成本指南的步驟 11 和步驟 12 後,即可將套件升級為穩定版:
npm version 0.0.2
npm publish --tag latest
npm dist-tag add @your-org/your-kit@0.0.2 next
npm-shrinkwrap.json注意事項:強烈建議在套件中加入 npm-shrinkwrap.json 檔案,否則 CLI 會在安裝時向使用者發出警告。確保使用者使用您測試過的確切依附元件,並防範供應鏈攻擊。不過,縮包會逐字套用至使用者的專案,包括在 Cloud Functions 建構 (npm ci) 期間,其中僅限開發人員的項目可能會失敗並顯示 EBADPLATFORM。您可能需要從發布的收縮包副本中,移除 "dev": true 項目和 devDependencies。
範例:將 Stream Cloud Firestore 轉移至 BigQuery
套件在第四個候選版本發布時的 package.json:
{
"name": "@firebase-function-kits/firestore-bigquery-export",
"version": "0.0.2-rc.4",
"repository": {
"type": "git",
"url": "https://github.com/firebase/extensions.git",
"directory": "kits/firestore-bigquery-export"
},
"main": "lib/index.js",
"types": "lib/index.d.ts",
"engines": { "node": "22" },
"scripts": { "build": "tsc -b" }
}
請注意,在本例中,套件位於單一存放區,因此請務必加入 repository.directory,讓 npm 登錄連結指向正確的資料夾。其 CHANGELOG.md會保留待處理版本的附註。
11. 以函式套件形式測試
發布套件後,建議使用 npm 測試套件。
請確認您使用的是 firebase-tools >= 15.32.0 版,並安裝套件:
firebase functions:kits:install --package <your-package-name>@<your-prerelease-version>
這會從 npm 下載套件,在套件的新來源目錄中設定套件,並逐步引導您設定第一個執行個體,與擴充功能安裝流程類似。在本地安裝及設定套件後,請執行部署作業,在 Google Cloud 專案中建立資源:
firebase deploy --only functions:<your-kit-instance-id>
安裝完成後,Firebase CLI 會列印類似的部署指令,其中包含您在安裝期間選擇的確切執行個體 ID。
請按照
步驟 9 的說明,再次驗證套件。測試第 2 代函式。現在您使用套件部署,函式會加上前置字元,並命名為 kit-<instance-id>-<method-name>。這樣一來,套件就能有多個執行個體,在專案中多次部署相同函式,且每個函式都有專屬名稱。
12. 測試遷移替換
您可以設定運作中的擴充功能例項,然後使用使用者遷移指南 (使用 firebase ext:migrate --package 或函式套件 CLI 指令),完成函式套件的測試,做為遷移替代方案。
13. 通知使用者和 Google 官方擴充功能替代方案
函式套件替代方案準備就緒並以 npm 套件形式提供後,請通知使用者和 Google 這項官方替代方案。在 GitHub 存放區中更新 README.md 檔案,其中包含下列資訊:
<!-- FIREBASE_EXTENSION_REPLACEMENT: extension="<your-extesion-id>" package="<your-npm-package-name>" -->
> [!WARNING]
> **Deprecation Notice:** The Firebase Extension `<your-extension>` is deprecated. Migrate to the [<your-npm-package-name>](<link-to-your-npm-package>) package.
Google 會掃描已知的擴充功能 README,找出類似 <!--
FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export"
package="@firebase-function-kits/firestore-bigquery-export" --> 的註解,並使用這些註解填入官方替代項目登錄檔,該登錄檔會儲存在 firebase-tools 存放區中,形式為 replacements.json。您也可以查看 replacements.json,瞭解系統會掃描哪些擴充功能 README.md。官方更換清單每週都會更新。
範例:將 Stream Cloud Firestore 移至 BigQuery
「firestore-bigquery-export」擴充功能
README.md
包含:
<!-- FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export" package="@firebase-function-kits/firestore-bigquery-export" -->
> [!WARNING]
> **Deprecation Notice:** The Firebase Extension `firebase/firestore-bigquery-export` is deprecated. Please migrate to the [`@firebase-function-kits/firestore-bigquery-export`](https://www.npmjs.com/package/@firebase-function-kits/firestore-bigquery-export) package.