คู่มือนี้จะแสดงวิธีการย้ายข้อมูลส่วนขยายจากสภาพแวดล้อม Firebase Extensions ที่เลิกใช้งานแล้วไปยังฟังก์ชันที่ผู้ใช้ติดตั้งและทำให้ใช้งานได้ใน Cloud Functions ของตนเองสำหรับฐานของโค้ด Firebase (รุ่นที่ 2)
นี่คือเส้นทางการย้ายข้อมูลที่แนะนำ Firebase จะดูแลรายการ ส่วนขยายที่มีแพ็กเกจ npm อย่างเป็นทางการที่เทียบเท่า โดยคำแนะนำนี้จะแนะนำขั้นตอนการสร้างส่วนขยายของคุณ
ตลอดทั้งคู่มือนี้ เราจะใช้ส่วนขยาย Stream Cloud Firestore to
BigQuery (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(...)ซึ่งจะแทนที่lifecycleEventsที่คุณประกาศ ในextension.yaml
ย้ายข้อมูลแหล่งที่มา Firebase Extensions ไปยังฟังก์ชันรุ่นที่ 2
(ไม่บังคับ) การย้ายข้อมูลอัตโนมัติด้วย Firebase Agent Skill
คุณสามารถทำให้ขั้นตอนที่ 1 ถึง 8 (การจัดทำรายการทรัพยากร การทริกเกอร์
การอัปเกรด การแปลงพารามิเตอร์และข้อมูลลับ IAM แบบประกาศ ฮุกวงจรชีวิต และ
การสร้าง README ของแพ็กเกจ) เป็นแบบอัตโนมัติได้โดยใช้ทักษะเอเจนต์ AI ของ extension-to-functions-codebase อย่างเป็นทางการ
ติดตั้งทักษะ
หากคุณหรือผู้ช่วยการเขียนโค้ด AI (Gemini ใน Firebase, Cursor, Claude Code, GitHub Copilot) ยังไม่ได้ติดตั้งทักษะ ให้เรียกใช้คำสั่งต่อไปนี้ โดยใช้ CLI ของทักษะ
npx skills add firebase/agent-skills --skill extension-to-functions-codebase
เมื่อติดตั้งทักษะในโปรเจ็กต์แล้ว ผู้ช่วยเขียนโค้ด AI จะทำตามกฎการย้ายข้อมูลและขั้นตอนการเปลี่ยนรูปแบบโดยอัตโนมัติ คุณใช้พรอมต์ต่อไปนี้ได้
"โปรดย้ายข้อมูล Firebase Extension นี้ไปยังแพ็กเกจ Function Kit รุ่นที่ 2 ที่เผยแพร่ได้
โดยทำตามวิธีการในextension-to-functions-codebase
ทักษะ"
1. จัดทำรายการส่วนขยาย
เริ่มต้นด้วยการทำสินค้าคงคลังของส่วนขยาย ซึ่งเป็นรายการทั้งหมด ที่ส่วนขยายประกาศ จัดส่ง และจัดทำเอกสาร เพื่อให้ทุกพฤติกรรมมี ปลายทางที่กำหนดไว้ในฟังก์ชันรุ่นที่ 2 และไม่มีข้อมูลใดสูญหายใน การย้ายข้อมูล
ตรวจสอบแต่ละรายการต่อไปนี้และจดบันทึกสิ่งที่คุณพบ
extension.yamlซึ่งประกาศพารามิเตอร์ ฟังก์ชัน เหตุการณ์ บทบาท IAM, API ที่จำเป็น, Secret และฮุควงจรfunctions/ซึ่งมีโค้ดฟังก์ชัน การขึ้นต่อกัน การกำหนดค่าบิลด์ ทริกเกอร์ และฟังก์ชันคิวงานREADME.md,PREINSTALL.mdและPOSTINSTALL.mdซึ่งมีขั้นตอนการตั้งค่า คำเตือน และหมายเหตุการเรียกเก็บเงินscripts/ซึ่งมีเครื่องมือสำหรับการนำเข้า การแสดงโฆษณาสำรอง IAM การซ่อม หรือการย้ายข้อมูล และเครื่องมืออื่นๆ ที่คุณจัดส่งพร้อมกับส่วนขยาย
จากนั้นสำหรับแต่ละรายการใน
extension.yaml ให้ตัดสินใจว่าจะวางไว้ที่ใดในแพ็กเกจ npm
แปลงการกำหนดค่าผู้ใช้เป็น Cloud Functions params (ขั้นตอนที่ 4)
แปลงข้อมูลลับเป็นCloud Functions ข้อมูลลับ (ขั้นตอนที่ 4)
แปลงบทบาท IAM เป็น
requiresRole(...)การประกาศ (ขั้นตอนที่ 6)แปลง Google API ที่จำเป็นให้เป็น
requiresAPI(...)ประกาศตามความเหมาะสม (ขั้นตอนที่ 6)แปลง Hook การติดตั้งและการอัปเดตเป็นประกาศ
afterFirstDeploy(...)และafterRedeploy(...)(ขั้นตอนที่ 7)แปลงรหัสอินสแตนซ์จาก
EXT_INSTANCE_IDเป็นFIREBASE_KIT_INSTANCE_ID(ขั้นตอนที่ 4)
ตัวอย่างการทำงาน: สตรีม 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) |
| รหัสอินสแตนซ์ | ไม่ได้ใช้ (ไม่มีการอ่าน 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 เป็นทรัพยากร Dependency ประกาศเวอร์ชัน firebase-functions ของคุณเป็นทรัพยากร Dependency แบบเพียร์ด้วย เพื่อให้โปรเจ็กต์ 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"
}
}
ตัวอย่างการทำงาน: สตรีม Cloud Firestore ไปยัง BigQuery
ก่อน functions/package.json ของส่วนขยายเป็นแบบส่วนตัว โดยจะตั้งชื่อ รหัสส่วนขยาย และประกาศ firebase-functions เป็นทรัพยากร Dependency โดยตรง
{
"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 และหลีกเลี่ยงการเขียนตรรกะของฟังก์ชันใหม่ เนื่องจาก SDK รุ่นที่ 2 จะแสดงพารามิเตอร์ 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การเปรียบเทียบเวอร์ชัน
ความแตกต่างที่สำคัญระหว่างฟังก์ชันรุ่นที่ 1 กับรุ่นที่ 2 คือฟังก์ชันรุ่นที่ 2 ต้องอยู่ร่วมกับทรัพยากรทริกเกอร์ เมื่อผู้ใช้ย้ายข้อมูลจากส่วนขยายที่ใช้ฟังก์ชันรุ่นที่ 1 ไปยังชุดเครื่องมือที่ใช้ฟังก์ชันรุ่นที่ 2 ผู้ใช้อาจต้องเปลี่ยนตำแหน่งฟังก์ชันเพื่อให้เป็นไปตามข้อกำหนดนี้
Cloud Functions ที่ผู้ใช้เลือกอาจใช้งานไม่ได้ในระหว่างการย้ายข้อมูลเนื่องจากระบบจะเก็บตำแหน่งที่มีอยู่ไว้ หากฟังก์ชันที่ทริกเกอร์เหตุการณ์ของส่วนขยายอาศัยตำแหน่งฟังก์ชันที่ผู้ใช้ระบุ เราขอแนะนำให้เพิ่มพารามิเตอร์ใหม่ลงในส่วนขยายเพื่อรวบรวมตำแหน่งทริกเกอร์เหตุการณ์และแมปตำแหน่งนี้กับตำแหน่งฟังก์ชันใหม่
ตัวอย่างการทำงาน: สตรีม Cloud Firestore ไปยัง BigQuery
defineString("DATABASE_REGION", {
label: "Firestore Instance Location",
description:
"Where is the Firestore database located? You can check your current database location at https://console.cloud.google.com/firestore/databases. The functions in this kit deploy to the Cloud Run region closest to this location.",
input: select({
"Multi-region (Europe - Belgium and Netherlands)": "eur3",
"Multi-region (United States)": "nam5",
"Multi-region (Iowa, North Virginia, and Oklahoma)": "nam7",
"Iowa (us-central1)": "us-central1",
// More locations...
})
});
// Firestore multi-region locations are not Cloud Run regions; deploying a
// function to one hard-fails, so they map to a region inside the multi-region.
const MULTI_REGION_TO_FUNCTION_REGION: Record<string, string> = {
nam5: "us-central1",
nam7: "us-central1",
eur3: "europe-west1",
};
/**
* Maps a Firestore database location to the Cloud Run region the functions
* should deploy to. The lookup is case-insensitive and ignores surrounding
* whitespace, as the CLI's own region handling is. Regional locations pass
* through lowercased; an unset or blank location returns `undefined`, meaning
* the functions declare no region.
*/
export function firestoreLocationToFunctionRegion(
location: string | undefined
): string | undefined {
const normalized = location?.trim().toLowerCase();
if (!normalized) {
return undefined;
}
return MULTI_REGION_TO_FUNCTION_REGION[normalized] ?? normalized;
}
const functionRegion = firestoreLocationToFunctionRegion(
process.env.DATABASE_REGION
);
export const fsexportbigquery = onDocumentWritten(
{
region: functionRegion,
// Other configuration
},
(event) => handleDocumentWrite(event, getHandlerContext())
);
ในการติดตั้งชุดอุปกรณ์เป็นครั้งแรก ระบบจะแจ้งให้ผู้ใช้ระบุ
DATABASE_REGION และจะติดตั้งฟังก์ชันไปยัง
functionRegionที่เกี่ยวข้องข้างต้นเพื่อแก้ไขปัญหาตำแหน่งสำหรับฟังก์ชันที่ทริกเกอร์เหตุการณ์รุ่นที่ 2
4. แปลงพารามิเตอร์และข้อมูลลับของส่วนขยาย
พารามิเตอร์
พารามิเตอร์แต่ละรายการที่คุณประกาศใน extension.yaml จะกลายเป็น Cloud Functions
param
แปลงการอ่านสภาพแวดล้อมโดยตรง
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> หรือแจ้งให้ผู้ใช้ทราบระหว่างการติดตั้งใช้งาน ใช้ชื่อพารามิเตอร์เดิมเพื่อให้ค่าจากการติดตั้งที่มีอยู่ยังคงอยู่
คุณไม่ควรเปลี่ยนชื่อพารามิเตอร์ที่ประกาศไว้ในโค้ด โดยเด็ดขาด การย้ายข้อมูลส่วนขยายจะรักษามูลค่าพารามิเตอร์ของผู้ใช้ปลายทางที่มีอยู่ โดยอัตโนมัติ แต่จะทำได้ก็ต่อเมื่อชื่อไม่เปลี่ยนแปลงเท่านั้น
ตัวอย่างการทำงาน: สตรีม 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 ที่มีอยู่จะยังคงทำงานต่อไปได้
รหัสอินสแตนซ์
ส่วนขยายจะอ่านรหัสอินสแตนซ์จาก EXT_INSTANCE_ID ซึ่งรันไทม์ของส่วนขยายจะแทรก ชุดฟังก์ชันจะอ่านรหัสอินสแตนซ์จาก
FIREBASE_KIT_INSTANCE_ID ซึ่ง Firebase CLI จะตั้งค่าสำหรับอินสแตนซ์
ของแต่ละชุดเป็นคีย์ของอินสแตนซ์ในแมป instances ใน firebase.json
CLI จะระบุข้อมูลนี้ในระหว่างการค้นหาเวลาที่ทำการติดตั้งใช้งาน ในโปรแกรมจำลอง และในฟังก์ชันที่
ติดตั้งใช้งาน
รหัสอินสแตนซ์ไม่ใช่พารามิเตอร์ จึงไม่ต้องประกาศด้วย defineString ในความเป็นจริงแล้ว
FIREBASE_... เป็นคำนำหน้าที่สงวนไว้ในไฟล์ .env ดังนั้นผู้ใช้จึงไม่สามารถ
ตั้งค่าหรือลบล้างได้ ค่าที่ CLI แทรกจะไม่ปรากฏในระบบ
พารามิเตอร์ อ่านได้โดยตรงจากสภาพแวดล้อม
// Before
const instanceId = process.env.EXT_INSTANCE_ID;
// After
const instanceId = process.env.FIREBASE_KIT_INSTANCE_ID;
ระบบจะตั้งค่าตัวแปรเมื่อมีการติดตั้งใช้งานแพ็กเกจเป็นชุดเท่านั้น หากมีการนำโค้ดไปใช้เป็นฐานของโค้ดแบบสแตนด์อโลนด้วย (ดูขั้นตอนที่ 9) ให้ถือว่าโค้ดเป็นโค้ดที่ไม่บังคับ หรือล้มเหลวอย่างรวดเร็วพร้อมข้อความที่ชัดเจนเมื่อไม่มีโค้ด หากส่วนขยายของคุณ แสดงรหัสอินสแตนซ์เป็นพารามิเตอร์ที่หันหน้าไปทางผู้ใช้ คุณต้องนำพารามิเตอร์นั้นออก เนื่องจากตอนนี้ CLI ของ Firebase เป็นเจ้าของค่าดังกล่าวแล้ว
ตัวอย่างการทำงาน: ลบข้อมูลผู้ใช้
(ส่วนขยายสตรีม Cloud Firestore ถึง BigQuery ไม่ได้อ่านรหัสอินสแตนซ์ จึงไม่มีอะไรให้ย้ายข้อมูล ส่วนขยายลบข้อมูลผู้ใช้ ใช้เพื่อตั้งชื่อหัวข้อ Pub/Sub)
ก่อน อ่านเป็นตัวแปรสภาพแวดล้อมดิบใน config.ts โดยมีคำนำหน้า 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 ที่ใช้สำหรับ
พารามิเตอร์ทั่วไป 2 รายการเพื่อให้ผู้ใช้ลบล้างชื่อหัวข้อได้
// 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`,
}),
ค่าเริ่มต้นต้องไม่ว่างเปล่าเนื่องจากระบบจะแก้ไขการเชื่อมโยงทริกเกอร์ในเวลาที่ค้นพบ ระบบจะเขียนค่าเริ่มต้นที่ว่างเปล่าลงในไฟล์ Manifest การติดตั้งใช้งานเป็น
ชื่อหัวข้อ นอกจากนี้ ชุดเครื่องมือยังป้องกันการเรียกใช้ภายนอกบริบทของชุดเครื่องมือด้วย
หากไม่มีตัวแปร ค่าเริ่มต้นระดับโมดูลจะประเมินเป็น
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 จึงไม่มี 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 1 รายการและ defineSecret 1 รายการ โดย CLI จะค้นพบทั้ง 2 รายการ
และอ่านจาก .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 ซึ่งแตกต่างจากการรับงานที่มอบหมาย (ครอบคลุมในส่วนฟังก์ชันการอัปเกรดและHook วงจรการเปลี่ยนลูกค้า) ในที่นี้ โค้ดของคุณคือผู้ผลิตที่เรียกใช้
queue.enqueue(...)
Admin SDK เวอร์ชันก่อนหน้ากำหนดให้ส่วนขยายส่งรหัสอินสแตนซ์ส่วนขยายของตนเองเป็นพารามิเตอร์ที่ 2 เพื่อกำหนดเป้าหมายฟังก์ชันคิวของงานในส่วนขยายเดียวกัน
ตั้งแต่เวอร์ชัน firebase-admin 14.2.0 เป็นต้นไป คุณไม่จำเป็นต้องทำตามขั้นตอนนี้และเราไม่แนะนำให้ทำ ตอนนี้ Task Queue API จะกำหนดเป้าหมายคิวของงานในบริบทเดียวกัน (เช่น ส่วนขยายหรือชุดเครื่องมือ) โดยค่าเริ่มต้น เราขอแนะนำให้คุณนำพารามิเตอร์นี้ออกจากโค้ดทั้งในรูปแบบส่วนขยายและฟังก์ชันแบบสแตนด์อโลน
การนำพารามิเตอร์นี้ออกจะช่วยให้มั่นใจได้ถึงความสามารถในการพกพาและความเข้ากันได้แบบย้อนหลัง
ส่วนอื่นๆ ทั้งหมดเกี่ยวกับการเรียกใช้ enqueue ไม่ว่าจะเป็น
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);
หากการเรียกใช้ enqueue มีเป้าหมายเป็นฐานของโค้ดที่มีคำนำหน้า ชื่อฟังก์ชันที่ค้นพบ จะมีคำนำหน้าด้วย (เช่น orders-syncBigQuery) ดู ตรวจสอบและติดตั้งอินสแตนซ์ชุดฟังก์ชันทดแทน และทดสอบเป็นชุดฟังก์ชัน
6. ประกาศ API และบทบาท IAM ที่จำเป็น
ย้ายข้อกำหนด IAM และ API ของส่วนขยายออกจาก extension.yaml และไปที่
code:
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 สุดท้ายจะรองรับโมเดลที่แคบกว่า
ตัวอย่างการทำงาน: สตรีม 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");
หากส่วนขยายเผยแพร่เหตุการณ์ Eventarc คุณต้อง
ตั้งค่าบทบาทและ API ที่จำเป็นที่เหมาะสมสำหรับการเผยแพร่เหตุการณ์ด้วย ก่อนหน้านี้ส่วนขยายจะจัดการเรื่องนี้โดยที่คุณไม่ต้องทำการเปลี่ยนแปลงใดๆ ใน extensions.yaml
คุณทำเช่นนี้ได้แบบมีเงื่อนไขในโค้ดเพื่อให้ชุดเครื่องมือ
ขอสิทธิ์เหล่านี้เฉพาะเมื่อใช้ช่อง Eventarc ที่กำหนดเอง
if (!!process.env.EVENTARC_CHANNEL) {
requiresRole("roles/eventarc.publisher");
requiresAPI(
"eventarcpublishing.googleapis.com",
"Publishes the extension's custom events to its Eventarc channel."
);
}
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 }
}
});
ทำให้การดำเนินการวงจรลูกค้าเป็นแบบ Idempotent ผู้ใช้อาจต้องเรียกใช้คำสั่งอีกครั้งด้วยตนเองหากการส่งหรือการดำเนินการล้มเหลว
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME
firebase functions:lifecycle:run afterRedeploy CODEBASE_NAME
ตัวอย่างการทำงาน: สตรีม 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" } });
การจัดสรรเป็นแบบ Idempotent ดังนั้นการเรียกใช้ซ้ำจะทำให้ชุดข้อมูล ตาราง และมุมมองสอดคล้องกัน
ผู้ใช้สามารถเรียกใช้ซ้ำด้วยตนเองได้โดยใช้ firebase functions:lifecycle:run afterFirstDeploy
CODEBASE_NAME
8. การตั้งค่าเอกสารสำหรับผู้ใช้
เขียนREADMEแพ็กเกจที่อธิบายข้อมูลต่อไปนี้เป็นอย่างน้อย
- ค่า
.envที่แพ็กเกจต้องการ - ข้อมูลลับที่แพ็กเกจต้องการและวิธีย้ายข้อมูลค่าลับที่มีอยู่
- บทบาท IAM ที่แพ็กเกจประกาศด้วย
requiresRole(...) - Google API ที่แพ็กเกจเปิดใช้หรือต้องใช้
- Lifecycle Hook ที่แพ็กเกจประกาศและวิธีกรอกอีกครั้ง ด้วยตนเอง
- หมายเหตุเกี่ยวกับการเรียกเก็บเงิน
- มีการเปลี่ยนแปลงอะไรบ้างเมื่อเทียบกับส่วนขยายเดิม
- วิธีที่แพ็กเกจได้รับรหัสอินสแตนซ์ (
FIREBASE_KIT_INSTANCE_IDที่ตั้งค่าโดย CLI) และฟังก์ชันทั้งหมดของอินสแตนซ์ได้รับการติดตั้งใช้งานด้วยคำนำหน้าkit-<instanceId>-
ตัวอย่างการทำงาน: สตรีม Cloud Firestore ไปยัง BigQuery
แพ็กเกจ README จะจัดส่งตาราง "สิ่งที่เปลี่ยนแปลง" ที่ชัดเจน
| ความกังวล | เป็นส่วนขยาย | As @firebase-function-kits/firestore-bigquery-export |
|---|---|---|
| การกำหนดค่า | พารามิเตอร์ส่วนขยาย | Cloud Functions พารามิเตอร์ผ่าน .env |
| IAM | ได้รับจากส่วนขยาย | requiresRole(...) ใช้เมื่อทำให้ใช้งานได้ |
| การจัดสรร | งานวงจรลูกค้าตามส่วนขยาย | afterFirstDeploy / afterRedeploy งาน |
| ชื่อฟังก์ชัน | ext-<instanceId>-fsexportbigquery |
fsexportbigquery (อาจมีคำนำหน้า) |
| รหัสอินสแตนซ์ | EXT_INSTANCE_ID ที่ส่วนขยายแทรก |
FIREBASE_KIT_INSTANCE_ID ซึ่ง CLI ตั้งค่าจาก firebase.json |
9. ทดสอบฟังก์ชันรุ่นที่ 2
ตอนนี้คุณควรมีฟังก์ชันรุ่นที่ 2 ซึ่งเมื่อนำไปใช้งานแล้วจะทำงานเหมือนกับการติดตั้งส่วนขยายใหม่ทุกประการ ขั้นตอนถัดไปคือการยืนยันและแก้ไขปัญหาที่เกิดขึ้นโดยไม่ตั้งใจ
หากต้องการเรียกใช้ setGlobalOptions
เพื่อตั้งค่าส่วนกลาง เช่น ภูมิภาคหรือ CPU เริ่มต้น คุณต้องทำเช่นนั้นเมื่อ
ติดตั้งใช้งานชุดเครื่องมือเป็นฟังก์ชันรุ่นที่ 2 แบบสแตนด์อโลนเท่านั้น เมื่อติดตั้งชุดเครื่องมือเป็นแพ็กเกจ npm ผู้ใช้จะเรียกใช้ setGlobalOptions ในโค้ด Wrapper เพื่อกำหนดค่าพารามิเตอร์เหล่านี้ และจะได้รับคำเตือนหากเกิดเหตุการณ์นี้ 2 ครั้ง
คุณป้องกันการเรียกนี้ได้โดยตรวจสอบ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คอนโซลสำหรับ ส่วนขยาย
ตัวอย่างการทำงาน: สตรีม Cloud Firestore ไปยัง BigQuery
เราจะยืนยันการซิงค์ Cloud Firestore กับ BigQuery แบบครบวงจรดังนี้
- ในCloud Firestoreหน้าของคอนโซล Firebase ให้สร้างคอลเล็กชัน
ที่คุณตั้งค่าเป็น
COLLECTION_PATH(users) หากยังไม่มี - สร้างเอกสารชื่อ
bigquery-mirror-testที่มีช่องที่มีค่าใดก็ได้ ในBigQueryหน้าของคอนโซล Google Cloud ให้ค้นหาตารางบันทึกการเปลี่ยนแปลงดิบ โดยควรมีแถวเดียวที่บันทึกการสร้างเอกสาร ดังนี้
SELECT * FROM `PROJECT_ID.analytics.users_raw_changelog`ค้นหามุมมองล่าสุด ซึ่งควรแสดงผลเหตุการณ์การเปลี่ยนแปลงล่าสุดสำหรับ เอกสารเดียวที่มีอยู่ (
bigquery-mirror-test)SELECT * FROM `PROJECT_ID.analytics.users_raw_latest`ลบเอกสาร
bigquery-mirror-testใน Cloud Firestore โดยจะหายไปจากมุมมองล่าสุด และระบบจะต่อท้ายเหตุการณ์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นอกจากนี้ คุณยังทดสอบโค้ดแบบหน่วยได้โดยใช้ SDK ของfirebase-functions-testตามที่อธิบายไว้ในการทดสอบแบบหน่วยของ Cloud Functions - การจัดสรรไม่ได้ขับเคลื่อนโดยรันไทม์ของส่วนขยายอีกต่อไป หากตารางบันทึกการเปลี่ยนแปลง
หายไปหลังจากที่ติดตั้งใช้งาน ให้เรียกใช้การตั้งค่าอีกครั้งด้วยตนเอง:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAMEงานนี้เป็น ไอดีมโปเตนต์ ดังนั้นการเรียกใช้ซ้ำจะทำให้ชุดข้อมูล ตาราง และมุมมองสอดคล้องกัน - ค่าพารามิเตอร์มาจาก
.envไม่ใช่แบบฟอร์มการติดตั้ง ดังนั้นการเรียกใช้firebase deployซ้ำจึงไม่โต้ตอบเมื่อ.envเสร็จสมบูรณ์
10. เผยแพร่ชุดฟังก์ชันใน npm
เมื่อตรวจสอบ Conversion จากส่วนขยายเป็นฟังก์ชันรุ่นที่ 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
(ซึ่งจะคอมมิตและติดแท็กใน Git หาก package.json อยู่ที่รูทของที่เก็บ) ให้ทำดังนี้
npm version prerelease --preid rc
หากต้องการเผยแพร่รุ่นที่อาจได้รับการเผยแพร่และลงทะเบียน @your-org/your-kit@0.0.2-rc.4 ใน
npm ภายใต้แท็ก next ให้ทำดังนี้
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 จะเตือนผู้ใช้เมื่อติดตั้งหากคุณไม่ได้รวมไฟล์ดังกล่าว ซึ่งจะช่วยให้มั่นใจได้ว่าผู้ใช้จะใช้การอ้างอิงที่แน่นอนที่คุณทดสอบ และช่วยป้องกันการโจมตีซัพพลายเชน อย่างไรก็ตาม จะมีการใช้ shrinkwrap ตามตัวอักษรในโปรเจ็กต์ของผู้ใช้ รวมถึงในระหว่างCloud Functionsบิลด์ (npm ci) ซึ่งรายการที่ใช้ได้เฉพาะในสภาพแวดล้อมการพัฒนาอาจล้มเหลวด้วย EBADPLATFORM คุณอาจต้อง
ลบรายการ "dev": true และ devDependencies ออกจากสำเนา
ที่เผยแพร่แล้ว
ตัวอย่างการทำงาน: สตรีม Cloud Firestore ไปยัง BigQuery
package.json ของชุดเครื่องมือในขณะที่รุ่นที่อาจได้รับการเผยแพร่รุ่นที่ 4 มีดังนี้
{
"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" }
}
โปรดทราบว่าในกรณีนี้ ชุดเครื่องมือจะอยู่ใน Monorepo ดังนั้นจึงควร
ใส่ 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 จะพิมพ์คำสั่งการทำให้ใช้งานได้ที่คล้ายกันพร้อม รหัสอินสแตนซ์ที่แน่นอนที่คุณเลือกในระหว่างการติดตั้ง
ตรวจสอบความถูกต้องของชุดทดสอบอีกครั้งโดยใช้คำสั่งใน
ขั้นตอนที่ 9 ทดสอบฟังก์ชันรุ่นที่ 2 ตอนนี้คุณได้
ติดตั้งใช้งานโดยใช้ชุดเครื่องมือแล้ว ฟังก์ชันของคุณจึงมีคำนำหน้าและชื่อเป็น
kit-<instance-id>-<method-name> ซึ่งช่วยให้ชุดเครื่องมือมีหลายอินสแตนซ์
และทำให้สามารถใช้ฟังก์ชันเดียวกันหลายครั้งในโปรเจ็กต์ โดยแต่ละฟังก์ชันจะมีชื่อที่ไม่ซ้ำกัน
12. ทดสอบการแทนที่การย้ายข้อมูล
คุณสามารถตั้งค่าอินสแตนซ์ส่วนขยายที่ใช้งานได้ แล้วใช้คู่มือการย้ายข้อมูลผู้ใช้
(โดยใช้ firebase ext:migrate --package
หรือคำสั่ง CLI ของชุดฟังก์ชัน)
เพื่อทดสอบชุดฟังก์ชันให้เสร็จสิ้นในฐานะการแทนที่การย้ายข้อมูล
13. แจ้งให้ผู้ใช้และ Google ทราบเกี่ยวกับการแทนที่ส่วนขยายอย่างเป็นทางการ
เมื่อชุดฟังก์ชันทดแทนพร้อมใช้งานและพร้อมให้บริการเป็นแพ็กเกจ npm ที่ผู้ใช้ควรย้ายข้อมูลไปแล้ว โปรดแจ้งให้ทั้งผู้ใช้และ Google ทราบถึงการทดแทนอย่างเป็นทางการนี้ อัปเดตไฟล์ README.md ในที่เก็บ GitHub ที่โฮสต์ส่วนขยายของคุณด้วยข้อมูลต่อไปนี้
<!-- 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 ใดจะได้รับการสแกน
สำหรับส่วนขยายของคุณได้ด้วย รายการการแทนที่อย่างเป็นทางการจะได้รับการอัปเดตทุกสัปดาห์
ตัวอย่างการทำงาน: สตรีม 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.