Panduan ini menunjukkan cara memigrasikan ekstensi Anda dari lingkungan Firebase Extensions yang tidak digunakan lagi ke fungsi yang diinstal dan di-deploy pengguna di Cloud Functions mereka sendiri untuk codebase Firebase (generasi ke-2).
Ini adalah jalur migrasi yang direkomendasikan. Firebase akan mengelola daftar ekstensi dengan padanan npm resmi; panduan ini akan memandu Anda membuat ekstensi sendiri.
Di seluruh panduan ini, ekstensi Stream Cloud Firestore to
BigQuery (firestore-bigquery-export) digunakan sebagai contoh yang sedang berjalan. Setiap
bagian diakhiri dengan Contoh penggunaan yang menunjukkan tampilan ekstensi tersebut sebelum migrasi, dan tampilannya setelah migrasi, sebagai paket
@firebase-function-kits/firestore-bigquery-export.
Daftar untuk mendapatkan informasi dan bantuan selengkapnya tentang memigrasikan ekstensi
Jika ada pertanyaan tentang cara bermigrasi dari Firebase Extensions, Anda dapat menghubungi kami di firebase-extensions-migrator-support-external@google.com. Kami juga akan mengirimkan email kepada grup ini saat kami memperbarui panduan dengan informasi selengkapnya tentang pengemasan, pengujian, dan pendistribusian fungsi generasi ke-2 Anda.
Untuk bergabung dengan grup ini, kirim pesan ke firebase-extensions-migrator-support-external+subscribe@google.com, yang akan merespons dengan email permintaan keanggotaan. Anda harus membalas email tersebut, bukan mengklik tombol "Gabung ke Grup Ini".
Sebelum memulai
Untuk menyelesaikan migrasi ini sesuai petunjuk, Anda akan menggunakan fitur Cloud Functions berikut:
Konfigurasi Berparameter. Setiap parameter yang Anda deklarasikan di
extension.yamlakan menjadi parameter yang ditentukan dalam kode paket Anda.Peran IAM deklaratif dan API yang diperlukan. Setiap peran yang Anda deklarasikan di
extension.yamlmenjadi panggilanrequiresRole(...), dan setiap API menjadi panggilanrequiresAPI(...)dalam kode paket Anda. Pada waktu deployment, CLI Firebase memberikan peran yang dideklarasikan ke akun layanan runtime terkelola dan mengaktifkan API yang dideklarasikan atas nama Anda.Peristiwa siklus proses untuk codebase Cloud Functions. Basis kode Cloud Functions kini mendukung peristiwa siklus proses yang serupa dengan Firebase Extensions. Deklarasikan penyiapan waktu penginstalan dan waktu update dengan hook siklus proses
afterFirstDeploy(...)danafterRedeploy(...). Hal ini menggantikanlifecycleEventsyang Anda deklarasikan diextension.yaml.
Memigrasikan sumber Firebase Extensions ke fungsi generasi ke-2
(Opsional) Migrasi otomatis dengan Keahlian Agen Firebase
Anda dapat mengotomatiskan Langkah 1 hingga 8 (menginventarisir resource, memicu upgrade, konversi param dan secret, IAM deklaratif, hook siklus proses, dan membuat README paket) menggunakan keterampilan agen AI extension-to-functions-codebase resmi.
Menginstal keahlian
Jika Anda atau asisten coding AI Anda (Gemini di Firebase, Cursor, Claude Code, GitHub Copilot) belum menginstal keahlian, jalankan perintah berikut menggunakan CLI keahlian:
npx skills add firebase/agent-skills --skill extension-to-functions-codebase
Setelah skill diinstal di project Anda, asisten coding AI Anda akan mengikuti aturan migrasi dan langkah-langkah transformasi secara otomatis. Anda dapat menggunakan perintah berikut:
"Migrasikan Ekstensi Firebase ini ke paket Kit Fungsi Generasi ke-2 yang dapat dipublikasikan dengan mengikuti petunjuk dalam extension-to-functions-codebase
skill."
1. Menginventaris ekstensi
Mulailah dengan membuat inventaris ekstensi Anda: daftar lengkap semua hal yang dideklarasikan, dikirim, dan didokumentasikan oleh ekstensi, sehingga setiap perilaku memiliki tujuan yang ditentukan dalam fungsi generasi ke-2 dan tidak ada yang hilang dalam migrasi.
Tinjau setiap hal berikut, dan catat apa yang Anda temukan:
extension.yaml, yang mendeklarasikan parameter, fungsi, peristiwa, peran IAM, API yang diperlukan, rahasia, dan hook siklus proses.functions/, yang berisi kode fungsi, dependensi, konfigurasi build, pemicu, dan fungsi task queue.README.md,PREINSTALL.md, danPOSTINSTALL.md, yang berisi langkah-langkah penyiapan, peringatan, dan catatan penagihan.scripts/, yang berisi utilitas impor, pengisian ulang, IAM, perbaikan, atau migrasi, dan alat lainnya yang Anda kirimkan bersama ekstensi.
Kemudian, untuk setiap item di
extension.yaml, tentukan lokasi
item tersebut dalam paket npm:
Konversi konfigurasi pengguna menjadi parameter Cloud Functions (Langkah 4).
Konversi secret menjadi secret Cloud Functions (Langkah 4).
Konversi peran IAM menjadi deklarasi
requiresRole(...)(Langkah 6).Konversi Google API yang diperlukan menjadi deklarasi
requiresAPI(...)jika sesuai (Langkah 6).Konversi hook penginstalan dan update menjadi deklarasi
afterFirstDeploy(...)danafterRedeploy(...)(Langkah 7).Mengonversi ID instance dari
EXT_INSTANCE_IDkeFIREBASE_KIT_INSTANCE_ID(Langkah 4).
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Membaca firestore-bigquery-export/extension.yaml dan functions/ menghasilkan inventaris ini:
Di extension.yaml |
Jumlah / nilai | Tujuan |
|---|---|---|
params |
25 (COLLECTION_PATH, DATASET_ID, TABLE_ID, DATASET_LOCATION, VIEW_TYPE, …) |
Cloud Functions params (Langkah 4) |
apis |
bigquery.googleapis.com |
requiresAPI(...) (Langkah 6) |
roles |
bigquery.dataEditor, datastore.user, bigquery.user |
requiresRole(...) (Langkah 6) |
resources |
1 pemicu peristiwa (fsexportbigquery) + fungsi task queue (initBigQuerySync, setupBigQuerySync) |
Fungsi paket yang diekspor (Langkah 3) |
lifecycleEvents |
onInstall → initBigQuerySync; onUpdate / onConfigure → setupBigQuerySync |
afterFirstDeploy / afterRedeploy (Langkah 7) |
| ID instance | Tidak digunakan (tidak ada pembacaan EXT_INSTANCE_ID) |
Tidak ada yang perlu dimigrasikan |
scripts/ |
import/ (pengisian ulang), gen-schema-view/ |
Disimpan sebagai skrip (di luar cakupan di sini) |
Analisis. Ekstensi tidak mendeklarasikan parameter type: secret, sehingga tidak ada yang perlu dimigrasikan untuk rahasia di Langkah 4. Pemicu
peristiwa sudah berupa generasi ke-2; hanya fungsi task queue yang masih berupa generasi
ke-1 (relevan di Langkah 3).
2. Perbarui package.json
Perbarui file package.json ekstensi Anda. Jika Anda memigrasikan satu ekstensi, ekstensi ini dapat menjadi package.json root. Jika Anda memigrasikan banyak ekstensi dalam satu repositori, berikan setiap ekstensi paketnya sendiri.
Versi SDK minimum: Deklarasikan
firebase-functions >=
7.4.0 dan firebase-admin >=
14.2.0 sebagai dependensi. Deklarasikan versi firebase-functions Anda sebagai dependensi
peer juga, sehingga project Cloud Functions pengguna Anda memiliki
versi SDK yang sama dengan yang digunakan untuk menulis library Anda.
{
"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"
}
}
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Sebelum. functions/package.json ekstensi bersifat pribadi, memberi nama
ID ekstensi, dan mendeklarasikan firebase-functions sebagai dependensi langsung:
{
"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"
}
}
Setelah. Paket yang dapat dipublikasikan: nama yang diberi cakupan, peta exports, dan
firebase-functions dipindahkan ke 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. Mengupgrade fungsi dari generasi ke-1 ke generasi ke-2
Jika ekstensi Anda masih mengekspor fungsi generasi ke-1, konversi setiap pemicu ke
pemicu generasi ke-2 yang setara. Impor dari modul firebase-functions/..., dan teruskan setelan runtime di opsi pemicu.
Lihat panduan upgrade generasi ke-2 Cloud Functions. Khususnya, Anda dapat meminimalkan upaya penulisan ulang dengan menggunakan penghancuran struktur peristiwa yang di-patch generasi ke-2 dan menghindari penulisan ulang logika fungsi karena SDK generasi ke-2 mengekspos parameter v1 sebagai kolom dalam objek peristiwa, sehingga Anda dapat menggunakan parameter yang dihancurkan/dinamai dan mempertahankan logika bisnis Anda tanpa perubahan.
Sebelum. Generasi ke-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);
});
Setelah. Generasi ke-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)
);
Lihat perbandingan versi Cloud Functions untuk mengetahui daftar lengkap perbedaan antara fungsi generasi ke-1 dan generasi ke-2.
4. Mengonversi parameter dan secret ekstensi
Params
Setiap parameter yang Anda deklarasikan di extension.yaml akan menjadi parameter Cloud Functions.
Mengonversi pembacaan lingkungan langsung:
const collectionPath = process.env.COLLECTION_PATH;
ke dalam parameter 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);
}
);
Gunakan collectionPath.value() untuk membaca string di dalam handler; gunakan
collectionPath secara langsung di tempat placeholder diharapkan, seperti jalur pemicu
fungsi.
CLI Firebase menemukan parameter Anda dan membaca nilainya dari .env,
.env.<projectId>, atau meminta pengguna Anda selama deployment. Pertahankan nama
parameter yang sama, sehingga nilai dari penginstalan yang ada akan dipertahankan.
Anda tidak boleh mengubah nama parameter yang dideklarasikan dalam kode Anda sama sekali. Migrasi ekstensi mempertahankan nilai parameter pengguna akhir yang ada secara otomatis, tetapi hanya jika namanya tidak berubah.
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Sebelum. Parameter yang dideklarasikan di extension.yaml, dibaca sebagai variabel
lingkungan mentah di config.ts:
# extension.yaml
- param: COLLECTION_PATH
label: Collection path
type: string
required: true
// functions/src/config.ts
collectionPath: process.env.COLLECTION_PATH,
Setelah. Satu defineString; CLI menemukannya dan membaca dari .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 } }
}),
Nama parameter tidak berubah, sehingga .env yang ada tetap berfungsi.
ID instance
Ekstensi membaca ID instance-nya dari EXT_INSTANCE_ID, yang disuntikkan oleh
runtime Ekstensi. Kit fungsi membaca ID instance-nya dari FIREBASE_KIT_INSTANCE_ID, yang ditetapkan oleh CLI Firebase untuk setiap instance kit ke kunci instance dalam peta instances di firebase.json. CLI menyediakannya selama penemuan waktu deployment, di emulator, dan ke fungsi yang di-deploy.
ID instance bukan merupakan parameter, jadi jangan deklarasikan dengan defineString. Sebenarnya,
FIREBASE_... adalah awalan yang dicadangkan dalam file .env, sehingga pengguna tidak akan dapat
menyetel atau menggantinya di sana. Nilai yang dimasukkan CLI tidak terlihat oleh sistem
parameter. Membacanya langsung dari lingkungan:
// Before
const instanceId = process.env.EXT_INSTANCE_ID;
// After
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
Variabel hanya akan ditetapkan saat paket Anda di-deploy sebagai kit. Jika kode Anda juga di-deploy sebagai codebase mandiri (lihat Langkah 9), perlakukan kode tersebut sebagai opsional atau gagal dengan cepat dengan pesan yang jelas jika kode tersebut tidak ada. Jika ekstensi Anda mengekspos ID instance sebagai parameter yang ditampilkan kepada pengguna, Anda harus menghapus parameter tersebut karena CLI Firebase kini memiliki nilai tersebut.
Contoh penggunaan: Menghapus Data Pengguna
(Ekstensi Cloud Firestore ke BigQuery tidak membaca ID instance-nya, jadi tidak ada yang perlu dimigrasikan di sana. Ekstensi Hapus Data Pengguna menggunakannya untuk memberi nama topik Pub/Sub.)
Sebelum. Dibaca sebagai variabel lingkungan mentah di config.ts dengan awalan ext-
yang digunakan Ekstensi untuk sumber dayanya:
// functions/src/config.ts
discoveryTopic: `ext-${process.env.EXT_INSTANCE_ID}-discovery`,
deletionTopic: `ext-${process.env.EXT_INSTANCE_ID}-deletion`,
Setelah. Pembacaan process.env biasa dari FIREBASE_KIT_INSTANCE_ID yang digunakan untuk
dua parameter biasa sehingga pengguna dapat mengganti nama topik:
// 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`,
}),
Nilai default tidak boleh kosong karena binding pemicu diselesaikan pada
waktu penemuan. Default kosong akan ditulis ke manifes deployment sebagai
nama topik. Kit ini juga defensif terhadap eksekusi di luar konteks kit. Jika variabel tidak ada, default tingkat modul akan dievaluasi menjadi
kit-undefined-discovery, sehingga pemuat konfigurasi gagal dengan error yang menjelaskan
sebagai gantinya:
// ...
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."
);
}
// ...
Pemeriksaan ini berjalan saat pengendali pertama kali menyelesaikan konfigurasinya, sehingga variabel yang tidak ada akan menghasilkan error runtime yang jelas, bukan fungsi yang terikat secara diam-diam ke topik kit-undefined-*. Untuk menolak deployment itu sendiri, lakukan pemeriksaan di cakupan modul sehingga berjalan selama penemuan. Karena CLI mendapatkan ID instance dari firebase.json, tidak ada INSTANCE_ID yang dapat dikonfigurasi, dan tidak ada yang perlu disinkronkan di beberapa instance.
Rahasia
Di extension.yaml, Anda mendeklarasikan secret dengan type: secret. Runtime Ekstensi menyimpan dan mengikatnya, sehingga kode ekstensi Anda dapat membaca process.env.PARAM_NAME secara langsung. Dalam codebase Cloud Functions yang umum,
Anda mendeklarasikan dan mengikat setiap rahasia secara eksplisit:
import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/https";
const apiKey = defineSecret("API_KEY");
export const fn = onRequest({ secrets: [apiKey] }, handler);
Setelah ekstensi dimigrasikan ke paket/kit npm, referensi rahasia dikelola dalam file .env pengguna akhir. Anda tidak boleh mengubah nama rahasia yang dideklarasikan dalam kode Anda sama sekali. Selama migrasi, secret pengguna akhir dimigrasikan sebagaimana mestinya.
Contoh penggunaan: Memicu Email Dari Cloud Firestore
Sebelum. MAIL_COLLECTION dan SMTP_PASSWORD dibaca sebagai variabel lingkungan
mentah di 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,
Setelah. Satu defineString dan satu defineSecret; CLI menemukan keduanya
dan membaca dari .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. Memigrasikan panggilan task queue internal
Beberapa ekstensi mengantrekan tugas ke antrean tugas sendiri dari dalam kode fungsi, menggunakan Firebase Admin SDK. Hal ini berbeda dengan menerima
tugas yang dikirim (dibahas di bagian Mengupgrade fungsi dan Mengonversi hook siklus proses). Di sini, kode Anda adalah produser yang memanggil
queue.enqueue(...).
Versi Admin SDK sebelumnya mengharuskan ekstensi meneruskan ID instance ekstensi mereka sendiri sebagai parameter kedua untuk menargetkan fungsi Task Queue di ekstensi yang sama. Mulai firebase-admin 14.2.0, hal ini tidak diperlukan dan tidak
direkomendasikan. Task Queue API kini menargetkan antrean tugas dalam konteks yang sama (misalnya, ekstensi atau kit) secara default. Parameter ini aman dan sebaiknya dihapus
dalam kode Anda, baik sebagai ekstensi maupun sebagai fungsi mandiri.
Menghapus parameter ini memastikan portabilitas dan kompatibilitas ke depan.
Semua hal lainnya tentang panggilan antrean — jalur resource locations/<region>/functions/<name>, payload tugas, dan logika percobaan ulang — tetap sama.
Baca artikel Mengantrekan fungsi dengan Cloud Tasks untuk mengetahui detail selengkapnya tentang cara mengantrekan fungsi dengan Cloud Tasks.
Sebelum. Ekstensi generasi ke-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);
Setelah. Ekstensi generasi ke-2:
import { getFunctions } from "firebase-admin/functions";
const queue = getFunctions().taskQueue(
`locations/${process.env.FUNCTION_REGION}/functions/syncBigQuery`
);
await queue.enqueue(taskData);
Jika panggilan antrean Anda menargetkan codebase yang diberi awalan, nama fungsi yang ditemukan juga diberi awalan (misalnya, orders-syncBigQuery); lihat
Meninjau dan menginstal instance pengganti kit fungsi
dan Menguji sebagai kit fungsi.
6. Mendeklarasikan API dan peran IAM yang diperlukan
Pindahkan persyaratan IAM dan API ekstensi Anda dari extension.yaml ke dalam
kode:
import { requiresAPI, requiresRole } from "firebase-functions";
requiresAPI("bigquery.googleapis.com", "Needed to write changelog rows");
requiresRole("roles/bigquery.dataEditor");
requiresRole("roles/bigquery.user");
Dengan keamanan deklaratif, CLI Firebase membuat atau memperbarui akun layanan runtime terkelola untuk codebase, dan memberikan gabungan semua peran yang dideklarasikan. Dokumentasikan untuk pengguna Anda bahwa semua fungsi dalam codebase berjalan dengan peran tersebut, kecuali jika API akhir mendukung model yang lebih sempit.
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Sebelum. Dideklarasikan di extension.yaml; runtime Ekstensi mengaktifkan
API dan memberikan peran ke akun terkelola:
apis:
- apiName: bigquery.googleapis.com
roles:
- role: bigquery.dataEditor
- role: datastore.user
- role: bigquery.user
Setelah. Dideklarasikan dalam kode dengan requiresAPI dan 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. Mengonversi hook siklus proses
Jika ekstensi Anda memanggil getExtensions().runtime() (misalnya, setProcessingState atau setFatalError), hapus panggilan tersebut karena akan menampilkan error jika dipanggil dari fungsi generasi ke-2 yang di-deploy secara normal. Status siklus proses
kini didorong oleh afterFirstDeploy dan afterRedeploy, tempat pelacakan status ini
tidak digunakan.
Firebase Extensions dapat menjalankan penyiapan saat pengguna menginstal, mengupdate, atau mengonfigurasi ulang ekstensi. Dalam paket npm, deklarasikan tindakan siklus proses yang setara dalam kode.
Untuk penyiapan satu kali:
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: {}
}
});
Untuk pembaruan konfigurasi atau kode:
import { afterRedeploy } from "firebase-functions/lifecycle";
afterRedeploy({
task: {
function: "runInitialSetup",
body: { reconcile: true }
}
});
Buat tindakan siklus proses Anda bersifat idempoten. Pengguna Anda mungkin perlu menjalankan ulang secara manual jika pengiriman atau eksekusi gagal:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Sebelum. lifecycleEvents di extension.yaml, yang didorong oleh runtime
Ekstensi:
lifecycleEvents:
onInstall:
function: initBigQuerySync
processingMessage: Configuring BigQuery Sync.
onUpdate:
function: setupBigQuerySync
processingMessage: Configuring BigQuery Sync
onConfigure:
function: setupBigQuerySync
processingMessage: Configuring BigQuery Sync
Setelah. Dideklarasikan dalam kode; tugas menyediakan BigQuery pada deployment pertama:
import { afterFirstDeploy, afterRedeploy } from "firebase-functions/lifecycle";
afterFirstDeploy({ task: { function: "initBigQuerySync" } });
afterRedeploy({ task: { function: "setupBigQuerySync" } });
Penyediaan bersifat idempoten, sehingga penayangan ulang akan merekonsiliasi set data, tabel, dan tampilan.
Pengguna dapat menjalankan ulang secara manual dengan firebase functions:lifecycle:run afterFirstDeploy
CODEBASE_NAME.
8. Menyiapkan dokumen untuk pengguna Anda
Tulis paket README yang menjelaskan, setidaknya:
- Nilai
.envyang diperlukan paket. - Secret yang diperlukan paket, dan cara memigrasikan nilai secret yang ada.
- Peran IAM yang dideklarasikan paket dengan
requiresRole(...). - Google API yang diaktifkan atau diperlukan oleh paket.
- Hook siklus proses yang dideklarasikan paket, dan cara menjalankannya ulang secara manual.
- Catatan penagihan.
- Apa yang berubah dibandingkan dengan ekstensi asli.
- Cara paket mendapatkan ID instance-nya (
FIREBASE_KIT_INSTANCE_IDyang ditetapkan oleh CLI) dan semua fungsi instance di-deploy dengan awalankit-<instanceId>-.
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Paket README mengirimkan tabel "apa yang berubah" yang konkret:
| Kepedulian | Sebagai ekstensi | Sebagai @firebase-function-kits/firestore-bigquery-export |
|---|---|---|
| Konfigurasi | Parameter ekstensi | Cloud Functions params melalui .env |
| IAM | Diberikan oleh Ekstensi | requiresRole(...), diterapkan saat deployment |
| Penyediaan | Tugas siklus proses menurut Ekstensi | afterFirstDeploy / afterRedeploy tugas |
| Nama fungsi | ext-<instanceId>-fsexportbigquery |
fsexportbigquery (dapat diawali) |
| ID instance | EXT_INSTANCE_ID yang dimasukkan oleh Ekstensi |
FIREBASE_KIT_INSTANCE_ID, ditetapkan oleh CLI dari firebase.json |
9. Menguji fungsi generasi ke-2
Sekarang Anda akan memiliki fungsi generasi ke-2 yang, saat di-deploy, berperilaku sama dengan penginstalan baru ekstensi Anda. Langkah berikutnya adalah memverifikasi dan memperbaiki masalah yang tidak sengaja muncul selama proses tersebut.
Untuk memanggil setGlobalOptions
guna menyetel opsi global seperti region atau CPU default, Anda hanya boleh melakukannya saat
men-deploy kit sebagai fungsi generasi ke-2 mandiri. Saat diinstal sebagai paket npm, pengguna Anda akan memanggil setGlobalOptions dalam kode pembungkusnya untuk mengonfigurasi parameter ini, dan mereka akan mendapatkan peringatan jika hal ini terjadi dua kali.
Anda dapat melindungi panggilan ini dengan memeriksa variabel lingkungan FIREBASE_KIT_INSTANCE_ID:
import { setGlobalOptions } from "firebase-functions";
if (!process.env.FIREBASE_KIT_INSTANCE_ID) {
setGlobalOptions({
region: "us-east1",
maxInstances: 10,
});
}
Pastikan Anda menggunakan
firebase-tools
>= 15.32.0, dan men-deploy fungsi generasi ke-2 yang dikonversi ke project pengujian
dengan resource yang sesuai untuk menguji perilakunya. Jika Anda sudah menyiapkan project pengujian dari pengujian ekstensi, jalankan perintah berikut:
firebase deploy --only functions
Isi wizard yang muncul dan meminta nilai parameter dengan cara yang sama seperti Anda mengisi formulir penginstalan di konsol Firebase untuk ekstensi.
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Kami memverifikasi sinkronisasi Cloud Firestore ke BigQuery secara end-to-end:
- Di halaman Cloud Firestore pada konsol Firebase, buat koleksi
yang Anda tetapkan sebagai
COLLECTION_PATH(users) jika belum ada. - Buat dokumen bernama
bigquery-mirror-testyang berisi kolom apa pun dengan nilai apa pun. Di halaman BigQuery pada konsol Google Cloud, kueri tabel log perubahan mentah. Tabel ini harus berisi satu baris yang mencatat pembuatan dokumen:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`Kueri tampilan terbaru, yang akan menampilkan peristiwa perubahan terbaru untuk satu-satunya dokumen yang ada (
bigquery-mirror-test):SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`Hapus dokumen
bigquery-mirror-testdi Cloud Firestore. Perubahan ini akan hilang dari tampilan terbaru, dan peristiwaDELETEditambahkan ke tabel log perubahan mentah.Anda dapat memeriksa histori lengkap satu dokumen dengan:
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog` WHERE document_name = "bigquery-mirror-test" ORDER BY timestamp ASC
Perbedaan dari pengujian ekstensi:
- Pemicu di-deploy sebagai
fsexportbigquery(tanpa awalan saat di-deploy sebagai fungsi generasi ke-2 biasa, bukan kit), bukanext-<instanceId>-fsexportbigquery. Cari nama tersebut di dasbor dan log Cloud Functions. - Kode Anda kini berjalan di Firebase Local Emulator Suite sebagai fungsi normal.
Anda dapat menetapkan nilai parameter yang akan digunakan di emulator dengan
.env.local. Anda juga dapat melakukan pengujian unit pada kode menggunakan SDKfirebase-functions-testseperti yang dijelaskan dalam Pengujian unit Cloud Functions. - Penyediaan tidak lagi didorong oleh runtime Ekstensi. Jika tabel log perubahan tidak ada setelah deployment, jalankan ulang tugas penyiapan secara manual:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME. Tugas ini bersifat idempoten, sehingga menjalankan ulang tugas ini akan merekonsiliasi set data, tabel, dan tampilan. - Nilai parameter berasal dari
.env, bukan formulir penginstalan, sehinggafirebase deployyang dijalankan ulang tidak interaktif setelah.envselesai.
10. Memublikasikan kit fungsi Anda di npm
Setelah memvalidasi konversi dari ekstensi ke fungsi generasi ke-2, Anda dapat memublikasikan kandidat rilis ke npm untuk pengujian end-to-end menggunakan salah satu panduan berikut:
- Membuat dan memublikasikan paket publik yang tidak tercakup
- Membuat dan memublikasikan paket publik yang tercakup
Setelah dipublikasikan ke npm, kit Anda dapat diinstal dengan
firebase functions:kits:install dan dicantumkan sebagai
pengganti resmi untuk ekstensi Anda.
Sebaiknya publikasikan kandidat rilis terlebih dahulu. Kit diinstal berdasarkan nama paket dan versi, sehingga pra-rilis memungkinkan Anda menguji alur penginstalan sebenarnya terhadap registry tanpa mengekspos paket yang belum selesai kepada pengguna yang menginstal dengan tag latest default.
Sebelum Anda memublikasikan:
- Pilih nama paket. Nama yang tercakup dan tidak tercakup berfungsi (lihat panduan di atas). Perhatikan bahwa paket yang memiliki cakupan bersifat pribadi secara default, jadi teruskan
--access public. - Bangun dan periksa apa yang dikirim.
maindantypesmengarah ke output yang dikompilasi (lib/dalam contoh yang kami kerjakan), sehingga direktori tersebut harus disertakan dalam file tar yang dipublikasikan. Gunakan.npmignoreatau daftar yang diizinkanfiles, dan periksa hasilnya dengannpm pack --dry-run. SkripprepublishOnlyyang menjalankan build Anda mencegah publikasi output yang tidak berlaku.
Penambahan package.json yang membuat publikasi aman secara default:
{
"files": ["lib", "README.md", "CHANGELOG.md"],
"publishConfig": { "access": "public", "tag": "next" },
"scripts": {
"build": "tsc -b",
"prepublishOnly": "npm run build && npm test"
}
}
Kolom "publishConfig": { "tag": "next" } memastikan bahwa npm
publish biasa tidak pernah menggantikan latest.
Membuat kandidat rilis:
Misalnya, untuk menaikkan versi secara lokal dari 0.0.2-rc.3 ke 0.0.2-rc.4
(ini melakukan commit dan memberi tag di Git jika package.json berada di root repositori):
npm version prerelease --preid rc
Untuk memublikasikan kandidat rilis dan mendaftarkan @your-org/your-kit@0.0.2-rc.4 di
npm dengan tag next:
npm publish
Situs npm mungkin memerlukan waktu beberapa menit untuk menampilkan versi baru; npm view membaca
registry secara langsung:
npm view @your-org/your-kit versions dist-tags
Setelah Langkah 11 dan Langkah 12 dalam panduan ini selesai, Anda dapat mempromosikan paket ke versi stabil:
npm version 0.0.2
npm publish --tag latest
npm dist-tag add @your-org/your-kit@0.0.2 next
Catatan tentang npm-shrinkwrap.json: Sebaiknya sertakan file
npm-shrinkwrap.json dalam paket Anda; CLI akan memperingatkan pengguna saat penginstalan jika Anda tidak melakukannya. Hal ini memastikan pengguna menggunakan dependensi persis yang Anda uji dan membantu melindungi dari serangan supply chain. Namun, shrinkwrap diterapkan
kata demi kata dalam project pengguna Anda, termasuk selama build Cloud Functions
(npm ci), tempat entri khusus developer dapat gagal dengan EBADPLATFORM. Anda mungkin perlu menghapus entri "dev": true dan devDependencies dari salinan shrinkwrap yang dipublikasikan.
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
package.json kit pada saat kandidat rilis keempat:
{
"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" }
}
Perhatikan bahwa dalam kasus ini, kit berada di monorepo, jadi penting untuk
menyertakan repository.directory untuk link registry npm agar mengarah ke
folder yang benar. CHANGELOG.md-nya menyimpan catatan untuk rilis yang tertunda.
11. Pengujian sebagai kit fungsi
Setelah memublikasikan kit, sebaiknya uji kit menggunakan npm.
Pastikan Anda menggunakan
firebase-tools
versi >= 15.32.0 dan instal kit:
firebase functions:kits:install --package <your-package-name>@<your-prerelease-version>
Tindakan ini akan mendownload paket Anda dari npm, menyiapkannya di dalam direktori sumber baru untuk kit Anda, dan memandu Anda mengonfigurasi instance pertama yang serupa dengan alur penginstalan ekstensi. Setelah menginstal dan menyiapkan paket secara lokal, jalankan deployment untuk membuat resource di project Google Cloud Anda:
firebase deploy --only functions:<your-kit-instance-id>
Setelah penginstalan, CLI Firebase akan mencetak perintah deployment serupa dengan ID instance persis yang Anda pilih selama penginstalan.
Validasi kembali kit Anda menggunakan petunjuk di
Langkah 9. Uji fungsi generasi ke-2 Anda. Sekarang setelah Anda men-deploy menggunakan kit, fungsi Anda akan diberi awalan dan nama kit-<instance-id>-<method-name>. Hal ini memungkinkan kit memiliki beberapa instance,
men-deploy fungsi yang sama beberapa kali dalam project, masing-masing dengan
nama yang unik.
12. Penggantian pengujian migrasi
Anda dapat menyiapkan instance ekstensi yang berfungsi, lalu menggunakan
panduan migrasi pengguna
(menggunakan firebase ext:migrate --package
atau perintah CLI kit fungsi)
untuk menyelesaikan pengujian kit fungsi sebagai pengganti migrasi.
13. Memberi tahu pengguna dan Google tentang penggantian ekstensi resmi Anda
Setelah penggantian kit fungsi Anda siap dan tersedia sebagai paket npm yang
harus dimigrasikan oleh pengguna, beri tahu pengguna dan Google tentang penggantian
resmi ini. Perbarui file README.md di repositori GitHub yang menghosting
ekstensi Anda dengan informasi berikut:
<!-- 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 memindai README ekstensi yang diketahui untuk menemukan komentar seperti <!--
FIREBASE_EXTENSION_REPLACEMENT: extension="firebase/firestore-bigquery-export"
package="@firebase-function-kits/firestore-bigquery-export" --> dan menggunakan komentar ini untuk mengisi registry resmi penggantian yang disimpan di repositori firebase-tools sebagai replacements.json.
Anda juga dapat memeriksa replacements.json untuk melihat README.md mana yang akan dipindai untuk ekstensi Anda. Daftar resmi penggantian diperbarui setiap minggu.
Contoh penggunaan: Streaming Cloud Firestore ke BigQuery
Ekstensi firestore-bigquery-export
README.md
berisi:
<!-- 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.