將您的 Cloud Functions 程式碼重新調整為 Firebase 擴充

1. 開始之前

Firebase 擴充功能執行一項特定任務或一組任務,以回應 HTTP 請求或觸發來自其他 Firebase 和 Google 產品(例如 Firebase Cloud Messaging、Cloud Firestore 或 Pub/Sub)的事件。

你將建構什麼

在此 Codelab 中,您將為geohashing建立 Firebase 擴充功能。部署後,您的擴充功能會將 X 座標和 Y 座標轉換為 geohashes,以回應 Firestore 事件或透過可呼叫函數呼叫。這可以作為在所有目標平台上實施 geofire 庫來儲存資料的替代方案,從而節省您的時間。

Firebase 控制台中顯示的 geohash 擴展

你將學到什麼

  • 如何利用現有的 Cloud Functions 程式碼並將其轉換為可分發的 Firebase 擴展
  • 如何設定extension.yaml文件
  • 如何在擴充功能中儲存敏感字串(API 金鑰)
  • 如何允許擴展的開發人員對其進行配置以滿足他們的需求
  • 如何測試和部署擴展

你需要什麼

  • Firebase CLI (安裝與登入)
  • Google 帳戶,例如 Gmail 帳戶
  • Node.js 和npm
  • 您最喜歡的開發環境

2. 設定

取得程式碼

此擴充功能所需的一切都在 GitHub 儲存庫中。首先,取得程式碼並在您最喜歡的開發環境中開啟它。

  1. 解壓縮下載的 zip 檔案。
  2. 若要安裝所需的依賴項,請在functions目錄中開啟終端機並執行npm install命令。

設定 Firebase

此 Codelab 強烈鼓勵使用 Firebase 模擬器。如果您想嘗試使用真實的 Firebase 專案進行擴充開發,請參閱建立 Firebase 專案。此 Codelab 使用 Cloud Functions,因此如果您使用真正的 Firebase 專案而不是模擬器,則需要升級至 Blaze 定價方案

想跳到前面嗎?

您可以下載 Codelab 的完整版本。如果您遇到困難或想要查看完整的擴充功能是什麼樣子,請查看GitHub 儲存庫codelab-end分支或下載完整的 zip。

3.審查代碼

  • 從 zip 檔案中開啟index.ts檔案。請注意,它包含兩個 Cloud Functions 聲明。

這些功能有什麼作用?

這些演示函數用於地理哈希。他們採用座標對並將其轉換為針對 Firestore 中的地理查詢進行最佳化的格式。這些函數模擬 API 呼叫的使用,以便您可以了解有關在擴充功能中處理敏感資料類型的更多資訊。有關更多信息,請參閱有關對 Firestore 中的資料運行地理查詢的文檔。

函數常數

常量是在index.ts文件頂部儘早聲明的。其中一些常數在擴展定義的觸發器中引用。

索引.ts

import {firestore} from "firebase-functions";
import {initializeApp} from "firebase-admin/app";
import {GeoHashService, ResultStatusCode} from "./fake-geohash-service";
import {onCall} from "firebase-functions/v1/https";
import {fieldValueExists} from "./utils";

const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";

initializeApp();

const service = new GeoHashService(apiKey);

Firestore觸發器

index.ts文件中的第一個函數如下所示:

索引.ts

export const locationUpdate = firestore.document(documentPath)
  .onWrite((change) => {
    // item deleted
    if (change.after == null) {
      return 0;
    }
    // double check that both values exist for computation
    if (
      !fieldValueExists(change.after.data(), xField) ||
      !fieldValueExists(change.after.data(), yField)
    ) {
      return 0;
    }
    const x: number = change.after.data()![xField];
    const y: number = change.after.data()![yField];
    const hash = service.convertToHash(x, y);
    // This is to check whether the hash value has changed. If
    // it hasn't, you don't want to write to the document again as it
    // would create a recursive write loop.
    if (fieldValueExists(change.after.data(), outputField)
      && change.after.data()![outputField] == hash) {
      return 0;
    }
    return change.after.ref
      .update(
        {
          [outputField]: hash.hash,
        }
      );
  });

此函數是Firestore 觸發器。當資料庫中發生寫入事件時,函數會透過搜尋xv欄位和yv欄位來回應該事件,如果這兩個欄位都存在,則它計算 geohash 並將輸出寫入指定的文件輸出位置。輸入文檔由users/{uid}常數定義,這表示該函數讀取寫入users/集合的每個文檔,然後處理這些文檔的 geohash。然後它將散列輸出到同一文檔中的雜湊字段。

