開始建立擴充功能

本頁面將逐步說明建構簡單 Firebase 擴充功能的必要步驟,您可以將擴充功能安裝在專案中,或與其他人分享。這個簡單的 Firebase 擴充功能範例會監控即時資料庫中的訊息,並將訊息轉換為大寫。

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 函式,方法是造訪該函式啟動時顯示的網址。

    瀏覽器會顯示「Hello World from greet-the-world」訊息。

  4. 這個函式的原始碼位於擴充功能的 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);
    });
    
  5. 模擬器執行時,會自動重新載入您對 Functions 程式碼所做的任何變更。請嘗試對 greetTheWorld 函式進行小幅變更:

    functions/index.js

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

    儲存變更。模擬器會重新載入程式碼,現在您造訪函式網址時,就會看到更新後的問候語。

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. 編寫 Cloud 函式並宣告為擴充功能資源

您現在可以開始編寫程式碼了。在這個步驟中,您將編寫 Cloud 函式,執行擴充功能的核心工作,也就是監控即時資料庫中的訊息,並將訊息轉換為大寫。

  1. 在您選擇的編輯器或 IDE 中,開啟擴充功能函式的來源 (位於擴充功能的 functions 目錄中)。將其內容替換為以下內容:

    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 模組語法 (importexport),而非 CommonJS (require)。如要在 Node 中使用 ES 模組,請在 functions/package.json 中指定 "type": "module"

    {
      "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. 由於擴充功能現在使用即時資料庫做為觸發事件,因此您需要更新模擬器設定,以便同時執行 RTDB 模擬器和 Cloud Functions 模擬器:

    1. 如果模擬器仍在執行中,請按下 Ctrl-C 停止模擬器。

    2. functions/integration-tests 目錄中執行下列指令:

      firebase init emulators

      系統詢問時,請略過設定預設專案,然後選取「函式」和「資料庫」模擬器。接受預設連接埠,並允許設定工具下載任何必要檔案。

    3. 重新啟動模擬器:

      firebase emulators:start --project=demo-test
  4. 試用更新後的擴充功能:

    1. 使用模擬器啟動時顯示的連結,開啟資料庫模擬器 UI。

    2. 編輯資料庫的根節點:

      • 欄位: messages
      • 類型: json
      • 值: {"11": {"original": "recipe"}}

      如果一切設定正確,當您儲存資料庫變更時,擴充功能的 makeuppercase 函式應會觸發,並在訊息 11 中新增子記錄,內容為 "upper": "RECIPE"。請查看模擬器 UI 的記錄和資料庫分頁,確認預期結果。

    3. 請嘗試在 messages 節點 ({"original":"any text"}) 中新增更多子項。每次新增新記錄時,擴充功能都應新增 uppercase 欄位,其中包含 original 欄位的大寫內容。

您現在擁有一個完整 (雖然簡單) 的擴充功能,可在 RTDB 例項上運作。在後續章節中,您將透過一些額外功能來改良這個擴充功能。接著,您將準備好擴充功能,以便發布給其他人,最後,瞭解如何在 Extensions Hub 中發布擴充功能。

5. 宣告 API 和角色

Firebase 會使用個別執行個體服務帳戶,授予已安裝擴充功能的每個例項有限的專案存取權和資料存取權。每個帳戶都具備運作所需的最低權限。因此,您必須明確宣告擴充功能所需的 IAM 角色;當使用者安裝擴充功能時,Firebase 會建立具有這些角色的服務帳戶,並使用該帳戶執行擴充功能。

您不需要宣告角色來觸發產品事件,但需要宣告角色才能以其他方式與產品互動。由於您在上一節新增的函式會寫入即時資料庫,因此您需要在 extension.yaml 中加入下列宣告:

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

同樣地,您也可以在 apis 欄位中宣告擴充功能使用的 Google API。使用者安裝擴充功能時,系統會詢問他們是否要為專案自動啟用這些 API。這項操作通常只需要在非 Firebase Google API 中執行,本指南不需要這麼做。

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.yamlPOSTINSTALL.md 中 (後文會進一步說明) 的任何位置參照任何使用者定義的參數。

  3. 您也可以透過函式程式碼存取使用者定義的參數。

    在上一節中編寫的函式中,您將路徑硬式編碼為要監控變更的路徑。請改變觸發條件定義,改為參照使用者定義的值:

    functions/index.js

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

    請注意,在 Firebase 擴充功能中,這項變更純粹是為了說明文件:當 Cloud 函式以擴充功能的一部分部署時,會使用 extension.yaml 檔案中的觸發條件定義,並忽略函式定義中指定的值。不過,建議您在程式碼中記錄這個值的來源。

  4. 您可能會發現,程式碼變更沒有任何執行階段效果,這可能會讓您感到失望,但您可以從中學到重要的一課,那就是您可以在函式程式碼中存取任何使用者定義的參數,並在函式邏輯中將其用作一般值。為了讓這項功能生效,請加入下列記錄陳述式,證明您確實存取使用者定義的值:

    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.
        ...
    
  5. 通常,使用者安裝擴充功能時,系統會提示他們提供參數值。不過,如果您使用模擬器進行測試和開發,則會略過安裝程序,並改為使用 env 檔案為使用者定義的參數提供值。

    開啟 functions/integration-tests/extensions/rtdb-uppercase-messages.env,並將 GREETING 定義替換為以下內容:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    請注意,上述路徑與預設路徑和先前定義的路徑不同;這只是為了讓您在嘗試更新的擴充功能時,能確認定義已生效。

  6. 請重新啟動模擬器,然後再次造訪資料庫模擬器 UI。

    使用上述定義的路徑編輯資料庫的根節點:

    • 欄位: msgs
    • 類型: json
    • 值: {"11": {"original": "recipe"}}

    儲存資料庫變更後,擴充功能的 makeuppercase 函式應會如先前一樣觸發,但現在也應會將使用者定義的參數列印到主控台記錄中。

7. 為使用者定義的邏輯提供事件鉤子

您已經瞭解,身為擴充功能作者,如何讓 Firebase 產品觸發擴充功能提供的邏輯:在即時資料庫中建立新記錄會觸發 makeuppercase 函式。您的擴充功能可以與安裝擴充功能的使用者建立類似的關係:使用者定義的邏輯可觸發擴充功能

擴充功能可以提供同步鉤針非同步鉤針,或同時提供兩者。同步掛鉤可讓使用者執行會阻斷擴充功能某個函式完成的作業。舉例來說,這項功能可讓使用者在擴充功能執行作業前,先執行自訂預先處理作業。

在本指南中,您將在擴充功能中新增非同步掛鉤,讓使用者在擴充功能將大寫訊息寫入 Realtime Database 後,自行定義要執行的處理步驟。非同步掛鉤會使用 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>。(您目前還沒有發布商 ID,因此請先使用 test-publisher)。

  2. 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 酬載,其中包含原始和大寫訊息。觸發事件的使用者定義函式可以使用這項資訊。

  3. 通常,系統會根據使用者在安裝期間選取的選項,定義 EVENTARC_CHANNELEXT_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. 重新啟動模擬器。模擬器會載入擴充功能的函式,以及「user」定義的後置處理函式。

  4. 前往資料庫模擬器 UI,並使用上述定義的路徑編輯資料庫的根節點:

    • 欄位:msgs
    • 類型: json
    • 值: {"11": {"original": "recipe"}}

    儲存資料庫變更時,擴充功能的 makeuppercase 函式和使用者的 extraemphasis 函式應依序觸發,導致 upper 欄位取得 RECIPE!!! 值。

8. 新增生命週期事件處理常式

您目前編寫的擴充功能會在訊息建立時進行處理。不過,如果使用者在安裝擴充功能時,已經有訊息資料庫,該怎麼辦呢?Firebase Extensions 提供「生命週期事件鉤子」功能,可在擴充功能安裝、更新或重新設定時觸發動作。在本節中,您將使用生命週期事件鉤子,在使用者安裝擴充功能時,以大寫訊息填補專案的現有訊息資料庫。

Firebase 擴充功能會使用 Cloud Tasks 執行生命週期事件處理常式。您可以使用 Cloud 函式定義事件處理常式。如果您已定義處理常式,只要擴充功能的例項達到任一支援的生命週期事件,就會將處理常式新增至 Cloud Tasks 佇列。接著,Cloud Tasks 會以非同步方式執行處理常式。生命週期事件處理常式執行時,Firebase 控制台會向使用者回報擴充功能例項有正在處理的工作。處理常式函式會將目前狀態和工作完成情形回報給使用者。

如要新增生命週期事件處理常式,以便補充現有訊息,請執行下列操作:

  1. 定義由工作佇列事件觸發的新 Cloud Function:

    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.");
      }
    });
    

    請注意,函式只會處理幾個記錄,然後將自己加回工作佇列。這是處理無法在 Cloud 函式逾時時間內完成的處理工作時常用的策略。由於您無法預測使用者在安裝擴充功能時,資料庫中可能已有多少訊息,因此這個策略非常適合。

  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 參數的值,如果未設定,則提早結束:

    functions/index.js

    if (!process.env.DO_BACKFILL) {
      return getExtensions()
        .runtime()
        .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped.");
    }
    

