Начните создавать расширение

Эта страница проведет вас через шаги, необходимые для создания простого расширения Firebase, которое вы можете установить в своих проектах или поделиться им с другими. Этот простой пример расширения Firebase будет следить за сообщениями в вашей базе данных Realtime и преобразовывать их в верхний регистр.

1. Настройте свою среду и инициализируйте проект.

Прежде чем приступить к созданию расширения, вам необходимо настроить среду сборки с необходимыми инструментами.

  1. Установите Node.js 16 или более новую версию. Один из способов установки Node — использовать nvm (или nvm-windows ).

  2. Установите или обновите Firebase CLI до последней версии. Для установки или обновления с помощью npm выполните следующую команду:

    npm install -g firebase-tools

Теперь используйте Firebase CLI для инициализации нового проекта расширения:

  1. Создайте каталог для вашего расширения и cd в него:

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
  2. Запустите команду Firebase CLI ext:dev:init :

    firebase ext:dev:init

    При появлении запроса выберите JavaScript в качестве языка для функций (но учтите, что вы также можете использовать TypeScript при разработке собственного расширения), а при появлении запроса на установку зависимостей ответьте «да». (Примите значения по умолчанию для любых других параметров.) Эта команда настроит скелетную кодовую базу для нового расширения, с которой вы сможете начать разработку своего расширения.

2. Попробуйте пример расширения с помощью эмулятора

Когда Firebase CLI инициализирует новый каталог расширений, он создает простой пример функции и каталог integration-tests , содержащий файлы, необходимые для запуска расширения с использованием набора эмуляторов Firebase.

Попробуйте запустить пример расширения в эмуляторе:

  1. Перейдите в каталог integration-tests :

    cd functions/integration-tests
  2. Запустите эмулятор с демо-проектом:

    firebase emulators:start --project=demo-test

    Эмулятор загружает расширение в предопределенный "фиктивный" проект ( demo-test ). Расширение на данный момент состоит из одной HTTP-функции, greetTheWorld , которая возвращает сообщение "hello world" при доступе.

  3. Пока эмулятор все еще работает, попробуйте функцию расширения greetTheWorld , перейдя по URL-адресу, который оно вывело при запуске.

    Ваш браузер отображает сообщение «Hello World от greet-the-world».

  4. Исходный код этой функции находится в каталоге 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);
    });
    
  5. Пока эмулятор работает, он автоматически перезагрузит любые изменения, которые вы вносите в код функций. Попробуйте внести небольшое изменение в функцию greetTheWorld :

    функции/index.js

    const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
    

    Сохраните изменения. Эмулятор перезагрузит ваш код, и теперь, когда вы посетите URL функции, вы увидите обновленное приветствие.

3. Добавьте основную информацию в extension.yaml

Теперь, когда у вас настроена среда разработки и запущен эмулятор расширений, вы можете приступить к написанию собственного расширения.

В качестве скромного первого шага отредактируйте предопределенные метаданные расширения, чтобы они отражали расширение, которое вы хотите написать вместо greet-the-world . Эти метаданные хранятся в файле extension.yaml .

  1. Откройте 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, на котором работает расширение, за которым следует описание того, что делает расширение. Вам следует использовать то же соглашение в своих собственных расширениях.

  2. Поскольку вы изменили имя своего расширения, вам также следует обновить конфигурацию эмулятора, указав новое имя:

    1. В functions/integration-tests/firebase.json измените greet-the-world на rtdb-uppercase-messages .
    2. Переименуйте functions/integration-tests/extensions/greet-the-world.env в functions/integration-tests/extensions/rtdb-uppercase-messages.env .

В вашем коде расширения все еще есть некоторые остатки расширения greet-the-world , но оставьте их пока. Вы обновите их в следующих нескольких разделах.

4. Напишите облачную функцию и объявите ее как ресурс расширения.