可呼叫函數

index.ts文件中的下一個函數如下所示:

索引.ts

export const callableHash = onCall((data, context) => {
  if (context.auth == undefined) {
    return {error: "Only authorized users are allowed to call this endpoint"};
  }
  const x = data[xField];
  const y = data[yField];
  if (x == undefined || y == undefined) {
    return {error: "Either x or y parameter was not declared"};
  }
  const result = service.convertToHash(x, y);
  if (result.status != ResultStatusCode.ok) {
    return {error: `Something went wrong ${result.message}`};
  }
  return {result: result.hash};
});

注意onCall函數。它表明該函數是一個可調用函數,可以從客戶端應用程式程式碼中呼叫。此可呼叫函數接受xy參數並傳回 geohash。儘管在此 Codelab 中不會直接呼叫此函數,但它包含在此處作為 Firebase 擴充功能中要配置的內容的範例。

4.設定extension.yaml文件

現在您已經知道擴充功能中的 Cloud Functions 程式碼的用途,您就可以將其打包以進行分發了。每個 Firebase 擴充功能都附帶一個extension.yaml文件,用於描述該擴充功能的用途及其行為方式。

extension.yaml檔案需要一些有關您的擴充功能的初始元資料。以下每個步驟都可以幫助您了解所有欄位的含義以及為什麼需要它們。

  1. 在您先前下載的專案的根目錄中建立一個extension.yaml檔案。首先加入以下內容:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

擴充功能的名稱用作擴充實例 ID 的基礎(使用者可以安裝擴充功能的多個實例,每個實例都有自己的 ID)。然後,Firebase 使用該實例 ID 產生擴充功能的服務帳戶和特定於擴充功能的資源的名稱。版本號表示您的擴充功能的版本。它必須遵循語義版本控制,並且每當您對擴充功能的功能進行更改時都需要更新它。擴充規範版本用於決定要遵循哪個 Firebase 擴充規範,在本例中使用v1beta

  1. 在 YAML 檔案中添加一些使用者友好的詳細資訊:
...

displayName: Latitude and longitude to GeoHash converter
description: A converter for changing your Latitude and longitude coordinates to geohashes.

當開發人員與您的擴充功能互動時,顯示名稱是您的擴充名稱的友善表示。該描述簡要概述了該擴充功能的功能。當擴充部署在extensions.dev上時,它看起來像這樣:

Geohash Converter 擴充功能如在 extensions.dev 所示

  1. 指定擴充中程式碼的許可證。
...

license: Apache-2.0  # The license you want for the extension
  1. 指示誰編寫了擴充功能以及安裝它是否需要付費:
...

author:
  authorName: AUTHOR_NAME
  url: https://github.com/Firebase

billingRequired: true

author部分用於讓您的用戶知道在遇到擴充功能問題或需要有關擴充功能的更多資訊時可以聯絡誰。 billingRequired是必要參數,必須設定為true ,因為所有擴充都依賴 Cloud Functions,這需要 Blaze 計畫。

這涵蓋了extension.yaml檔案中識別此擴充功能所需的最少欄位數。有關可以在擴充功能中指定的其他標識資訊的更多詳細信息,請參閱文件

5. 將 Cloud Functions 程式碼轉換為擴充資源

擴充資源是 Firebase 在擴充安裝期間在專案中建立的專案。然後,擴充功能擁有這些資源,並擁有對其進行操作的特定服務帳戶。在此專案中,這些資源是 Cloud Functions,必須在extension.yaml檔案中定義,因為擴充功能不會自動從 Functions 資料夾中的程式碼建立資源。如果您的 Cloud Functions 未明確宣告為資源,則在部署擴充功能時無法部署它們。

使用者定義的部署位置

  1. 允許用戶指定他們想要部署此擴充功能的位置,並決定是將擴充功能託管在靠近最終用戶還是靠近資料庫的位置更好。在extension.yaml檔案中,包含選擇位置的選項。

擴展.yaml

您現在已準備好編寫函數資源的配置。

  1. extension.yaml檔案中,為locationUpdate函數建立資源物件。將以下內容附加到extension.yaml檔案:
resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}

