На этой странице описаны шаги, необходимые для создания простого расширения Firebase, которое вы можете установить в свои проекты или поделиться им с другими. Этот простой пример расширения Firebase будет отслеживать сообщения в вашей базе данных Realtime Database и преобразовывать их в верхний регистр.
1. Настройте свою среду и инициализируйте проект.
Прежде чем приступить к разработке расширения, вам потребуется настроить среду сборки с необходимыми инструментами.
Установите Node.js версии 16 или новее. Один из способов установки Node — использование nvm (или nvm-windows ).
Установите или обновите Firebase CLI до последней версии. Для установки или обновления с помощью
npmвыполните следующую команду:npm install -g firebase-tools
Теперь воспользуйтесь интерфейсом командной строки Firebase для инициализации нового проекта расширения:
Создайте директорию для вашего расширения и перейдите в неё с помощью
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 from greet-the-world".
Исходный код этой функции находится в каталоге
functionsрасширения. Откройте исходный код в любом редакторе или IDE по вашему выбору:functions/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:functions/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. Замените его содержимое следующим:functions/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— подробнее об этом позже).Вы также можете получить доступ к определяемым пользователем параметрам из кода ваших функций.
В функции, которую вы написали в предыдущем разделе, вы жестко задали путь для отслеживания изменений. Измените определение триггера, чтобы оно ссылалось на заданное пользователем значение:
functions/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreateОбратите внимание, что в Firebase Extensions это изменение внесено исключительно в целях документирования: при развертывании облачной функции в составе расширения используется определение триггера из файла
extension.yaml, и игнорируется значение, указанное в определении функции. Тем не менее, рекомендуется документировать в коде, откуда берется это значение.Возможно, вас разочарует изменение кода, не имеющее эффекта во время выполнения, но важный урок, который следует усвоить, заключается в том, что вы можете получить доступ к любому пользовательскому параметру в коде вашей функции и использовать его как обычное значение в логике функции. В качестве подтверждения этой возможности добавьте следующее сообщение в лог, чтобы продемонстрировать, что вы действительно обращаетесь к значению, определенному пользователем:
functions/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добавьте код, который отправляет событие того типа, который вы только что объявили:functions/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 в качестве языка Cloud Functions и установите необходимые зависимости. Этот проект представляет собой проект пользователя , в котором установлено ваше расширение.
Отредактируйте
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 используют Cloud Tasks для запуска обработчиков событий жизненного цикла. Вы определяете обработчики событий с помощью Cloud Functions; всякий раз, когда экземпляр вашего расширения достигает одного из поддерживаемых событий жизненного цикла, если вы определили обработчик, он добавляется в очередь Cloud Tasks. Затем Cloud Tasks асинхронно выполняет обработчик. Во время выполнения обработчика события жизненного цикла консоль Firebase сообщает пользователю, что экземпляр расширения имеет задачу обработки, находящуюся в процессе. Ваша функция-обработчик отвечает за передачу пользователю информации о текущем состоянии и завершении задачи.
Чтобы добавить обработчик событий жизненного цикла, который заполняет существующие сообщения данными, выполните следующие действия:
Определите новую облачную функцию, которая запускается событиями из очереди задач:
functions/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и завершите работу функции досрочно, если он не задан:functions/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 требуется, чтобы у вашего проекта был платежный аккаунт, поэтому он также необходим для установки расширения.
- В новом проекте включите функцию "База данных в реальном времени" .
- Поскольку вы хотите проверить способность вашего расширения заполнять существующие данные при установке, импортируйте несколько примеров данных в ваш экземпляр базы данных реального времени:
- Загрузите некоторые исходные данные из базы данных 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. Обязательно выберите «да», когда инструмент настройки спросит, хотите ли вы заполнить существующую базу данных.
После выбора параметров конфигурации Firebase CLI сохранит вашу конфигурацию в каталоге
extensionsи укажет местоположение исходного кода расширения в файлеfirebase.json. Вместе эти две записи называются манифестом расширений . Пользователи могут использовать манифест для сохранения конфигурации своих расширений и развертывания их в различных проектах.Разверните конфигурацию расширения в своем рабочем проекте:
firebase deploy --only extensions
Если все пройдет успешно, Firebase CLI должен загрузить ваше расширение в ваш проект и установить его. После завершения установки запустится задача заполнения базы данных, и через несколько минут она будет обновлена сообщениями, написанными в верхнем регистре. Добавьте несколько новых узлов в базу данных сообщений и убедитесь, что расширение также работает для новых сообщений.
- Пользователи могут создать манифест расширения с помощью команды
firebase ext:install. Также эту команду можно использовать для установки расширения из локального источника. - Разверните конфигурацию расширения из манифеста в работающий проект с помощью
firebase deploy. - Хотя здесь это не показано, пользователи также могут устанавливать расширения в свои проекты из Центра расширений.
Более подробная информация
См. пользовательскую документацию по управлению конфигурациями проекта с помощью манифеста расширений .
10. Напишите документацию.
Прежде чем делиться своим расширением с пользователями, убедитесь, что вы предоставили достаточно документации, чтобы они могли успешно его использовать.
При инициализации проекта расширения Firebase CLI создал заглушки минимально необходимой документации. Обновите эти файлы, чтобы они точно отражали созданное вами расширение.
extension.yaml
Вы уже обновляли этот файл в процессе разработки расширения, поэтому сейчас вам не нужно вносить никаких дополнительных обновлений.
Однако не следует недооценивать важность документации, содержащейся в этом файле. Помимо важной идентификационной информации расширения — имени, описания, автора, местоположения официального репозитория — файл extension.yaml содержит документацию для каждого ресурса и настраиваемого пользователем параметра, доступную пользователям. Эта информация отображается пользователям в консоли Firebase, Центре расширений и Firebase CLI.
PREINSTALL.md
В этом файле предоставьте пользователю необходимую информацию перед установкой расширения: кратко опишите его функции, объясните необходимые предварительные условия и предоставьте информацию о платежных последствиях установки расширения. Если у вас есть веб-сайт с дополнительной информацией, это также хорошее место для размещения ссылки на него.
Текст этого файла отображается пользователю в Центре расширений и командой firebase ext:info .
Вот пример файла предварительной установки:
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.
Загрузите свое расширение в Центр расширений, используя команду
firebase ext:dev:upload.Перейдите в панель управления издателя в консоли Firebase, найдите только что загруженное расширение и нажмите «Опубликовать в Extensions Hub». Это запросит проверку у наших сотрудников, которая может занять несколько дней. В случае одобрения расширение будет опубликовано в Extensions Hub. В случае отклонения вы получите сообщение с объяснением причины; после этого вы сможете устранить выявленные проблемы и повторно отправить расширение на проверку.
- Для публикации расширений в Extensions Hub необходимо быть зарегистрированным издателем.
- Публикация из проверяемого источника является обязательной и гарантирует пользователям, что устанавливаемый ими код — это тот же самый код, который они могут проверить на GitHub.
- Используйте команду
firebase ext:dev:uploadдля загрузки расширения в Extensions Hub. - Отправляйте свои расширения на проверку через панель управления издателя.
Более подробная информация
Узнайте больше о регистрации в качестве издателя и публикации расширения .