Теперь вы можете начать писать код. На этом этапе вы напишете облачную функцию, которая выполняет основную задачу вашего расширения, а именно, отслеживает сообщения в вашей базе данных реального времени и преобразует их в верхний регистр.

  1. Откройте исходный код функций расширения (в каталоге 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",
      
    }
    
  2. Каждая функция в вашем расширении должна быть объявлена ​​в файле extension.yaml . Пример расширения объявил greetTheWorld как единственную функцию Cloud; теперь, когда вы заменили ее на 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"
    
  3. Поскольку ваше расширение теперь использует Realtime Database в качестве триггера, вам необходимо обновить конфигурацию эмулятора, чтобы запустить эмулятор RTDB вместе с эмулятором Cloud Functions:

    1. Если эмулятор все еще работает, остановите его, нажав Ctrl-C.

    2. Из каталога functions/integration-tests выполните следующую команду:

      firebase init emulators

      При появлении запроса пропустите настройку проекта по умолчанию, затем выберите эмуляторы функций и баз данных. Примите порты по умолчанию и разрешите инструменту настройки загрузить все необходимые файлы.

    3. Перезапустите эмулятор:

      firebase emulators:start --project=demo-test
  4. Попробуйте обновленное расширение:

    1. Откройте пользовательский интерфейс эмулятора базы данных, используя ссылку, которую эмулятор распечатал при запуске.

    2. Отредактируйте корневой узел базы данных:

      • Поле: messages
      • Тип: json
      • Значение: {"11": {"original": "recipe"}}

      Если все настроено правильно, то при сохранении изменений в базе данных функция расширения makeuppercase должна сработать и добавить дочернюю запись в сообщение 11 с содержимым "upper": "RECIPE" . Просмотрите журналы и вкладки базы данных пользовательского интерфейса эмулятора, чтобы подтвердить ожидаемые результаты.

    3. Попробуйте добавить еще несколько дочерних элементов к узлу messages ( {"original":"any text"} ). Всякий раз, когда вы добавляете новую запись, расширение должно добавлять поле uppercase , содержащее содержимое original поля в верхнем регистре.

Теперь у вас есть полное, хотя и простое, расширение, работающее на экземпляре RTDB. В следующих разделах вы улучшите это расширение, добавив некоторые дополнительные функции. Затем вы подготовите расширение к распространению среди других и, наконец, узнаете, как опубликовать свое расширение на Extensions Hub.

5. Объявление API и ролей

Firebase предоставляет каждому экземпляру установленного расширения ограниченный доступ к проекту и его данным с помощью учетной записи службы для каждого экземпляра. Каждая учетная запись имеет минимальный набор разрешений, необходимых для работы. По этой причине вы должны явно объявить все роли IAM, требуемые вашим расширением; когда пользователи устанавливают ваше расширение, Firebase создает учетную запись службы с этими предоставленными ролями и использует ее для запуска расширения.

Вам не нужно объявлять роли для запуска событий продукта, но вам нужно объявить роль, чтобы иным образом взаимодействовать с ней. Поскольку функция, которую вы добавили на последнем шаге, записывает в базу данных Realtime, вам нужно добавить следующее объявление в extension.yaml :

roles:
  - role: firebasedatabase.admin
    reason: Allows the extension to write to RTDB.

Аналогично вы объявляете API Google, которые использует расширение, в поле apis . Когда пользователи устанавливают ваше расширение, им будет предложено автоматически включить эти API для своего проекта. Обычно это необходимо только для API Google, отличных от Firebase, и не требуется для этого руководства.

6. Определите настраиваемые пользователем параметры

Функция, которую вы создали на последних двух этапах, отслеживала определенное местоположение RTDB для входящих сообщений. Иногда отслеживание определенного местоположения — это действительно то, что вам нужно, например, когда ваше расширение работает со структурой базы данных, которую вы используете исключительно для своего расширения. Однако в большинстве случаев вы захотите сделать эти значения настраиваемыми пользователями, которые устанавливают ваше расширение в своих проектах. Таким образом, пользователи смогут использовать ваше расширение для работы с существующей настройкой базы данных.