您將name定義為專案的index.ts檔案中定義的函數名稱。您指定正在部署的函數type ,目前應始終為firebaseextensions.v1beta.function 。然後,定義該函數的properties 。您定義的第一個屬性是與該函數關聯的eventTrigger 。若要反映擴充目前支援的內容,請使用providers/cloud.firestore/eventTypes/document.writeeventType ,該事件類型可在擴充文件的編寫雲端函數中找到。您將resource定義為文件的位置。由於您目前的目標是鏡像程式碼中存在的內容,因此文件路徑偵聽users/{uid} ,其前面帶有預設資料庫位置。

  1. 此擴充功能需要 Firestore 資料庫的讀寫權限。在extension.yaml檔案的最後,指定擴充功能應有權存取的 IAM 角色,以便使用開發人員的 Firebase 專案中的資料庫。
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

datastore.user角色來自擴充支援的 IAM 角色清單。由於擴充將進行讀取和寫入,因此datastore.user角色非常適合這裡。

  1. 還必須新增可調用函數。在extension.yaml檔案中,在resources 屬性下建立一個新資源。這些屬性特定於可調用函數:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

雖然之前的資源使用了eventTrigger ,但這裡使用了httpsTrigger ,它涵蓋了可呼叫函數和 HTTPS 函數。

代碼檢查

為了使您的extension.yamlindex.ts檔案中的程式碼完成的所有內容相匹配,需要進行大量配置。此時完成的extension.yaml檔案應如下所示:

擴展.yaml

name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.

license: Apache-2.0  # The license you want for the extension

author:
  authorName: Sparky
  url: https://github.com/Firebase

billingRequired: true

resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

狀態檢查

此時,您已經設定了擴充功能的初始功能部分,因此您可以使用 Firebase 模擬器實際嘗試它!

  1. 如果您還沒準備好,請在下載的擴充項目的函數資料夾中呼叫npm run build
  2. 在主機系統上建立一個新目錄,並使用firebase init將該目錄連接到您的 Firebase 專案。
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
    This command creates a `firebase.json` file in the directory. In the following steps, you push the configuration specified in this file to Firebase.
  1. 從同一目錄運行firebase ext:install 。將/path/to/extension替換為包含extension.yaml檔案的目錄的絕對路徑。
firebase ext:install /path/to/extension
    This command does two things:
  • 它會提示您指定擴充實例的配置,並建立一個包含該實例的配置資訊的*.env檔案。
  • 它將擴展實例添加到firebase.jsonextensions部分。這充當實例 ID 到擴展版本的映射。
  • 由於您是在本機部署項目,因此您可以指定要使用本機檔案而不是 Google Cloud Secret Manager。

擴充安裝過程的螢幕截圖顯示安裝此擴充功能時本地檔案被用於機密

  1. 使用新配置啟動 Firebase 模擬器:
firebase emulators:start
  1. 執行emulators:start後,導覽至模擬器 Web 視圖中的 Firestore 標籤。
  2. 使用xv數字欄位和yv數字欄位將文件新增至users集合。

Firebase 模擬器中顯示的對話框,用於啟動集合 ID 包含短語的集合

  1. 如果您成功安裝了擴展,該擴展會在文件中建立名為hash的新欄位。

使用者集合以及具有 xv、yv 和哈希字段的用戶文件。

清理乾淨避免衝突

  • 完成測試後,卸載擴充功能 - 您將更新擴充程式碼,並且不希望稍後與目前擴充功能發生衝突。

擴充功能允許同時安裝相同擴充功能的多個版本,因此透過卸載,您可以確保與先前安裝的擴充功能不會發生衝突。

firebase ext:uninstall geohash-ext

目前的解決方案有效,但正如專案開頭所提到的,有一個硬編碼的 API 金鑰來模擬與服務的通訊。如何使用最終用戶的 API 金鑰而不是最初提供的金鑰?請仔細閱讀,找出答案。

6. 使擴充功能可供使用者配置

此時,在 Codelab 中,您已經配置了一個擴展,可與您已編寫的函數的自以為是的設定一起使用,但是如果您的用戶想要使用緯度和經度而不是yx作為指示字段的字段,怎麼辦?笛卡爾平面上的位置?另外,如何讓最終用戶提供自己的 API 金鑰,而不是讓他們使用所提供的 API 金鑰?您可能很快就會超出該 API 的配額。在這種情況下,您可以設定並使用參數。

extension.yaml檔案中定義基本參數

