На этой странице вы найдёте пошаговые инструкции по созданию простого расширения Firebase, которое вы можете установить в своих проектах или поделиться им с другими. Этот простой пример расширения Firebase будет отслеживать сообщения в вашей базе данных в режиме реального времени и преобразовывать их в верхний регистр.
1. Настройте свою среду и инициализируйте проект.
Прежде чем приступить к созданию расширения, вам необходимо настроить среду сборки с необходимыми инструментами.
Установите Node.js 16 или более новую версию. Один из способов установки Node — использовать nvm (или nvm-windows ).
Установите или обновите Firebase CLI до последней версии. Для установки или обновления с помощью
npm
выполните следующую команду:npm install -g firebase-tools
Теперь используйте Firebase CLI для инициализации нового проекта расширения:
Создайте каталог для вашего расширения и
cd
в него:mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
Выполните команду
ext:dev:init
в Firebase CLI:firebase ext:dev:init
При появлении запроса выберите JavaScript в качестве языка функций (но учтите, что вы также можете использовать TypeScript при разработке собственного расширения), а при запросе на установку зависимостей ответьте «да». (Для всех остальных параметров примите значения по умолчанию.) Эта команда создаст скелетную кодовую базу для нового расширения, на основе которой вы сможете начать разработку своего расширения.
Используйте firebase ext:dev:init
для инициализации нового каталога расширений.
2. Попробуйте пример расширения с помощью эмулятора.
Когда Firebase CLI инициализирует новый каталог расширений, он создает простой пример функции и каталог integration-tests
, содержащий файлы, необходимые для запуска расширения с использованием набора эмуляторов Firebase.
Попробуйте запустить пример расширения в эмуляторе:
Перейдите в каталог
integration-tests
:cd functions/integration-tests
Запустите эмулятор с демо-проектом:
firebase emulators:start --project=demo-test
Эмулятор загружает расширение в предопределенный «пустой» проект (
demo-test
). Расширение пока состоит из одной HTTP-функцииgreetTheWorld
, которая возвращает сообщение «hello world» при обращении к ней.При работающем эмуляторе попробуйте функцию расширения
greetTheWorld
, перейдя по URL-адресу, который оно вывело при запуске.В вашем браузере отображается сообщение «Hello World от greet-the-world».
Исходный код этой функции находится в каталоге
functions
расширения. Откройте исходный код в редакторе или IDE по вашему выбору:функции/index.js
const functions = require("firebase-functions/v1"); exports.greetTheWorld = functions.https.onRequest((req, res) => { // Here we reference a user-provided parameter // (its value is provided by the user during installation) const consumerProvidedGreeting = process.env.GREETING; // And here we reference an auto-populated parameter // (its value is provided by Firebase after installation) const instanceId = process.env.EXT_INSTANCE_ID; const greeting = `${consumerProvidedGreeting} World from ${instanceId}`; res.send(greeting); });
Во время работы эмулятора он автоматически перезагрузит все изменения, внесённые вами в код функций. Попробуйте внести небольшое изменение в функцию
greetTheWorld
:функции/index.js
const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
Сохраните изменения. Эмулятор перезагрузит ваш код, и теперь при переходе по URL-адресу функции вы увидите обновлённое приветствие.
Использование эмулятора расширений может ускорить разработку, позволяя вам быстро тестировать и итерировать свой код.
Дополнительная информация
Узнайте больше об использовании эмулятора расширений .
3. Добавьте основную информацию в extension.yaml
Теперь, когда у вас настроена среда разработки и запущен эмулятор расширений, вы можете приступить к написанию собственного расширения.
В качестве скромного первого шага отредактируйте предопределенные метаданные расширения, указав расширение, которое вы хотите написать вместо greet-the-world
. Эти метаданные хранятся в файле extension.yaml
.
Откройте
extension.yaml
в редакторе и замените все содержимое файла следующим:name: rtdb-uppercase-messages version: 0.0.1 specVersion: v1beta # Firebase Extensions specification version; don't change # Friendly display name for your extension (~3-5 words) displayName: Convert messages to upper case # Brief description of the task your extension performs (~1 sentence) description: >- Converts messages in RTDB to upper case author: authorName: Your Name url: https://your-site.example.com license: Apache-2.0 # Required license # Public URL for the source code of your extension sourceUrl: https://github.com/your-name/your-repo
Обратите внимание на соглашение об именовании, используемое в поле
name
: официальные расширения Firebase имеют префикс, указывающий на основной продукт Firebase, с которым работает расширение, а затем описание его функций. Вам следует использовать то же соглашение в своих расширениях.Поскольку вы изменили имя своего расширения, вам также следует обновить конфигурацию эмулятора, указав новое имя:
- В
functions/integration-tests/firebase.json
изменитеgreet-the-world
наrtdb-uppercase-messages
. - Переименуйте
functions/integration-tests/extensions/greet-the-world.env
вfunctions/integration-tests/extensions/rtdb-uppercase-messages.env
.
- В
В коде вашего расширения всё ещё остались некоторые фрагменты расширения greet-the-world
, но пока оставьте их. Вы обновите их в следующих нескольких разделах.
Файл
extension.yaml
содержит метаданные о вашем расширении. Наиболее важная часть этих метаданных — название расширения и описание его функций.Называйте расширения в следующем формате:
<firebase-product>-<description-of-tasks-performed>
.
Дополнительная информация
Полную спецификацию файла можно найти в справочнике extension.yaml
; однако в данной документации будут рассмотрены конкретные варианты использования этого файла по мере необходимости.
4. Напишите облачную функцию и объявите ее как ресурс расширения.
Теперь вы можете приступить к написанию кода. На этом этапе вы напишете облачную функцию, которая выполняет основную задачу вашего расширения: отслеживает сообщения в базе данных в реальном времени и преобразует их в верхний регистр.
Откройте исходный код функций расширения (в каталоге
functions
расширения) в редакторе или IDE по вашему выбору. Замените его содержимое следующим:функции/index.js
import { database, logger } from "firebase-functions/v1"; const app = initializeApp(); // Listens for new messages added to /messages/{pushId}/original and creates an // uppercase version of the message to /messages/{pushId}/uppercase // for all databases in 'us-central1' export const makeuppercase = database .ref("/messages/{pushId}/uppercase") .onCreate(async (snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); // Convert it to upper case. logger.log("Uppercasing", context.params.pushId, original); const uppercase = original.toUpperCase(); // Setting an "uppercase" sibling in the Realtime Database. const upperRef = snapshot.ref.parent.child("upper"); await upperRef.set(uppercase); });
Старая функция, которую вы заменили, была функцией, активируемой HTTP-запросом, которая выполнялась при доступе к конечной точке HTTP. Новая функция активируется событиями базы данных в режиме реального времени: она отслеживает новые элементы по определённому пути и при их обнаружении записывает значение в верхнем регистре обратно в базу данных.
Кстати, этот новый файл использует синтаксис модулей ECMAScript (
import
иexport
) вместо CommonJS (require
). Чтобы использовать модули ES в Node, укажите"type": "module"
вfunctions/package.json
:{ "name": "rtdb-uppercase-messages", "main": "index.js", "type": "module", … }
Каждая функция в вашем расширении должна быть объявлена в файле
extension.yaml
. В примере расширенияgreetTheWorld
объявлена как единственная облачная функция расширения; теперь, когда вы заменили её наmakeuppercase
, вам также необходимо обновить её объявление.Откройте
extension.yaml
и добавьте полеresources
:resources: - name: makeuppercase type: firebaseextensions.v1beta.function properties: eventTrigger: eventType: providers/google.firebase.database/eventTypes/ref.create # DATABASE_INSTANCE (project's default instance) is an auto-populated # parameter value. You can also specify an instance. resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original runtime: "nodejs18"
Поскольку ваше расширение теперь использует Realtime Database в качестве триггера, вам необходимо обновить конфигурацию эмулятора, чтобы запустить эмулятор RTDB вместе с эмулятором Cloud Functions:
Если эмулятор все еще работает, остановите его, нажав Ctrl-C.
Из каталога
functions/integration-tests
выполните следующую команду:firebase init emulators
При появлении запроса пропустите настройку проекта по умолчанию, затем выберите эмуляторы функций и баз данных. Примите порты по умолчанию и разрешите инструменту настройки загрузить все необходимые файлы.
Перезапустите эмулятор:
firebase emulators:start --project=demo-test
Попробуйте обновленное расширение:
Откройте пользовательский интерфейс эмулятора базы данных, используя ссылку, которую эмулятор распечатал при запуске.
Отредактируйте корневой узел базы данных:
- Поле:
messages
- Тип:
json
- Значение:
{"11": {"original": "recipe"}}
Если всё настроено правильно, то при сохранении изменений в базе данных функция
makeuppercase
расширения должна сработать и добавить дочернюю запись в сообщение 11 с содержимым"upper": "RECIPE"
. Проверьте журналы и вкладки базы данных в интерфейсе эмулятора, чтобы убедиться в ожидаемых результатах.- Поле:
Попробуйте добавить ещё несколько дочерних элементов к узлу
messages
({"original":"any text"}
). При добавлении новой записи расширение должно добавлять полеuppercase
, содержащее содержимоеoriginal
поля, записанное заглавными буквами.
Теперь у вас есть готовое, хотя и простое, расширение, работающее на экземпляре RTDB. В следующих разделах вы доработаете это расширение, добавив несколько дополнительных функций. Затем вы подготовите расширение к распространению и, наконец, узнаете, как опубликовать его в Extensions Hub.
- Функции, составляющие логику вашего расширения, должны быть определены как код Cloud Functions и объявлены как ресурс расширения в файле
extension.yaml
. - Вы можете написать функции, которые срабатывают при доступе к конечным точкам HTTP или в ответ на события, создаваемые продуктами Firebase, продуктами Google Cloud и другими расширениями.
Дополнительная информация
- Узнайте больше о написании облачных функций для расширений , включая информацию о поддерживаемых триггерах событий.
- Полную спецификацию файла можно найти в справочнике
extension.yaml
; однако в данной документации будут рассмотрены конкретные варианты использования этого файла по мере необходимости. - Документация Cloud Functions for Firebase содержит общую информацию об использовании Cloud Functions, не относящуюся только к расширениям Firebase.
5. Объявите API и роли
Firebase предоставляет каждому экземпляру установленного расширения ограниченный доступ к проекту и его данным, используя учётную запись службы для каждого экземпляра. Каждая учётная запись имеет минимальный набор разрешений, необходимых для работы. Поэтому необходимо явно указать все IAM-роли, требуемые вашим расширением; когда пользователи устанавливают ваше расширение, Firebase создаёт учётную запись службы с этими ролями и использует её для запуска расширения.
Вам не нужно объявлять роли для запуска событий продукта, но вам необходимо объявить роль для взаимодействия с ним. Поскольку функция, добавленная на последнем шаге, записывает данные в базу данных реального времени, вам необходимо добавить следующее объявление в extension.yaml
:
roles:
- role: firebasedatabase.admin
reason: Allows the extension to write to RTDB.
Аналогичным образом, вы указываете API Google, используемые расширением, в поле apis
. При установке расширения пользователям будет предложено автоматически включить эти API для своего проекта. Обычно это необходимо только для API Google, отличных от Firebase, и не требуется в рамках данного руководства.
- Укажите все необходимые IAM-роли для вашего расширения в поле
roles
файлаextensions.yaml
. После установки расширениям эти роли предоставляются автоматически. - Укажите все необходимые вашему расширению API Google в поле
apis
файлаextensions.yaml
. При установке расширения пользователи могут автоматически включить эти API для своего проекта. - В целях документирования укажите все API, не принадлежащие Google, которые требуются вашему расширению, в поле
externalServices
файлаextensions.yaml
.
Дополнительная информация
- Узнайте больше о настройке соответствующего доступа для расширения .
- Полную спецификацию файла можно найти в справочнике
extension.yaml
; однако в данной документации будут рассмотрены конкретные варианты использования этого файла по мере необходимости.
6. Определите настраиваемые пользователем параметры
Функция, созданная вами на последних двух этапах, отслеживала входящие сообщения в определённом месте RTDB. Иногда отслеживание определённого места действительно необходимо, например, когда ваше расширение работает со структурой базы данных, используемой исключительно для него. Однако в большинстве случаев вам потребуется предоставить пользователям, устанавливающим ваше расширение в свои проекты, возможность настраивать эти значения. Таким образом, пользователи смогут использовать ваше расширение для работы с существующей базой данных.
Сделайте так, чтобы путь, по которому расширение отслеживает новые сообщения, настраивался пользователем:
В файле
extension.yaml
добавьте разделparams
:- param: MESSAGE_PATH label: Message path description: >- What is the path at which the original text of a message can be found? type: string default: /messages/{pushId}/original required: true immutable: false
Это определяет новый строковый параметр, который пользователям будет предложено задать при установке вашего расширения.
Оставаясь в файле
extension.yaml
, вернитесь к объявлениюmakeuppercase
и измените полеresource
на следующее:resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
Токен
${param:MESSAGE_PATH}
— это ссылка на только что определённый вами параметр. При запуске расширения этот токен будет заменён значением, заданным пользователем для этого параметра, в результате чего функцияmakeuppercase
будет прослушивать указанный пользователем путь. Вы можете использовать этот синтаксис для ссылки на любой пользовательский параметр в любом месте файлаextension.yaml
(и вPOSTINSTALL.md
— подробнее об этом позже).Вы также можете получить доступ к определяемым пользователем параметрам из кода ваших функций.
В функции, написанной в предыдущем разделе, вы жёстко задали путь для отслеживания изменений. Измените определение триггера так, чтобы оно ссылалось на пользовательское значение:
функции/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
Обратите внимание, что в расширениях Firebase это изменение сделано исключительно для документирования: когда облачная функция развёртывается как часть расширения, она использует определение триггера из файла
extension.yaml
и игнорирует значение, указанное в определении функции. Тем не менее, рекомендуется документировать в коде источник этого значения.Возможно, вас разочарует внесение изменений в код, не влияющих на время выполнения, но важный урок, который следует извлечь, заключается в том, что вы можете получить доступ к любому пользовательскому параметру в коде функции и использовать его как обычное значение в логике функции. В качестве подтверждения этой возможности добавьте следующий оператор журнала, чтобы продемонстрировать, что вы действительно получаете доступ к значению, заданному пользователем:
функции/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate( async (snapshot, context) => { logger.log("Found new message at ", snapshot.ref); // Grab the current value of what was written to the Realtime Database. ...
Обычно пользователям предлагается указать значения параметров при установке расширения. Однако при использовании эмулятора для тестирования и разработки процесс установки пропускается, поэтому вместо этого значения пользовательских параметров указываются в файле
env
.Откройте
functions/integration-tests/extensions/rtdb-uppercase-messages.env
и замените определениеGREETING
следующим:MESSAGE_PATH=/msgs/{pushId}/original
Обратите внимание, что указанный выше путь отличается от пути по умолчанию и от пути, который вы определили ранее. Это сделано только для того, чтобы убедиться, что при попытке запустить обновленное расширение ваше определение вступило в силу.
Теперь перезапустите эмулятор и еще раз посетите пользовательский интерфейс эмулятора базы данных.
Отредактируйте корневой узел базы данных, используя путь, который вы определили выше:
- Поле:
msgs
- Тип:
json
- Значение:
{"11": {"original": "recipe"}}
При сохранении изменений в базе данных функция расширения
makeuppercase
должна срабатывать, как и раньше, но теперь она также должна выводить определенный пользователем параметр в журнал консоли.- Поле:
- Вы можете предоставить пользователям возможность настраивать ваше расширение под свои нужды, объявив пользовательские параметры в файле
extension.yaml
. Пользователям будет предложено указать эти значения при установке расширения. - Вы можете ссылаться на значения пользовательских параметров в файле
extension.yaml
и в файлеPOSTINSTALL.md
, используя следующий синтаксис:${param:PARAMETER_NAME}
- Вы можете получить доступ к значениям пользовательских параметров в коде Cloud Functions как к переменным среды:
process.env.PARAMETER_NAME
- При тестировании с использованием эмулятора определите пользовательские параметры в файле
<extension-name>.env
.
Дополнительная информация
Узнайте больше о настройке и использовании параметров в вашем расширении .
7. Предоставьте перехватчики событий для пользовательской логики.
Как автор расширения, вы уже видели, как продукт Firebase может активировать логику, предоставляемую вашим расширением: создание новых записей в базе данных Realtime Database активирует вашу функцию makeuppercase
. Аналогичные отношения могут быть у вашего расширения и с пользователями, устанавливающими его: ваше расширение может активировать логику, определяемую пользователем .
Расширение может предоставлять синхронные хуки , асинхронные хуки или и то, и другое. Синхронные хуки позволяют пользователям выполнять задачи, блокирующие завершение одной из функций расширения. Это может быть полезно, например, для предоставления пользователям возможности выполнить пользовательскую предварительную обработку перед тем, как расширение выполнит свою работу.
В этом руководстве вы добавите асинхронный хук к своему расширению, который позволит пользователям определять собственные этапы обработки, которые будут выполняться после того, как ваше расширение запишет сообщение в верхнем регистре в базу данных Realtime Database. Асинхронные хуки используют Eventarc для запуска пользовательских функций. Расширения объявляют типы создаваемых ими событий, и при установке расширения пользователи выбирают, какие типы событий им интересны. Если они выберут хотя бы одно событие, Firebase подготовит канал Eventarc для расширения в процессе установки. Затем пользователи смогут развернуть собственные облачные функции, которые прослушивают этот канал и срабатывают при публикации новых событий расширением.
Чтобы добавить асинхронный хук, выполните следующие действия:
В файле
extension.yaml
добавьте следующий раздел, в котором объявляется один тип событий, испускаемых расширением:events: - type: test-publisher.rtdb-uppercase-messages.v1.complete description: >- Occurs when message uppercasing completes. The event subject will contain the RTDB URL of the uppercase message.
Типы событий должны быть универсально уникальными. Чтобы обеспечить уникальность, всегда называйте события в следующем формате:
<publisher-id>.<extension-id>.<version>.<description>
. (У вас пока нет идентификатора издателя, поэтому пока просто используйтеtest-publisher
.)В конце функции
makeuppercase
добавьте код, который публикует событие типа, который вы только что объявили:функции/index.js
// Import the Eventarc library: import { initializeApp } from "firebase-admin/app"; import { getEventarc } from "firebase-admin/eventarc"; const app = initializeApp(); // In makeuppercase, after upperRef.set(uppercase), add: // Set eventChannel to a newly-initialized channel, or `undefined` if events // aren't enabled. const eventChannel = process.env.EVENTARC_CHANNEL && getEventarc().channel(process.env.EVENTARC_CHANNEL, { allowedEventTypes: process.env.EXT_SELECTED_EVENTS, }); // If events are enabled, publish a `complete` event to the configured // channel. eventChannel && eventChannel.publish({ type: "test-publisher.rtdb-uppercase-messages.v1.complete", subject: upperRef.toString(), data: { "original": original, "uppercase": uppercase, }, });
В этом примере кода используется тот факт, что переменная среды
EVENTARC_CHANNEL
определяется только тогда, когда пользователь включил хотя бы один тип событий. ЕслиEVENTARC_CHANNEL
не определен, код не пытается публиковать какие-либо события.Вы можете прикрепить дополнительную информацию к событию Eventarc. В примере выше событие содержит поле
subject
, содержащее ссылку на созданное значение, иdata
нагрузку, содержащую исходное сообщение и сообщение в верхнем регистре. Пользовательские функции, запускающие событие, могут использовать эту информацию.Обычно переменные окружения
EVENTARC_CHANNEL
иEXT_SELECTED_EVENTS
определяются на основе параметров, выбранных пользователем при установке. Для тестирования с помощью эмулятора вручную определите эти переменные в файлеrtdb-uppercase-messages.env
:EVENTARC_CHANNEL=locations/us-central1/channels/firebase EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
На этом этапе вы выполнили все необходимые шаги для добавления асинхронного обработчика событий в свое расширение.
Чтобы опробовать новую функцию, которую вы только что реализовали, в следующих нескольких шагах возьмите на себя роль пользователя, устанавливающего расширение:
В каталоге
functions/integration-tests
инициализируйте новый проект Firebase:firebase init functions
При появлении запроса откажитесь от настройки проекта по умолчанию, выберите JavaScript в качестве языка облачных функций и установите необходимые зависимости. Этот проект представляет собой проект пользователя , в котором установлено ваше расширение.
Отредактируйте
integration-tests/functions/index.js
и вставьте следующий код:import { logger } from "firebase-functions/v1"; import { onCustomEventPublished } from "firebase-functions/v2/eventarc"; import { initializeApp } from "firebase-admin/app"; import { getDatabase } from "firebase-admin/database"; const app = initializeApp(); export const extraemphasis = onCustomEventPublished( "test-publisher.rtdb-uppercase-messages.v1.complete", async (event) => { logger.info("Received makeuppercase completed event", event); const refUrl = event.subject; const ref = getDatabase().refFromURL(refUrl); const upper = (await ref.get()).val(); return ref.set(`${upper}!!!`); } );
Это пример функции постобработки, которую может написать пользователь. В этом случае функция ожидает, что расширение опубликует
complete
событие, и при срабатывании добавляет три восклицательных знака к новому сообщению, преобразованному в верхний регистр.Перезапустите эмулятор. Эмулятор загрузит функции расширения, а также функцию постобработки, заданную пользователем.
Откройте пользовательский интерфейс эмулятора базы данных и отредактируйте корневой узел базы данных, используя путь, который вы определили выше:
- Поле:
msgs
- Тип:
json
- Значение:
{"11": {"original": "recipe"}}
При сохранении изменений в базе данных функция расширения
makeuppercase
и функцияextraemphasis
пользователя должны сработать последовательно, в результате чегоupper
поле получит значениеRECIPE!!!
.- Поле:
- Ваши расширения могут включать в себя хуки, которые позволяют пользователям вставлять собственную логику в базовую работу вашего расширения.
- Пользовательские хуки могут быть синхронными, блокируя выполнение расширения до его завершения. Расширения часто используют синхронные хуки для выполнения заданных пользователем задач предварительной обработки.
- Пользовательские хуки также могут быть асинхронными, как в примере выше. Асинхронные хуки могут использоваться для выполнения пользовательской логики, которая не является критичной для корректной работы расширения.
Дополнительная информация
Узнайте больше о добавлении хуков для пользовательской логики , включая как асинхронные, так и синхронные хуки.
8. Добавьте обработчики событий жизненного цикла
Расширение, которое вы написали, обрабатывает сообщения по мере их создания. Но что делать, если у ваших пользователей уже есть база данных сообщений на момент установки расширения? В Firebase Extensions есть функция, называемая перехватчиками событий жизненного цикла , которую можно использовать для запуска действий при установке, обновлении или перенастройке расширения. В этом разделе вы будете использовать перехватчики событий жизненного цикла для заполнения существующей базы данных сообщений проекта сообщениями в верхнем регистре при установке расширения пользователем.
Firebase Extensions использует Cloud Tasks для запуска обработчиков событий жизненного цикла. Обработчики событий определяются с помощью Cloud Functions; всякий раз, когда экземпляр вашего расширения достигает одного из поддерживаемых событий жизненного цикла, если вы определили обработчик, он добавляется в очередь Cloud Tasks. Cloud Tasks затем асинхронно выполняет обработчик. Во время работы обработчика событий жизненного цикла консоль Firebase сообщает пользователю о том, что экземпляр расширения выполняет задачу обработки. Функция-обработчик должна сообщать пользователю о текущем состоянии и завершении задачи.
Чтобы добавить обработчик событий жизненного цикла, который заполняет существующие сообщения, выполните следующие действия:
Определите новую облачную функцию, которая запускается событиями очереди задач:
функции/index.js
import { tasks } from "firebase-functions/v1"; import { getDatabase } from "firebase-admin/database"; import { getExtensions } from "firebase-admin/extensions"; import { getFunctions } from "firebase-admin/functions"; export const backfilldata = tasks.taskQueue().onDispatch(async () => { const batch = await getDatabase() .ref(process.env.MESSAGE_PATH) .parent.parent.orderByChild("upper") .limitToFirst(20) .get(); const promises = []; for (const key in batch.val()) { const msg = batch.child(key); if (msg.hasChild("original") && !msg.hasChild("upper")) { const upper = msg.child("original").val().toUpperCase(); promises.push(msg.child("upper").ref.set(upper)); } } await Promise.all(promises); if (promises.length > 0) { const queue = getFunctions().taskQueue( "backfilldata", process.env.EXT_INSTANCE_ID ); return queue.enqueue({}); } else { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill complete."); } });
Обратите внимание, что функция обрабатывает лишь несколько записей, прежде чем вернуться в очередь задач. Это распространённая стратегия для обработки задач, которые не могут быть завершены в течение тайм-аута облачной функции. Поскольку невозможно предсказать, сколько сообщений уже будет в базе данных пользователя на момент установки расширения, эта стратегия подходит как нельзя лучше.
В файле
extension.yaml
объявите функцию обратного заполнения как ресурс расширения, имеющий свойствоtaskQueueTrigger
:resources: - name: makeuppercase ... - name: backfilldata type: firebaseextensions.v1beta.function description: >- Backfill existing messages with uppercase versions properties: runtime: "nodejs18" taskQueueTrigger: {}
Затем объявите функцию как обработчик события жизненного цикла
onInstall
:lifecycleEvents: onInstall: function: backfilldata processingMessage: Uppercasing existing messages
Хотя функция обратного заполнения существующих сообщений полезна, расширение может работать и без неё. В подобных ситуациях запуск обработчиков событий жизненного цикла следует сделать необязательным.
Для этого добавьте новый параметр в
extension.yaml
:- param: DO_BACKFILL label: Backfill existing messages description: >- Generate uppercase versions of existing messages? type: select required: true options: - label: Yes value: true - label: No value: false
Затем в начале функции обратного заполнения проверьте значение параметра
DO_BACKFILL
и выйдите досрочно, если он не установлен:функции/index.js
if (!process.env.DO_BACKFILL) { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped."); }
Благодаря вышеуказанным изменениям расширение теперь после установки будет преобразовывать существующие сообщения в верхний регистр.
До этого момента вы использовали эмулятор расширений для разработки расширения и тестирования текущих изменений. Однако эмулятор расширений пропускает процесс установки, поэтому для тестирования обработчика событий onInstall
вам потребуется установить расширение в реальном проекте. Это, конечно, хорошо, поскольку благодаря функции автоматического заполнения код расширения для руководства теперь полностью готов!
События жизненного цикла инициируются, когда пользователи выполняют определенные задачи по управлению расширениями:
- Установка экземпляра расширения
- Обновление экземпляра расширения до новой версии
- Перенастройка экземпляра расширения
Вы можете определить функции, которые будут запускаться при событиях жизненного цикла вашего расширения.
Используйте API среды выполнения расширения Admin SDK, чтобы сообщать пользователю о состоянии обработчика событий жизненного цикла. Текущий статус обработки расширения будет отображаться в консоли Firebase.
Функции, работающие со всей базой данных (например, операции обратного заполнения), часто не успевают завершиться до истечения времени ожидания облачной функции. Эту проблему можно избежать, разделив задачу на несколько вызовов функций.
Если ваше расширение включает обработчики событий жизненного цикла, которые не являются критически важными для функционирования расширения, вам следует сделать выполнение обработчика настраиваемым пользователем.
Дополнительная информация
Узнайте больше об обработке событий жизненного цикла вашего расширения .
9. Развертывание в реальном проекте Firebase
Хотя эмулятор расширений является отличным инструментом для быстрой итерации расширения в процессе разработки, в какой-то момент вам захочется опробовать его в реальном проекте.
Для этого сначала создайте новый проект с некоторыми включенными службами:
- В консоли Firebase добавьте новый проект.
- Переведите свой проект на тарифный план Blaze с оплатой по факту использования. Для использования Cloud Functions for Firebase в вашем проекте должен быть платёжный аккаунт, поэтому для установки расширения вам также потребуется платёжный аккаунт.
- В новом проекте включите Real-time Database .
- Поскольку вы хотите проверить способность вашего расширения заполнять существующие данные при установке, импортируйте несколько образцов данных в ваш экземпляр базы данных в реальном времени:
- Загрузите некоторые исходные данные RTDB .
- На странице «База данных реального времени» консоли Firebase нажмите (ещё) > Импорт JSON и выберите файл, который вы только что загрузили.
Чтобы функция обратного заполнения могла использовать метод
orderByChild
, настройте базу данных на индексацию сообщений по значениюupper
:{ "rules": { ".read": false, ".write": false, "messages": { ".indexOn": "upper" } } }
Теперь установите расширение из локального источника в новый проект:
Создайте новый каталог для вашего проекта Firebase:
mkdir ~/extensions-live-test && cd ~/extensions-live-test
Инициализируйте проект Firebase в рабочем каталоге:
firebase init database
При появлении запроса выберите проект, который вы только что создали.
Установите расширение в локальный проект Firebase:
firebase ext:install /path/to/rtdb-uppercase-messages
Здесь вы можете увидеть, как выглядит пользовательский интерфейс при установке расширения с помощью инструмента Firebase CLI. Обязательно выберите «Да», когда инструмент настройки спросит, хотите ли вы выполнить резервное копирование существующей базы данных.
После выбора параметров конфигурации Firebase CLI сохранит вашу конфигурацию в каталоге
extensions
и запишет местоположение исходного файла расширения в файлfirebase.json
. Вместе эти две записи называются манифестом расширений . Пользователи могут использовать манифест для сохранения конфигурации своих расширений и её развертывания в различных проектах.Разверните конфигурацию расширения в вашем рабочем проекте:
firebase deploy --only extensions
Если всё пройдёт успешно, Firebase CLI загрузит ваше расширение в ваш проект и установит его. После завершения установки запустится задача обратного заполнения, и через несколько минут ваша база данных будет обновлена сообщениями в верхнем регистре. Добавьте несколько новых узлов в базу данных сообщений и убедитесь, что расширение также работает с новыми сообщениями.
- Пользователи могут создать манифест расширения с помощью команды
firebase ext:install
. Эту команду также можно использовать для установки расширения из локального источника. - Разверните конфигурацию расширения из манифеста в работающий проект с помощью
firebase deploy
. - Хотя здесь это не показано, пользователи также могут устанавливать расширения в свои проекты из Extensions Hub.
Дополнительная информация
См. пользовательскую документацию по управлению конфигурациями проекта с помощью манифеста расширений .
10. Напишите документацию
Прежде чем поделиться своим расширением с пользователями, убедитесь, что вы предоставляете им достаточно документации для успешной работы.
При инициализации проекта расширения Firebase CLI создал заглушки минимально необходимой документации. Обновите эти файлы, чтобы они точно соответствовали созданному вами расширению.
расширение.yaml
Вы уже обновили этот файл, поскольку разработали это расширение, поэтому вам не нужно вносить какие-либо дополнительные обновления прямо сейчас.
Однако не стоит недооценивать важность документации, содержащейся в этом файле. Помимо важнейшей идентификационной информации расширения — имени, описания, автора и расположения официального репозитория — файл extension.yaml
содержит пользовательскую документацию по каждому ресурсу и настраиваемым пользователем параметрам. Эта информация отображается пользователям в консоли Firebase, Extensions Hub и Firebase CLI.
PREINSTALL.md
В этом файле предоставьте пользователю информацию, необходимую для установки расширения: кратко опишите, что делает расширение, объясните все предварительные условия и предоставьте пользователю информацию о том, как будет взиматься плата за установку расширения. Если у вас есть веб-сайт с дополнительной информацией, здесь также можно разместить ссылку на него.
Текст этого файла отображается пользователю в Extensions Hub и с помощью команды firebase ext:info
.
Вот пример файла PREINSTALL:
Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.
This extension expects a database layout like the following example:
"messages": {
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
}
When you create new string records, this extension creates a new sibling record
with upper-cased text:
MESSAGE_ID: {
"original": MESSAGE_TEXT,
"upper": UPPERCASE_MESSAGE_TEXT,
}
#### Additional setup
Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.
#### Billing
To install an extension, your project must be on the
[Blaze (pay as you go) plan](https://firebase.google.com/pricing).
- This extension uses other Firebase and Google Cloud Platform services, which
have associated charges if you exceed the service's no-cost tier:
- Realtime Database
- Cloud Functions (Node.js 10+ runtime)
[See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
[Eventarc fees apply](https://cloud.google.com/eventarc/pricing).
POSTINSTALL.md
Этот файл содержит полезную информацию для пользователей после успешной установки вашего расширения: например, последующие шаги по настройке, пример расширения в действии и т. д.
Содержимое файла POSTINSTALL.md отображается в консоли Firebase после настройки и установки расширения. Вы можете ссылаться на пользовательские параметры в этом файле, и они будут заменены настроенными значениями.
Вот пример файла после установки для расширения руководства:
### See it in action
You can test out this extension right away!
1. Go to your
[Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.
1. Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.
1. In a few seconds, you'll see a sibling node named `upper` that contains the
message in upper case.
### Using the extension
We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).
### Monitoring
As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.
CHANGELOG.md
Вам также следует документировать изменения, вносимые между выпусками расширения, в файле CHANGELOG.md
.
Поскольку пример расширения ранее не публиковался, в журнале изменений есть только одна запись:
## Version 0.0.1
Initial release of the _Convert messages to upper case_ extension.
README.md
Большинство расширений также предоставляют файл readme для удобства пользователей, посещающих репозиторий расширения. Вы можете написать этот файл вручную или сгенерировать файл readme с помощью команды.
Для целей данного руководства пропустите написание файла readme.
Дополнительная документация
Приведённая выше документация — это минимальный набор, который следует предоставить пользователям. Многие расширения требуют более подробной документации для успешного использования. В этом случае следует создать дополнительную документацию и разместить её в месте, к которому пользователи смогут обратиться.
В рамках данного руководства пропустите написание более подробной документации.
- Как минимум каждое расширение должно предоставлять пользовательскую документацию в следующих файлах:
extension.yaml
,PREINSTALL.md
,POSTINSTALL.md
иCHANGELOG.md
. - При необходимости вам также следует предоставлять пользователям более подробную документацию.
Дополнительная информация
См. документацию по написанию документации .
11. Опубликуйте в Extensions Hub
Теперь, когда код вашего расширения готов и задокументирован, вы готовы поделиться им со всем миром на Extensions Hub. Но поскольку это всего лишь руководство, не делайте этого. Начните писать собственное расширение, используя знания, полученные здесь и в остальной части документации издателя Firebase Extensions, а также изучив исходный код официальных расширений, написанных Firebase.
Когда вы будете готовы опубликовать свою работу на Extensions Hub, вот как это сделать:
- Если вы публикуете своё первое расширение, зарегистрируйтесь как издатель расширений . При регистрации в качестве издателя расширений вы создаёте идентификатор издателя, который позволяет пользователям быстро идентифицировать вас как автора ваших расширений.
Размещайте исходный код вашего расширения в общедоступном месте, доступном для проверки. Если ваш код доступен из проверяемого источника, Firebase может опубликовать его непосредственно из этого места. Это гарантирует публикацию текущей версии расширения и помогает пользователям изучить код, устанавливаемый в их проекты.
В настоящее время это означает, что ваше расширение должно быть доступно в публичном репозитории GitHub.
Загрузите свое расширение в Extensions Hub с помощью команды
firebase ext:dev:upload
.Перейдите на панель управления издателя в консоли Firebase, найдите только что загруженное расширение и нажмите «Опубликовать в Extensions Hub». Это запрашивает проверку нашими специалистами, которая может занять несколько дней. В случае одобрения расширение будет опубликовано в Extensions Hub. В случае отклонения вы получите сообщение с объяснением причины; затем вы сможете устранить выявленные проблемы и повторно отправить расширение на проверку.
- Чтобы поделиться расширениями на Extensions Hub, вам необходимо зарегистрироваться в качестве издателя.
- Публикация из проверяемого источника обязательна и дает пользователям уверенность в том, что устанавливаемый ими код — это тот же код, который они могут изучить на GitHub.
- Используйте команду
firebase ext:dev:upload
для загрузки расширения в Extensions Hub. - Отправьте свои расширения на проверку через панель управления издателя.
Дополнительная информация
Узнайте больше о регистрации в качестве издателя и публикации расширения .