Сделайте так, чтобы путь, по которому расширение отслеживает новые сообщения, настраивался пользователем:

  1. В файле 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
    

    Это определяет новый строковый параметр, который пользователям будет предложено задать при установке вашего расширения.

  2. Оставаясь в файле extension.yaml , вернитесь к объявлению makeuppercase и измените поле resource на следующее:

    resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
    

    Токен ${param:MESSAGE_PATH} — это ссылка на параметр, который вы только что определили. Когда ваше расширение запустится, этот токен будет заменен любым значением, которое пользователь настроил для этого параметра, в результате чего функция makeuppercase будет прослушивать указанный пользователем путь. Вы можете использовать этот синтаксис для ссылки на любой определенный пользователем параметр в любом месте extension.yaml (и в POSTINSTALL.md — подробнее об этом позже).

  3. Вы также можете получить доступ к пользовательским параметрам из кода функций.

    В функции, которую вы написали в последнем разделе, вы жестко закодировали путь для отслеживания изменений. Измените определение триггера так, чтобы оно ссылалось на пользовательское значение:

    функции/index.js

    export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
    

    Обратите внимание, что в Firebase Extensions это изменение сделано исключительно в целях документации: когда функция Cloud Function развертывается как часть расширения, она использует определение триггера из файла extension.yaml и игнорирует значение, указанное в определении функции. Тем не менее, хорошей идеей будет документировать в вашем коде, откуда берется это значение.

  4. Вас может разочаровать внесение изменений в код, которые не имеют эффекта во время выполнения, но важный урок, который следует извлечь, заключается в том, что вы можете получить доступ к любому определенному пользователем параметру в коде функции и использовать его как обычное значение в логике функции. В знак признания этой возможности добавьте следующий оператор журнала, чтобы продемонстрировать, что вы действительно получаете доступ к значению, определенному пользователем:

    функции/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.
        ...
    
  5. Обычно пользователям предлагается ввести значения параметров при установке расширения. Однако при использовании эмулятора для тестирования и разработки вы пропускаете процесс установки, поэтому вместо этого вы вводите значения для определяемых пользователем параметров с помощью файла env .

    Откройте functions/integration-tests/extensions/rtdb-uppercase-messages.env и замените определение GREETING следующим:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    Обратите внимание, что указанный выше путь отличается от пути по умолчанию и от пути, который вы определили ранее. Это сделано только для того, чтобы убедиться, что при попытке запустить обновленное расширение ваше определение вступает в силу.

  6. Теперь перезапустите эмулятор и снова посетите пользовательский интерфейс эмулятора базы данных.

    Отредактируйте корневой узел базы данных, используя путь, который вы определили выше:

    • Поле: msgs
    • Тип: json
    • Значение: {"11": {"original": "recipe"}}

    При сохранении изменений в базе данных функция расширения makeuppercase должна сработать, как и раньше, но теперь она также должна вывести определенный пользователем параметр в журнал консоли.

7. Предоставьте перехватчики событий для пользовательской логики

Вы уже видели, как автор расширения, как продукт Firebase может запускать логику, предоставляемую вашим расширением: создание новых записей в Realtime Database запускает вашу функцию makeuppercase . Ваше расширение может иметь аналогичные отношения с пользователями, которые устанавливают ваше расширение: ваше расширение может запускать логику, которую определяет пользователь .

Расширение может предоставлять синхронные хуки , асинхронные хуки или и то, и другое. Синхронные хуки дают пользователям возможность выполнять задачи, которые блокируют завершение одной из функций расширения. Это может быть полезно, например, чтобы предоставить пользователям возможность выполнять пользовательскую предварительную обработку перед тем, как расширение выполнит свою работу.

В этом руководстве вы добавите асинхронный хук в свое расширение, который позволит пользователям определять собственные шаги обработки, которые будут выполняться после того, как ваше расширение запишет сообщение в верхнем регистре в базу данных Realtime. Асинхронные хуки используют Eventarc для запуска пользовательских функций. Расширения объявляют типы событий, которые они генерируют, и когда пользователи устанавливают расширение, они выбирают, какие типы событий им интересны. Если они выберут хотя бы одно событие, Firebase предоставит канал Eventarc для расширения в рамках процесса установки. Затем пользователи могут развернуть собственные облачные функции, которые прослушивают этот канал и срабатывают, когда расширение публикует новые события.

Чтобы добавить асинхронный хук, выполните следующие действия:

  1. В файле 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 .)

  2. В конце функции 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 , содержащую исходные и заглавные сообщения. Определяемые пользователем функции, которые запускают событие, могут использовать эту информацию.

  3. Обычно переменные окружения 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
    