有了上述變更,擴充功能現在會在安裝時將現有訊息轉換為大寫。

到目前為止,您已使用擴充功能模擬器開發擴充功能,並測試目前的變更。不過,擴充功能模擬器會略過安裝程序,因此如要測試 onInstall 事件處理常式,您必須在實際專案中安裝擴充功能。不過,這也沒什麼大不了的,因為有了這項自動填補功能,教學課程擴充功能現在已完成程式碼!

9. 部署至實際的 Firebase 專案

雖然擴充功能模擬器是開發期間快速疊代擴充功能的絕佳工具,但您還是應該在實際專案中試試這個工具。

如要這麼做,請先設定已啟用部分服務的新專案:

  1. Firebase 主控台中新增專案。
  2. 將專案升級至即付即用 Blaze 方案。Firebase 專用的 Cloud Functions 需要專案具備帳單帳戶,因此您也需要帳單帳戶才能安裝擴充功能。
  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 會建立所需最低說明文件的虛設版本。更新這些檔案,確實反映您建構的擴充功能。

extension.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

這個檔案包含使用者在成功安裝擴充功能後,可能會需要的資訊,例如後續設定步驟、擴充功能運作示例等等。

設定及安裝擴充功能後,Firebase 主控台會顯示 POSTINSTALL.md 的內容。您可以在這個檔案中參照使用者參數,系統會以設定的值取代這些參數。