首先轉換開發人員可能具有自訂配置的專案。第一個是XFIELDYFIELD參數。

  1. extension.yaml檔案中,新增以下程式碼,程式使用XFIELDYFIELD欄位參數。這些參數位於先前定義的params YAML 屬性內:

擴展.yaml

params:
  - param: XFIELD
    label: The X Field Name
    description: >-
      The X Field is also known as the **longitude** value. What does
      your Firestore instance refer to as the X value or the longitude
      value. If no value is specified, the extension searches for
      field 'xv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: xv
    required: false
    immutable: false
    example: xv
  - param: YFIELD
    label: The Y Field Name
    description: >-
      The Y Field is also known as the **latitude** value. What does
      your Firestore instance refer to as the Y value or the latitude
      value. If no value is specified, the extension searches for
      field 'yv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: yv
    required: false
    immutable: false
    example: yv
  • param以您(擴充生成者)可見的方式命名參數。稍後在指定參數值時使用該值。
  • 標籤是開發人員可讀的標識符,讓他們知道參數的作用。
  • 描述給出了該值的詳細描述。由於它支援 Markdown,因此它可以連結到額外的文檔,或者可以突出顯示對開發人員可能重要的單字。
  • type定義使用者如何設定參數值的輸入機制。存在多種類型,包括stringselectmultiSelectselectResourcesecret 。要了解有關每個選項的更多信息,請參閱文件
  • validRegex將開發人員輸入限制為某個正規表示式值(在範例中,它基於此處找到的簡單欄位名稱指南);如果失敗了......
  • validationErrorMessage提醒開發人員失敗值。
  • 預設值是開發人員未輸入任何文字時的值。
  • required意味著開發者不需要輸入任何文字。
  • 不可變允許開發人員更新此擴充功能並更改此值。在這種情況下,開發人員應該能夠隨著需求的變化而更改欄位名稱。
  • 範例提供了有效輸入可能會是什麼樣子的想法。

這是很多需要理解的事情!

  1. 在新增特殊參數之前,您還需要將三個參數新增至extension.yaml檔案。
  - param: INPUTPATH
    label: The input document to listen to for changes
    description: >-
      This is the document where you write an x and y value to. Once
      that document has received a value, it notifies the extension to
      calculate a geohash and store that in an output document in a certain
      field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
    type: string
    validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
    validationErrorMessage: >-
      This must point to a document path, not a collection path from the root
      of the database. It must also not start or end with a '/' character.
    required: true
    immutable: false
    example: users/{uid}
  - param: OUTPUTFIELD
    label: Geohash field
    description: >-
      This specifies the field in the output document to store the geohash in.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    required: false
    default: hash
    immutable: false
    example: hash

定義敏感參數

現在,您需要管理使用者指定的 API 金鑰。這是一個敏感字串,不應以純文字形式儲存在函數中。相反,請將此值儲存在Cloud Secret Manager中。這是雲端中的一個特殊位置,用於儲存加密的秘密,並防止它們被意外洩露。這要求開發人員為使用該服務付費,但它在 API 金鑰上增加了額外的安全層,並可能限制詐欺活動。使用者文件提醒開發人員這是一項付費服務,這樣計費就不會出現任何意外。總體來說,使用方法與上面提到的其他字串資源類似。唯一的區別是稱為secret類型。

  • extension.yaml檔案中加入以下程式碼:

擴展.yaml

  - param: APIKEY
    label: GeohashService API Key
    description: >-
      Your geohash service API Key. Since this is a demo, and not a real
      service, you can use : 1234567890.
    type: secret
    required: true
    immutable: false

更新resource屬性以使用參數

如前所述,資源(而不是函數)定義瞭如何觀察資源,因此需要更新locationUpdate資源才能使用新參數。

  • extension.yaml檔案中加入以下程式碼:

擴展.yaml

## Change from this
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}]

## To this
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}

檢查extension.yaml文件

  • 查看extension.yaml檔。它應該看起來像這樣:

擴展.yaml

name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.

license: Apache-2.0  # The license you want to use for the extension

author:
  authorName: Sparky
  url: https://github.com/Firebase

billingRequired: true

