В этом руководстве показано, как перенести ваши расширения из устаревшей среды Firebase Extensions в функцию, которую ваши пользователи будут устанавливать и развертывать в своей собственной кодовой базе Cloud Functions for 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 . Мы также будем отправлять электронные письма этой группе по мере обновления руководства с дополнительной информацией о сборке, тестировании и распространении ваших функций второго поколения.
Чтобы присоединиться к этой группе, отправьте сообщение на адрес 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 во второе поколение функций.
(Необязательно) Автоматическая миграция с помощью навыка Firebase Agent
Вы можете автоматизировать шаги с 1 по 8 (инвентаризация ресурсов, запуск обновлений, преобразование параметров и секретов, декларативный IAM, хуки жизненного цикла и генерация файла README пакета) с помощью официального навыка AI-агента extension-to-functions-codebase .
Установите навык
Если вы или ваш ИИ-помощник в программировании (Gemini в Firebase , Cursor, Claude Code, GitHub Copilot) еще не установили навык, выполните следующую команду с помощью CLI навыка:
npx skills add firebase/agent-skills --skill extension-to-functions-codebase
После установки навыка в ваш проект, ваш ИИ-помощник по программированию автоматически будет следовать правилам миграции и этапам преобразования. Вы можете использовать следующую подсказку:
«Пожалуйста, перенесите это расширение Firebase в публикуемый пакет Function Kit второго поколения, следуя инструкциям в навыке extension-to-functions-codebase ».
1. Проведите инвентаризацию расширения.
Начните с инвентаризации вашего расширения: составьте полный список всего, что расширение объявляет, включает в себя и документирует, чтобы каждое поведение имело определенное место назначения во второй функции и ничего не было потеряно при миграции.
Проанализируйте каждый из следующих пунктов и отметьте, что вы обнаружили:
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 ).При необходимости преобразуйте необходимые API Google в объявления
requiresAPI(...)( Шаг 6 ).Преобразуйте обработчики установки и обновления в объявления
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 нечего переносить для секретов. Триггер событий уже относится ко второму поколению; только функции очереди задач по-прежнему относятся к первому поколению (это важно в шаге 3 ).
2. Обновите файл package.json.
Обновите файл 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"
}
}
Пример работы: потоковая передача данных из Cloud Firestore в BigQuery
Раньше. Файл functions/package.json расширения является приватным, в нём указывается идентификатор расширения, и 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-го поколения.
Если ваше расширение по-прежнему экспортирует функции первого поколения, преобразуйте каждый триггер в его эквивалент второго поколения. Импортируйте функции из модулей firebase-functions/... и передавайте параметры времени выполнения в параметрах триггера.
См. руководство по обновлению Cloud Functions 2-го поколения . Важно отметить, что вы можете минимизировать усилия по переписыванию, используя деструктуризацию событий 2-го поколения , и избежать переписывания логики вашей функции, поскольку SDK 2-го поколения предоставляет параметры версии 1 в виде полей в объекте события, что позволяет использовать деструктурированные/именованные параметры и сохранять вашу бизнес-логику без изменений.
Раньше. 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)
);
Полный список различий между функциями первого и второго поколений можно найти в сравнении версий 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 указанном выше, что исправит любые проблемы с местоположением для их функций, запускаемых событиями второго поколения.
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 обнаруживает ваши параметры и считывает их значения из .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 ), либо рассматривайте ее как необязательную, либо быстро выдавайте четкое сообщение об ошибке, если она отсутствует. Если ваше расширение предоставляло идентификатор экземпляра в качестве параметра, доступного пользователю, вы должны удалить этот параметр, поскольку теперь значение принадлежит Firebase CLI.
Пример работы: Удаление пользовательских данных
(Расширение Stream Cloud Firestore to BigQuery не считывает свой идентификатор экземпляра, поэтому переносить туда нечего. Расширение Delete User Data использует его для именования своих тем 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 , используемого в качестве двух стандартных параметров, чтобы пользователи могли переопределять имена тем:
// 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 , нет настраиваемого 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 расширениям требовалось передавать свой собственный идентификатор экземпляра расширения в качестве второго параметра для обращения к функции очереди задач в том же расширении. Начиная с firebase-admin 14.2.0, это не требуется и не рекомендуется. API очереди задач теперь по умолчанию обращается к очередям задач в том же контексте (например, в расширении или наборе инструментов). Безопасно и даже рекомендуется удалить этот параметр в вашем коде как для расширений, так и для отдельных функций. Удаление этого параметра обеспечивает переносимость и обратную совместимость.
Все остальное, касающееся вызова функции enqueue — путь к ресурсу locations/<region>/functions/<name> , полезная нагрузка задачи и ваша логика повторных попыток — остается неизменным.
Дополнительные сведения о добавлении функций в очередь с помощью Cloud Tasks см. в разделе «Добавление функций в очередь с помощью Cloud Tasks .
Ранее. Расширение первого поколения:
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 не поддерживает более узкую модель.
Пример работы: потоковая передача данных из 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 ), удалите эти вызовы, поскольку они вызывают ошибку, если вызываются из обычно развернутой функции второго поколения. Состояние жизненного цикла теперь управляется функциями 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
Пример работы: потоковая передача данных из 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, необходимые для работы пакета. - Секреты, необходимые для работы пакета, и как перенести существующие секретные значения.
- Роли IAM, которые объявляются в пакете с помощью
requiresRole(...). - API-интерфейсы Google, которые включает или требует данный пакет.
- Объявленные в пакете механизмы жизненного цикла и способы их ручного повторного запуска.
- Примечания к выставлению счетов.
- Что изменилось по сравнению с первоначальным расширением.
- Как пакет получает свой идентификатор экземпляра (
FIREBASE_KIT_INSTANCE_IDустанавливаемый CLI) и как все функции экземпляра развертываются с префиксомkit-<instanceId>-.
Пример работы: потоковая передача данных из Cloud Firestore в BigQuery
В файле README пакета содержится подробная таблица с описанием изменений:
| Беспокойство | В качестве расширения | Как @firebase-function-kits/firestore-bigquery-export |
|---|---|---|
| Конфигурация | Параметры расширения | Параметры Cloud Functions передаются через .env |
| Я | Предоставлено в рамках продления срока действия. | requiresRole(...) применяется при развертывании |
| Предоставление ресурсов | Задача жизненного цикла, созданная расширениями. | задача afterFirstDeploy / afterRedeploy |
| Названия функций | ext-<instanceId>-fsexportbigquery | fsexportbigquery (с возможностью добавления префикса) |
| Идентификатор экземпляра | EXT_INSTANCE_ID внедряется расширениями. | FIREBASE_KIT_INSTANCE_ID устанавливается CLI из firebase.json |
9. Проверьте работу функций вашего устройства второго поколения.
Теперь у вас должна быть функция второго поколения, которая после развертывания будет вести себя идентично новой установке вашего расширения. Следующий шаг — проверить и исправить любые проблемы, случайно возникшие в процессе.
Чтобы вызвать setGlobalOptions для установки глобальных параметров, таких как регион по умолчанию или процессор, это необходимо делать только при развертывании вашего комплекта как автономной функции второго поколения. Когда ваш комплект установлен как пакет 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 , и разверните преобразованную функцию второго поколения в тестовый проект с соответствующими ресурсами для проверки её поведения. Если у вас уже есть тестовый проект, созданный после тестирования вашего расширения, выполните следующую команду:
firebase deploy --only functions
Заполните появившийся мастер, запрашивающий значения параметров, точно так же, как вы заполняли бы форму установки в консоли Firebase для расширения.
Пример работы: потоковая передача данных из Cloud Firestore в BigQuery
Мы проверяем сквозную синхронизацию Cloud Firestore и BigQuery :
- На странице Cloud Firestore в консоли Firebase создайте коллекцию, указанную в переменной
COLLECTION_PATH(users), если она еще не существует. - Создайте документ с именем
bigquery-mirror-test, содержащий любые поля с любыми значениями. На странице BigQuery в консоли Google Cloud выполните запрос к исходной таблице changelog. Она должна содержать одну строку, регистрирующую создание документа:
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(без префикса при развертывании в качестве типичной функции второго поколения, а не комплекта), а неext-<instanceId>-fsexportbigquery. Найдите это имя на панели мониторинга и в журналах Cloud Functions . - Теперь ваш код работает в Firebase Local Emulator Suite как обычные функции. Вы можете задать значения параметров для использования в эмуляторе с помощью `
.env.local. Вы также можете протестировать свой код с помощью SDKfirebase-functions-testкак описано в разделе «Модульное тестирование Cloud Functions . - Процесс подготовки ресурсов больше не управляется средой выполнения расширений. Если после развертывания отсутствует таблица журнала изменений, повторно запустите задачу настройки вручную:
firebase functions:lifecycle:run afterFirstDeploy CODEBASE_NAME. Задача является идемпотентной, поэтому ее повторный запуск согласует набор данных, таблицу и представления. - Значения параметров берутся из
.env, а не из формы установки, поэтому повторный запуск командыfirebase deployстановится неинтерактивным после завершения обработки файла.env.
10. Опубликуйте свой набор функций на npm.
После того, как вы подтвердите преобразование из расширения в функцию второго поколения, вы можете опубликовать релиз-кандидат в npm для сквозного тестирования, используя одно из следующих руководств:
- Создание и публикация общедоступных пакетов без ограничений по области действия.
- Создание и публикация целевых общедоступных пакетов.
После публикации вашего комплекта в npm его можно установить с помощью firebase functions:kits:install , и он будет указан в качестве официальной замены вашего расширения.
Мы настоятельно рекомендуем сначала выпустить предварительный релиз. Установка комплектов осуществляется по имени пакета и версии, поэтому предварительный релиз позволяет протестировать реальный процесс установки в реестре, не предоставляя пользователям, устанавливающим пакет с тегом latest , доступ к незавершенному пакету.
Перед публикацией:
- Выберите имя пакета. Подходят как пакеты с областью видимости, так и без нее (см. инструкции выше). Обратите внимание, что пакеты с областью видимости по умолчанию являются приватными, поэтому передайте
--access public. - Выполните сборку и
main, на какие файлы ships.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 из опубликованной копии shrinkwrap.
Пример работы: потоковая передача данных из 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 выводит аналогичную команду развертывания с тем же идентификатором экземпляра, который вы выбрали во время установки.
Повторно проверьте свой комплект, используя инструкции из шага 9. Протестируйте функцию второго поколения . Теперь, когда вы развертываете приложения с помощью комплектов, ваши функции имеют префикс и называются 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
Файл README.md расширения firestore-bigquery-export содержит:
<!-- 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.