На этом этапе вы выполнили все необходимые шаги для добавления асинхронного обработчика событий в свое расширение.

Чтобы опробовать эту новую функцию, которую вы только что реализовали, в следующих нескольких шагах возьмите на себя роль пользователя, устанавливающего расширение:

  1. Из каталога functions/integration-tests инициализируйте новый проект Firebase:

    firebase init functions

    При появлении запроса откажитесь от настройки проекта по умолчанию, выберите JavaScript в качестве языка Cloud Functions и установите требуемые зависимости. Этот проект представляет собой проект пользователя , в котором установлено ваше расширение.

  2. Отредактируйте 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 события и при срабатывании добавляет три восклицательных знака к новому сообщению с заглавными буквами.

  3. Перезапустите эмулятор. Эмулятор загрузит функции расширения, а также функцию постобработки, определенную «пользователем».

  4. Откройте пользовательский интерфейс эмулятора базы данных и отредактируйте корневой узел базы данных, используя путь, который вы определили выше:

    • Поле: msgs
    • Тип: json
    • Значение: {"11": {"original": "recipe"}}

    При сохранении изменений в базе данных функция makeuppercase расширения и функция extraemphasis пользователя должны сработать последовательно, в результате чего upper поле получит значение RECIPE!!! .

8. Добавьте обработчики событий жизненного цикла

Расширение, которое вы написали до сих пор, обрабатывает сообщения по мере их создания. Но что, если у ваших пользователей уже есть база данных сообщений, когда они устанавливают расширение? В Firebase Extensions есть функция, называемая хуками событий жизненного цикла , которую вы можете использовать для запуска действий при установке, обновлении или перенастройке вашего расширения. В этом разделе вы будете использовать хуки событий жизненного цикла для заполнения существующей базы данных сообщений проекта сообщениями в верхнем регистре, когда пользователь устанавливает ваше расширение.

Firebase Extensions использует Cloud Tasks для запуска обработчиков событий жизненного цикла. Вы определяете обработчики событий с помощью Cloud Functions; всякий раз, когда экземпляр вашего расширения достигает одного из поддерживаемых событий жизненного цикла, если вы определили обработчик, он добавляет обработчик в очередь Cloud Tasks. Затем Cloud Tasks асинхронно выполняет обработчик. Пока обработчик событий жизненного цикла работает, консоль Firebase сообщает пользователю, что экземпляр расширения выполняет задачу обработки. Функция обработчика должна сообщать пользователю о текущем состоянии и завершении задачи.

Чтобы добавить обработчик событий жизненного цикла, который заполняет существующие сообщения, выполните следующие действия:

  1. Определите новую облачную функцию, которая запускается событиями очереди задач:

    функции/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.");
      }
    });
    

    Обратите внимание, что функция обрабатывает только несколько записей, прежде чем добавить себя обратно в очередь задач. Это часто используемая стратегия для обработки задач, которые не могут быть завершены в течение окна тайм-аута облачной функции. Поскольку вы не можете предсказать, сколько сообщений уже может быть у пользователя в его базе данных, когда он устанавливает ваше расширение, эта стратегия хорошо подходит.

  2. В файле 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
    
  3. Хотя заполнение существующих сообщений — это хорошо, расширение может работать и без него. В таких ситуациях следует сделать запуск обработчиков событий жизненного цикла необязательным.

    Для этого добавьте новый параметр в 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 вам нужно будет установить расширение в реальном проекте. Это также хорошо, поскольку с добавлением этой функции автоматического заполнения расширение руководства теперь является полностью готовым к коду!

9. Развертывание в реальном проекте Firebase

Хотя эмулятор расширений — отличный инструмент для быстрой итерации расширения в процессе разработки, в какой-то момент вам захочется опробовать его в реальном проекте.