params:
  - param: XFIELD
    label: The X Field Name
    description: >-
      The X Field is also known as the **longitude** value. What does
      your Firestore instance refer to as the X value or the longitude
      value. If you don't provide a value for this field, the extension will use 'xv' as the default value.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: xv
    required: false
    immutable: false
    example: xv
  - param: YFIELD
    label: The Y Field Name
    description: >-
      The Y Field is also known as the **latitude** value. What does
      your Firestore instance refer to as the Y value or the latitude
      Value. If you don't provide a value for this field, the extension will use 'yv' as the default value.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: yv
    required: false
    immutable: false
    example: yv
  - param: INPUTPATH
    label: The input document to listen to for changes
    description: >-
      This is the document where you write an x and y value to. Once
      that document has been modified, it notifies the extension to
      compute a geohash and store that in an output document in a certain
      field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
    type: string
    validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
    validationErrorMessage: >-
      This must point to a document path, not a collection path from the root
      of the database. It must also not start or end with a '/' character.
    required: true
    immutable: false
    example: users/{uid}
  - param: OUTPUTFIELD
    label: Geohash field
    description: >-
      This specifies the field in the output document to store the geohash in.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    required: false
    default: hash
    immutable: false
    example: hash
  - param: APIKEY
    label: GeohashService API Key
    description: >-
      Your geohash service API Key. Since this is a demo, and not a real
      service, you can use : 1234567890.
    type: secret
    required: true
    immutable: false

resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

訪問程式碼中的參數

現在所有參數都已在extension.yaml檔案中配置,請將它們新增至index.ts檔案。

  • index.ts檔案中,將預設值替換為process.env.PARAMETER_NAME ,這會取得適當的參數值並將其填入開發人員的 Firebase 專案上部署的函數程式碼中。

索引.ts

// Replace this:
const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";

// with this:
const documentPath = process.env.INPUTPATH!; // this value is ignored since its read from the resource
const xField = process.env.XFIELD!;
const yField = process.env.YFIELD!;
const apiKey = process.env.APIKEY!;
const outputField = process.env.OUTPUTFIELD!;

通常,您希望對環境變數值執行 null 檢查,但在這種情況下,您相信參數值已正確複製。該程式碼現在已配置為使用擴充參數。

7. 建立使用者文檔

在模擬器或 Firebase 擴充市場中測試程式碼之前,需要對擴充功能進行記錄,以便開發人員知道使用該擴充功能時會得到什麼。

  1. 首先建立PREINSTALL.md文件,該文件用於描述功能、安裝的任何先決條件以及潛在的計費影響。

預先安裝.md

Use this extension to automatically convert documents with a latitude and
longitude to a geohash in your database. Additionally, this extension includes a callable function that allows users to make one-time calls
to convert an x,y coordinate into a geohash.

Geohashing is supported for latitudes between 90 and -90 and longitudes
between 180 and -180.

#### Third Party API Key

This extension uses a fictitious third-party API for calculating the
geohash. You need to supply your own API keys. (Since it's fictitious,
you can use 1234567890 as an API key).

#### Additional setup