以下是教學課程擴充功能的範例安裝後檔案:

### 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 中發布

擴充功能的程式碼已完成並完成文件編寫,您現在可以透過擴充功能中心向全世界分享。但這只是教學課程,因此請勿實際執行這項操作。請根據您在這裡和其他 Firebase Extensions 發布者說明文件中學到的知識,以及檢查 Firebase 官方擴充功能的來源,開始撰寫自己的擴充功能。

準備好在 Extensions Hub 發布作品時,請按照下列步驟操作:

  1. 如果您要發布第一個擴充功能,請註冊為擴充功能發布商。註冊為擴充功能發布商時,您會建立發布商 ID,讓使用者快速辨識您是擴充功能的作者。
  2. 在可公開驗證的位置代管擴充功能的原始碼。如果您的程式碼可從可驗證的來源取得,Firebase 就能直接從這個位置發布擴充功能。這有助於確保您發布的擴充功能是目前已發布的版本,並讓使用者檢查他們在專案中安裝的程式碼,為他們提供協助。

    目前這表示要將擴充功能提供至公開的 GitHub 存放區。

  3. 使用 firebase ext:dev:upload 指令,將擴充功能上傳至擴充功能中心。

  4. 前往 Firebase 控制台中的發布商資訊主頁,找出您剛上傳的擴充功能,然後按一下「發布至擴充功能中心」。這項要求會由審查人員進行審查,可能需要幾天的時間。經過核准後,擴充功能就會發布到 Extensions Hub。如果遭到拒絕,您會收到說明原因的訊息,屆時您可以解決檢舉的問題,並重新送交審查。