Для этого сначала создайте новый проект с некоторыми включенными службами:

  1. В консоли Firebase добавьте новый проект.
  2. Обновите свой проект до плана Blaze с оплатой по мере использования. Cloud Functions for Firebase требует, чтобы у вашего проекта был платежный аккаунт, поэтому для установки расширения вам также понадобится платежный аккаунт.
  3. В новом проекте включите базу данных в реальном времени .
  4. Поскольку вы хотите проверить способность вашего расширения заполнять существующие данные при установке, импортируйте несколько образцов данных в ваш экземпляр базы данных реального времени:
    1. Загрузите некоторые исходные данные RTDB .
    2. На странице «База данных реального времени» консоли Firebase нажмите (еще) > Импорт JSON и выберите файл, который вы только что скачали.
  5. Чтобы включить функцию обратного заполнения для использования метода orderByChild , настройте базу данных для индексации сообщений по значению upper :

    {
      "rules": {
        ".read": false,
        ".write": false,
        "messages": {
          ".indexOn": "upper"
        }
      }
    }
    

Теперь установите расширение из локального источника в новый проект:

  1. Создайте новый каталог для вашего проекта Firebase:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. Инициализируйте проект Firebase в рабочем каталоге:

    firebase init database

    При появлении запроса выберите проект, который вы только что создали.

  3. Установите расширение в свой локальный проект Firebase:

    firebase ext:install /path/to/rtdb-uppercase-messages

    Здесь вы можете увидеть, как выглядит пользовательский опыт при установке расширения с помощью инструмента Firebase CLI. Обязательно выберите «да», когда инструмент конфигурации спросит, хотите ли вы заполнить существующую базу данных.

    После выбора параметров конфигурации Firebase CLI сохранит вашу конфигурацию в каталоге extensions и запишет местоположение источника расширения в файл firebase.json . В совокупности эти две записи называются манифестом расширений . Пользователи могут использовать манифест для сохранения конфигурации своих расширений и развертывания ее в различных проектах.

  4. Разверните конфигурацию расширения в вашем рабочем проекте:

    firebase deploy --only extensions

Если все пройдет хорошо, Firebase CLI должен загрузить ваше расширение в ваш проект и установить его. После завершения установки будет запущена задача обратного заполнения, и через несколько минут ваша база данных будет обновлена ​​сообщениями в верхнем регистре. Добавьте несколько новых узлов в базу данных сообщений и убедитесь, что расширение также работает для новых сообщений.

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.

Дополнительная документация

Документация, обсуждаемая выше, является минимальным набором документации, который вы должны предоставить пользователям. Многие расширения требуют более подробной документации для успешного использования пользователями. В этом случае вам следует написать дополнительную документацию и разместить ее где-то, куда вы сможете указать пользователям.

В целях данного руководства пропустите написание более подробной документации.

11. Опубликуйте на Extensions Hub

Теперь, когда код вашего расширения завершен и задокументирован, вы готовы поделиться им с миром на Extensions Hub. Но поскольку это всего лишь руководство, не делайте этого на самом деле. Идите и начните писать свое собственное расширение, используя то, что вы узнали здесь и в остальной части документации издателя Firebase Extensions, и изучив исходный код официальных расширений, написанных Firebase.

Когда вы будете готовы опубликовать свою работу на Extensions Hub, вот как это сделать:

  1. Если вы публикуете свое первое расширение, зарегистрируйтесь как издатель расширений . Когда вы регистрируетесь как издатель расширений, вы создаете идентификатор издателя, который позволяет пользователям быстро идентифицировать вас как автора ваших расширений.
  2. Размещайте исходный код вашего расширения в общедоступном проверяемом месте. Когда ваш код доступен из проверяемого источника, Firebase может опубликовать ваше расширение непосредственно из этого места. Это поможет вам убедиться, что вы публикуете текущую выпущенную версию вашего расширения, и поможет пользователям, позволяя им изучить код, который они устанавливают в свои проекты.

    В настоящее время это означает размещение вашего расширения в публичном репозитории GitHub.

  3. Загрузите свое расширение в Extensions Hub с помощью команды firebase ext:dev:upload .

  4. Перейдите на панель инструментов издателя в консоли Firebase, найдите только что загруженное расширение и нажмите «Опубликовать в Extensions Hub». Это запрашивает проверку от наших сотрудников по проверке, которая может занять несколько дней. В случае одобрения расширение будет опубликовано в Extensions Hub. В случае отклонения вы получите сообщение с объяснением причины; затем вы можете устранить указанные проблемы и повторно отправить на проверку.