Before installing this extension, make sure that you've [set up a Cloud
Firestore database](https://firebase.google.com/docs/firestore/quickstart) in your Firebase project.

After installing this extension, you'll need to:

- Update your client code to point to the callable geohash function if you
want to perform arbitrary geohashes.

Detailed information for these post-installation tasks are provided after
you install this extension.

#### 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:
 - Cloud Firestore
 - Cloud Functions (Node.js 16+ runtime. [See
FAQs](https://firebase.google.com/support/faq#extensions-pricing))
 - [Cloud Secret Manager](https://cloud.google.com/secret-manager/pricing)
  1. 為了節省為此項目編寫README.md的時間,請使用便利方法:
firebase ext:info . --markdown > README.md

這結合了PREINSTALL.md檔案的內容和extension.yaml檔案中有關擴充功能的其他詳細資訊。

最後,告知擴充功能的開發人員有關剛安裝的擴充功能的一些其他詳細資訊。完成安裝後,開發人員可能會獲得一些額外的說明和信息,並且可能會獲得一些詳細的安裝後任務,例如在此處設定客戶端程式碼。

  1. 建立POSTINSTALL.md文件,然後包含以下安裝後資訊:

安裝後.md

Congratulations on installing the geohash extension!

#### Function information

* **Firestore Trigger** - ${function:locationUpdate.name} was installed
and is invoked when both an x field (${param:XFIELD}) and y field
(${param:YFIELD}) contain a value.

* **Callable Trigger** - ${function:callableHash.name} was installed and
can be invoked by writing the following client code:
 ```javascript
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const geoHash = httpsCallable(functions, '${function:callableHash.name}');
geoHash({ ${param:XFIELD}: -122.0840, ${param:YFIELD}: 37.4221 })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const error = data.error;
    if (error != null) {
        console.error(`callable error : ${error}`);
    }
    const result = data.result;
    console.log(result);
  });

監控

作為最佳實踐,您可以監控已安裝擴充功能的活動,包括檢查其運作狀況、使用情況和日誌。

The output rendering looks something like this when it's deployed:

<img src="img/82b54a5c6ca34b3c.png" alt="A preview of the latitude and longitude geohash converter extension in the firebase console"  width="957.00" />


## Test the extension with the full configuration
Duration: 03:00


It's time to make sure that the user-configurable extension is working the way it is intended.

* Change into the functions folder and ensure that the latest compiled version of the extensions exists. In the extensions project functions directory, call:

```console
npm run build

這會重新編譯函數,以便在將其部署到模擬器或直接部署到 Firebase 時,最新的原始程式碼可以與擴充一起部署。

接下來,建立一個新目錄來測試擴充。由於擴充功能是根據現有函數開發的,因此請勿從配置擴充功能的資料夾中進行測試,因為這也會嘗試將函數和 Firebase 規則與其一起部署。

安裝 Firebase 模擬器並進行測試

  1. 在主機系統上建立一個新目錄,並使用firebase init將該目錄連接到您的 Firebase 專案。
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. 從該目錄運行firebase ext:install以安裝擴充功能。將/path/to/extension替換為包含extension.yaml檔案的目錄的絕對路徑。這將啟動擴充功能的安裝過程,並建立一個包含您的配置的.env文件,然後再將配置推送到 Firebase 或模擬器。
firebase ext:install /path/to/extension
  • 由於您是在本機部署項目,因此請指定您希望使用本機檔案而不是 Google Cloud Secret Manager。

da928c65ffa8ce15.png

  1. 啟動本地模擬器套件:
firebase emulators:start

安裝並使用真實的 Firebase 專案進行測試

您可以在實際的 Firebase 專案中安裝擴充功能。建議使用測試項目進行測試。如果您想要測試擴充功能的端對端流程,或者 Firebase 模擬器套件尚不支援您的擴充功能的觸發器(請參閱擴充功能模擬器選項),請使用此測試工作流程。模擬器目前支援 Cloud Firestore、即時資料庫和 Pub/Sub 的 HTTP 請求觸發函數和後台事件觸發函數。

  1. 在主機系統上建立一個新目錄,並使用firebase init將該目錄連接到您的 Firebase 專案。
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. 然後,從該目錄執行firebase ext:install以安裝擴充功能。將/path/to/extension替換為包含extension.yaml檔案的目錄的絕對路徑。這將啟動擴充功能的安裝過程,並建立一個包含您的配置的.env文件,然後再將配置推送到 Firebase 或模擬器。
firebase ext:install /path/to/extension
  • 由於您想要直接部署到 Firebase,並且想要使用 Google Cloud Secret Manager,因此需要在安裝擴充功能之前啟動 Secret Manager API
  1. 部署到您的 Firebase 專案。
firebase deploy

測試擴展

  1. 執行firebase deployfirebase emulators:start後,根據需要導覽至Firebase 控制台或模擬器的 Web 視圖的 Firestore 標籤。
  2. 將文件新增至x字段和y字段指定的集合。在這種情況下,更新的文檔位於u/{uid}其中x字段為xvy字段為yv

用於新增 Firestore 記錄的 Firebase 模擬器螢幕

  1. 如果您成功安裝了擴充程序,則擴充功能會在您儲存這兩個欄位後在文件中建立一個名為hash的新欄位。

模擬器中的 Firestore 資料庫畫面顯示已新增的哈希值

8. 恭喜!

您已成功將您的第一個 Cloud Function 轉換為 Firebase 擴充功能!

您新增了一個extension.yaml檔案並對其進行了配置,以便開發人員可以選擇他們希望如何部署您的擴充功能。然後,您建立了使用者文檔,為擴展開發人員在設定擴充功能之前應執行的操作以及成功安裝擴充功能後可能需要執行的步驟提供指導。

現在您知道將 Firebase 函數轉換為可分發的 Firebase 擴充功能所需的關鍵步驟。

下一步是什麼?