Bắt đầu tạo tiện ích

Trang này hướng dẫn bạn các bước cần thiết để tạo một Firebase đơn giản Tiện ích mà bạn có thể cài đặt trong các dự án của mình hoặc chia sẻ với người khác. Chiến dịch này ví dụ đơn giản về Tiện ích Firebase sẽ theo dõi Cơ sở dữ liệu theo thời gian thực của bạn trong thư và chuyển chúng thành chữ hoa.

1. Thiết lập môi trường và khởi chạy dự án

Trước khi có thể bắt đầu tạo tiện ích, bạn cần thiết lập bản dựng bằng các công cụ cần thiết.

  1. Cài đặt Node.js 16 trở lên. Có một cách để cài đặt Nút là dùng nvm (hoặc nvm-windows).

  2. Cài đặt hoặc cập nhật lên phiên bản mới nhất của Firebase CLI. Người nhận cài đặt hoặc cập nhật bằng npm, hãy chạy lệnh này:

    npm install -g firebase-tools
    

Bây giờ, hãy sử dụng Giao diện dòng lệnh (CLI) của Firebase để khởi chạy một dự án tiện ích mới:

  1. Tạo một thư mục cho tiện ích của bạn và cd vào thư mục đó:

    mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
    
  2. Chạy lệnh ext:dev:init của Firebase CLI:

    firebase ext:dev:init
    

    Khi được nhắc, hãy chọn JavaScript làm ngôn ngữ cho các hàm (nhưng lưu ý rằng bạn cũng có thể sử dụng TypeScript khi phát triển tiện ích của riêng mình) và, khi được yêu cầu cài đặt phần phụ thuộc, hãy trả lời "có". (Chấp nhận các giá trị mặc định cho bất kỳ tuỳ chọn nào khác). Lệnh này sẽ thiết lập cơ sở mã khung cho một tiện ích mở rộng mới mà từ đó bạn có thể bắt đầu phát triển tiện ích của mình.

2. Dùng thử tiện ích mẫu bằng trình mô phỏng

Khi Firebase CLI khởi chạy thư mục tiện ích mới, thư mục này sẽ tạo hàm ví dụ đơn giản và một thư mục integration-tests chứa tệp cần thiết để chạy tiện ích bằng bộ trình mô phỏng Firebase.

Hãy thử chạy tiện ích mẫu trong trình mô phỏng:

  1. Thay đổi sang thư mục integration-tests:

    cd functions/integration-tests
    
  2. Khởi động trình mô phỏng bằng một dự án minh hoạ:

    firebase emulators:start --project=demo-test
    

    Trình mô phỏng tải tiện ích vào một "dummy" được xác định trước dự án (demo-test). Cho đến nay, tiện ích này bao gồm một tiện ích được kích hoạt HTTP hàm greetTheWorld trả về một câu lệnh "xin chào thế giới" thông báo khi truy cập.

  3. Khi trình mô phỏng vẫn đang chạy, hãy thử dùng greetTheWorld của tiện ích bằng cách truy cập URL đã in khi bạn khởi động.

    Trình duyệt của bạn hiển thị thông báo "Hello World from Greeting-the-world".

  4. Mã nguồn cho hàm này nằm trong functions của tiện ích thư mục. Mở nguồn trong trình chỉnh sửa hoặc IDE mà bạn chọn:

    functions/index.js

    const functions = require("firebase-functions");
    
    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. Khi đang chạy, trình mô phỏng sẽ tự động tải lại mọi thay đổi mà bạn thực hiện thực hiện cho mã Hàm của bạn. Hãy thử thực hiện một thay đổi nhỏ đối với Hàm greetTheWorld:

    functions/index.js

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

    Lưu thay đổi. Trình mô phỏng sẽ tải lại mã của bạn và bây giờ, khi bạn hãy truy cập URL hàm, bạn sẽ thấy lời chào được cập nhật.

3. Thêm thông tin cơ bản vào extensions.yaml

Giờ đây, bạn đã thiết lập môi trường phát triển và đang chạy trình mô phỏng tiện ích mở rộng, bạn có thể bắt đầu viết tiện ích của riêng mình.

Bước đầu tiên đơn giản là chỉnh sửa siêu dữ liệu của tiện ích được xác định trước để phản ánh tiện ích bạn muốn viết thay cho greet-the-world. Siêu dữ liệu này được lưu trữ trong tệp extension.yaml.

  1. Mở extension.yaml trong trình chỉnh sửa của bạn và thay thế toàn bộ nội dung của chứa những nội dung sau:

    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
    

    Lưu ý quy ước đặt tên được sử dụng trong trường name: Firebase chính thức tiện ích được đặt tên bằng một tiền tố cho biết sản phẩm Firebase chính tiện ích hoạt động, theo sau là mô tả về tiện ích mà tiện ích làm. Bạn nên sử dụng cùng một quy ước trong các tiện ích của riêng mình.

  2. Vì bạn đã thay đổi tên của tiện ích, bạn cũng nên cập nhật cấu hình trình mô phỏng với tên mới:

    1. Trong functions/integration-tests/firebase.json, hãy thay đổi greet-the-world đến rtdb-uppercase-messages.
    2. Đổi tên functions/integration-tests/extensions/greet-the-world.env thành functions/integration-tests/extensions/rtdb-uppercase-messages.env.

Vẫn còn một số phần mở rộng còn lại của tiện ích greet-the-world trong mã tiện ích của bạn, nhưng hãy tạm thời giữ lại chúng. Bạn sẽ cập nhật các bản ghi đó trong vài phút tới .

4. Viết một hàm đám mây và khai báo hàm đó là tài nguyên tiện ích

Bây giờ, bạn có thể bắt đầu viết một số mã. Ở bước này, bạn sẽ viết một Cloud Hàm thực hiện nhiệm vụ cốt lõi của tiện ích, tức là để xem Cơ sở dữ liệu theo thời gian thực cho tin nhắn và chuyển đổi chúng thành kiểu viết hoa.

  1. Mở nguồn cho các hàm của tiện ích (trong functions) trong trình chỉnh sửa hoặc IDE mà bạn chọn. Thay thế có chứa những thông tin sau:

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

    Hàm cũ mà bạn đã thay thế là hàm được kích hoạt HTTP. Hàm này khi được truy cập vào một điểm cuối HTTP. Hàm mới được kích hoạt bởi sự kiện trong cơ sở dữ liệu theo thời gian thực: Search Ads 360 theo dõi các mặt hàng mới tại một đường dẫn cụ thể và khi phát hiện một giá trị, phương thức này sẽ ghi phiên bản viết hoa của giá trị trở lại vào cơ sở dữ liệu.

    Nhân tiện, tệp mới này sử dụng cú pháp mô-đun ECMAScript (importexport) thay vì CommonJS (require). Để sử dụng các mô-đun ES trong Nút, chỉ định "type": "module" trong functions/package.json:

    {
      "name": "rtdb-uppercase-messages",
      "main": "index.js",
      "type": "module",
      …
    }
    
  2. Bạn phải khai báo mọi hàm trong tiện ích trong extension.yaml . Tiện ích mẫu đã khai báo greetTheWorld là tiện ích duy nhất Chức năng đám mây; giờ đây, bạn đã thay thế nó bằng makeuppercase, bạn cũng cần cập nhật nội dung khai báo.

    Mở extension.yaml và thêm trường 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. Vì tiện ích của bạn đang sử dụng Cơ sở dữ liệu theo thời gian thực làm điều kiện kích hoạt, nên bạn cần cập nhật cấu hình trình mô phỏng để chạy trình mô phỏng RTDB cùng với Trình mô phỏng Cloud Functions:

    1. Nếu trình mô phỏng vẫn đang chạy, hãy dừng trình mô phỏng bằng cách nhấn Ctrl-C.

    2. Từ thư mục functions/integration-tests, hãy chạy lệnh sau :

      firebase init emulators
      

      Khi được hỏi, hãy bỏ qua bước thiết lập dự án mặc định, sau đó chọn Functions và Trình mô phỏng cơ sở dữ liệu. Chấp nhận các cổng mặc định và cho phép thiết lập để tải xuống mọi tệp cần thiết.

    3. Khởi động lại trình mô phỏng:

      firebase emulators:start --project=demo-test
      
  4. Dùng thử tiện ích đã cập nhật của bạn:

    1. Mở giao diện người dùng của trình mô phỏng cơ sở dữ liệu bằng cách sử dụng đường liên kết mà trình mô phỏng được in khi bạn bắt đầu chiến dịch.

    2. Chỉnh sửa nút gốc của cơ sở dữ liệu:

      • Trường: messages
      • Loại: json
      • Giá trị: {"11": {"original": "recipe"}}

      Nếu mọi thứ được thiết lập chính xác, khi bạn lưu các thay đổi đối với cơ sở dữ liệu của mình, hàm makeuppercase của tiện ích sẽ kích hoạt và thêm một phần tử con ghi vào tin nhắn 11 với nội dung "upper": "RECIPE". Xem qua tại các thẻ nhật ký và thẻ cơ sở dữ liệu trên giao diện người dùng trình mô phỏng để xác nhận các kết quả mong đợi.

    3. Hãy thử thêm một số phần tử con khác vào nút messages ({"original":"any text"}). Bất cứ khi nào bạn thêm một bản ghi mới, phải thêm trường uppercase có chứa chữ hoa nội dung của trường original.

Giờ đây, bạn đã có tiện ích hoàn chỉnh, tuy đơn giản, hoạt động trên RTDB thực thể. Trong các phần tiếp theo, bạn sẽ tinh chỉnh phần mở rộng này bằng một số các tính năng bổ sung. Sau đó, bạn sẽ chuẩn bị sẵn tiện ích để phân phối đến người dùng khác và cuối cùng là tìm hiểu cách xuất bản tiện ích của bạn trên Trung tâm tiện ích.

5. Khai báo API và vai trò

Firebase cấp cho mỗi bản sao của tiện ích đã cài đặt quyền truy cập có giới hạn vào dự án và dữ liệu của dự án đó thông qua một tài khoản dịch vụ cho mỗi phiên bản. Mỗi tài khoản có tập hợp quyền tối thiểu cần thiết để hoạt động. Vì lý do này, bạn phải khai báo rõ ràng mọi vai trò IAM mà tiện ích của bạn yêu cầu; khi người dùng cài đặt tiện ích của bạn, Firebase sẽ tạo một tài khoản dịch vụ với các vai trò đã được cấp và sẽ sử dụng nó để chạy tiện ích.

Bạn không cần khai báo vai trò để kích hoạt các sự kiện của một sản phẩm, nhưng bạn có thể cần khai báo vai trò để tương tác với vai trò đó. Vì chức năng mà bạn thêm ở bước cuối cùng ghi vào Cơ sở dữ liệu theo thời gian thực, thì bạn cần thêm khai báo sau cho extension.yaml:

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

Tương tự, bạn khai báo các API của Google mà một tiện ích sử dụng trong apis . Khi cài đặt tiện ích của bạn, người dùng sẽ được hỏi xem có muốn cài đặt tiện ích đó không để tự động bật các API này cho dự án của họ. Thông thường, cần thiết đối với các API của Google không phải của Firebase và không cần thiết trong hướng dẫn này.

6. Xác định các thông số mà người dùng có thể định cấu hình

Hàm bạn tạo trong 2 bước cuối đã xem một vị trí RTDB cụ thể cho các tin nhắn đến. Đôi khi, xem một vị trí cụ thể thực sự là điều bạn muốn, chẳng hạn như khi tiện ích của bạn hoạt động trên một cấu trúc cơ sở dữ liệu mà bạn sử dụng riêng cho tiện ích của bạn. Tuy nhiên, trong hầu hết trường hợp, bạn sẽ muốn làm cho những người dùng cài đặt tiện ích của bạn trong ứng dụng dự án. Bằng cách này, người dùng có thể sử dụng tiện ích của bạn để làm việc với cách thiết lập cơ sở dữ liệu hiện có.

Làm cho đường dẫn mà tiện ích theo dõi đối với các tin nhắn mới ở chế độ có thể định cấu hình cho người dùng:

  1. Trong tệp extension.yaml, hãy thêm một phần 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
    

    Thao tác này xác định một tham số chuỗi mới mà người dùng sẽ được nhắc đặt khi họ cài đặt tiện ích của bạn.

  2. Vẫn trong tệp extension.yaml, hãy quay lại makeuppercase của bạn khai báo và thay đổi trường resource thành như sau:

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

    Mã thông báo ${param:MESSAGE_PATH} là mã tham chiếu đến thông số bạn vừa xác định. Khi tiện ích của bạn chạy, mã thông báo này sẽ được thay thế bằng bất kỳ giá trị nào giá trị mà người dùng đã định cấu hình cho thông số đó, với kết quả là Hàm makeuppercase sẽ theo dõi đường dẫn mà người dùng đã chỉ định. Bạn có thể hãy sử dụng cú pháp này để tham chiếu bất kỳ tham số nào do người dùng xác định ở bất kỳ đâu trong extension.yaml (và trong POSTINSTALL.md — chúng ta sẽ tìm hiểu thêm về nội dung này ở phần sau).

  3. Bạn cũng có thể truy cập vào các tham số do người dùng xác định từ mã hàm.

    Trong hàm bạn đã viết ở phần trước, bạn đã mã hoá cứng đường dẫn đến chú ý theo dõi những thay đổi. Thay đổi định nghĩa của điều kiện kích hoạt để tham chiếu đến giá trị do người dùng xác định thay thế:

    functions/index.js

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

    Xin lưu ý rằng trong Tiện ích Firebase, thay đổi này chỉ nhằm mục đích tài liệu: khi triển khai một Chức năng đám mây dưới dạng một phần của tiện ích, sử dụng định nghĩa điều kiện kích hoạt từ tệp extension.yaml và bỏ qua được chỉ định trong định nghĩa hàm. Tuy nhiên, bạn nên vào tài liệu trong mã của bạn nơi bắt nguồn giá trị này.

  4. Bạn có thể không hài lòng khi thay đổi mã mà không có thời gian chạy nhưng bài học quan trọng cần rút ra là bạn có thể truy cập vào bất kỳ tham số do người dùng xác định trong mã hàm của bạn và sử dụng tham số đó làm giá trị thông thường trong logic của hàm. Để làm quen với tính năng này, hãy thêm nhật ký sau để chứng minh rằng bạn đang thực sự truy cập vào giá trị mà do người dùng xác định:

    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. Thông thường, người dùng được nhắc cung cấp giá trị cho các thông số khi họ cài đặt một tiện ích. Khi bạn dùng trình mô phỏng để kiểm thử và phát triển, tuy nhiên, bạn bỏ qua quá trình cài đặt, vì vậy thay vào đó bạn cung cấp các giá trị cho các tham số do người dùng xác định bằng cách sử dụng tệp env.

    Mở ứng dụng functions/integration-tests/extensions/rtdb-uppercase-messages.env và thay thế định nghĩa GREETING bằng:

    MESSAGE_PATH=/msgs/{pushId}/original
    

    Lưu ý rằng đường dẫn ở trên khác với đường dẫn mặc định và với đường dẫn đường dẫn mà bạn đã xác định trước đó; đây chỉ là để chứng minh với chính bạn khi bạn thử tiện ích được cập nhật mà định nghĩa của bạn sẽ có hiệu lực.

  6. Bây giờ, hãy khởi động lại trình mô phỏng và một lần nữa truy cập vào giao diện người dùng của trình mô phỏng cơ sở dữ liệu.

    Chỉnh sửa nút gốc của cơ sở dữ liệu, sử dụng đường dẫn mà bạn đã xác định ở trên:

    • Trường: msgs
    • Loại: json
    • Giá trị: {"11": {"original": "recipe"}}

    Khi bạn lưu các thay đổi đối với cơ sở dữ liệu, makeuppercase của tiện ích hàm sẽ kích hoạt như trước đây, nhưng giờ đây hàm này cũng in tham số do người dùng xác định vào nhật ký bảng điều khiển.

7. Cung cấp hook sự kiện cho logic do người dùng xác định

Với tư cách là tác giả tiện ích, bạn đã biết cách sản phẩm Firebase có thể kích hoạt logic do tiện ích cung cấp: tạo bản ghi mới trong Cơ sở dữ liệu theo thời gian thực kích hoạt hàm makeuppercase của bạn. Tiện ích của bạn có thể có một truy vấn tương tự mối quan hệ với người dùng cài đặt tiện ích của bạn: tiện ích của bạn có thể logic kích hoạt mà người dùng xác định.

Mỗi tiện ích có thể cung cấp hook đồng bộ, hook không đồng bộ hoặc cả hai. Hook đồng bộ giúp người dùng thực hiện các thao tác chặn việc hoàn tất một trong các hàm của tiện ích. Ví dụ: điều này có thể hữu ích để cung cấp cho người dùng một cách để thực hiện xử lý trước tùy chỉnh trước khi tiện ích thực hiện công việc.

Trong hướng dẫn này, bạn sẽ thêm một hook không đồng bộ vào tiện ích của mình. Thao tác này sẽ cho phép người dùng xác định các bước xử lý của riêng họ để chạy sau tiện ích của bạn ghi thông báo viết hoa vào Cơ sở dữ liệu theo thời gian thực. Hook không đồng bộ sử dụng Eventarc để kích hoạt hàm do người dùng xác định. Tiện ích khai báo loại sự kiện mà chúng phát đi và khi người dùng cài đặt tiện ích, họ chọn loại sự kiện mà họ muốn quan tâm. Nếu họ chọn ít nhất một sự kiện, Firebase sẽ cung cấp một Kênh Eventarc cho tiện ích trong quá trình cài đặt. Số người dùng khi đó có thể triển khai các chức năng đám mây của riêng họ để nghe trên kênh đó và kích hoạt khi tiện ích xuất bản các sự kiện mới.

Hãy làm theo các bước sau để thêm một hook không đồng bộ:

  1. Trong tệp extension.yaml, hãy thêm phần sau đây để khai báo một loại sự kiện mà tiện ích phát ra:

    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.
    

    Loại sự kiện phải là duy nhất trên toàn cầu; để đảm bảo tính duy nhất, hãy luôn đặt tên các sự kiện bằng cách sử dụng định dạng sau: <publisher-id>.<extension-id>.<version>.<description>. (Bạn không có chưa có mã nhà xuất bản, nên bây giờ chỉ cần sử dụng test-publisher.)

  2. Ở cuối hàm makeuppercase, thêm một số mã phát hành một loại sự kiện bạn vừa khai báo:

    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,
        },
      });
    

    Mã ví dụ này tận dụng thực tế là EVENTARC_CHANNEL biến môi trường chỉ được xác định khi người dùng bật ít nhất một biến loại sự kiện. nếu không xác định EVENTARC_CHANNEL, mã này sẽ không cố gắng để xuất bản bất kỳ sự kiện nào.

    Bạn có thể đính kèm thông tin bổ sung vào sự kiện Eventarc. Trong ví dụ trên, sự kiện này có trường subject chứa tham chiếu đến giá trị mới được tạo và tải trọng data chứa giá trị gốc và tin nhắn hoa. Các hàm do người dùng xác định kích hoạt ngoài sự kiện có thể tận dụng thông tin này.

  3. Thông thường, môi trường EVENTARC_CHANNELEXT_SELECTED_EVENTS các biến được xác định dựa trên các tuỳ chọn mà người dùng đã chọn trong thời gian đó cài đặt. Để kiểm thử bằng trình mô phỏng, hãy xác định các biến này theo cách thủ công trong tệp rtdb-uppercase-messages.env:

    EVENTARC_CHANNEL=locations/us-central1/channels/firebase
    EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
    

Đến đây, bạn đã hoàn tất các bước cần thiết để thêm sự kiện không đồng bộ gắn kết với tiện ích của bạn.

Để dùng thử tính năng mới mà bạn vừa triển khai, trong vài bước tiếp theo các bước, giả định vai trò của người dùng đang cài đặt tiện ích:

  1. Từ thư mục functions/integration-tests, hãy khởi chạy một Firebase mới dự án:

    firebase init functions
    

    Khi được nhắc, hãy từ chối thiết lập dự án mặc định, chọn JavaScript làm Ngôn ngữ của Cloud Functions và cài đặt các phần phụ thuộc bắt buộc. Chiến dịch này dự án đại diện cho dự án của người dùng đã cài đặt tiện ích của bạn.

  2. Chỉnh sửa integration-tests/functions/index.js và dán mã sau:

    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}!!!`);
      }
    );
    

    Đây là ví dụ về hàm xử lý hậu kỳ mà người dùng có thể viết. Trong phần này trường hợp, hàm này sẽ theo dõi tiện ích để xuất bản một sự kiện complete, và khi được kích hoạt, thêm ba dấu chấm than vào chữ hoa mới viết hoa .

  3. Khởi động lại trình mô phỏng. Trình mô phỏng sẽ tải các chức năng của tiện ích dưới dạng cũng như chức năng xử lý hậu kỳ, "người dùng" xác định.

  4. Truy cập giao diện người dùng của trình mô phỏng cơ sở dữ liệu và chỉnh sửa nút gốc của cơ sở dữ liệu bằng cách sử dụng đường dẫn mà bạn đã xác định ở trên:

    • Trường:msgs
    • Loại: json
    • Giá trị: {"11": {"original": "recipe"}}

    Khi bạn lưu các thay đổi đối với cơ sở dữ liệu, makeuppercase của tiện ích và hàm extraemphasis của người dùng phải kích hoạt theo trình tự, dẫn đến trường upper nhận được giá trị RECIPE!!!.

8. Thêm trình xử lý sự kiện trong vòng đời

Tiện ích mà bạn đã viết cho đến nay sẽ xử lý thư khi chúng được tạo. Nhưng nếu người dùng đã có một cơ sở dữ liệu gồm các thông báo thì sao khi họ cài đặt không? Tiện ích của Firebase có một tính năng được gọi là mối gắn kết sự kiện trong vòng đời bạn có thể sử dụng để kích hoạt các hành động khi tiện ích của bạn được cài đặt, cập nhật hoặc đã định cấu hình lại. Trong phần này, bạn sẽ sử dụng các hook sự kiện trong vòng đời để thay thế một cơ sở dữ liệu thông báo hiện có của dự án với các thông báo được viết hoa khi người dùng cài đặt tiện ích của bạn.

Tiện ích Firebase sử dụng Cloud Tasks để chạy các trình xử lý sự kiện trong vòng đời của bạn. Bạn xác định trình xử lý sự kiện bằng Chức năng đám mây; bất cứ khi nào một phiên bản của tiện ích tiếp cận một trong các sự kiện vòng đời được hỗ trợ, nếu bạn đã xác định trình xử lý riêng, nó sẽ thêm trình xử lý vào hàng đợi Cloud Tasks. Sau đó, Cloud Tasks sẽ thực thi không đồng bộ trình xử lý. Khi một trình xử lý sự kiện trong vòng đời đang chạy, bảng điều khiển của Firebase sẽ báo cáo cho người dùng rằng phiên bản tiện ích có đang thực hiện tác vụ xử lý. Chức năng xử lý của bạn phụ thuộc vào việc báo cáo tình trạng trạng thái và hoàn thành tác vụ cho người dùng.

Để thêm một trình xử lý sự kiện trong vòng đời nhằm bổ sung các tin nhắn hiện có, hãy làm như sau sau:

  1. Xác định một Hàm đám mây mới được kích hoạt bởi các sự kiện trong hàng đợi tác vụ:

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

    Lưu ý rằng hàm chỉ xử lý một vài bản ghi trước khi thêm chính nó quay lại hàng đợi tác vụ. Đây là một chiến lược thường được dùng để đối phó với xử lý các tác vụ không thể hoàn thành trong khung thời gian chờ của Đám mây Hàm. Vì bạn không thể dự đoán số lượng thư mà người dùng có thể đã có trong cơ sở dữ liệu của họ khi họ cài đặt tiện ích của bạn, chiến lược này là phù hợp.

  2. Trong tệp extension.yaml, hãy khai báo hàm chèn lấp dưới dạng một phần mở rộng tài nguyên có thuộc tính taskQueueTrigger:

    resources:
      - name: makeuppercase
        ...
      - name: backfilldata
        type: firebaseextensions.v1beta.function
        description: >-
          Backfill existing messages with uppercase versions
        properties:
          runtime: "nodejs18"
          taskQueueTrigger: {}
    

    Sau đó, hãy khai báo hàm này làm trình xử lý cho vòng đời onInstall sự kiện:

    lifecycleEvents:
      onInstall:
        function: backfilldata
        processingMessage: Uppercasing existing messages
    
  3. Mặc dù việc chèn tin nhắn hiện có thì rất hữu ích, nhưng tiện ích này có thể vẫn hoạt động nếu không có mã. Trong các trường hợp như thế này, bạn nên chạy trình xử lý sự kiện vòng đời (không bắt buộc).

    Để làm như vậy, hãy thêm một tham số mới vào 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
    

    Sau đó, ở đầu hàm chèn lấp, kiểm tra giá trị của tham số DO_BACKFILL và thoát sớm nếu bạn chưa đặt tham số này:

    functions/index.js

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

Với những thay đổi nêu trên, giờ đây, tiện ích sẽ chuyển đổi các tin nhắn hiện có thành chữ hoa khi được cài đặt.

Cho đến thời điểm này, bạn đã sử dụng trình mô phỏng tiện ích để phát triển tiện ích và kiểm thử các thay đổi đang diễn ra. Tuy nhiên, trình mô phỏng tiện ích bỏ qua việc cài đặt Do đó, để kiểm thử trình xử lý sự kiện onInstall, bạn cần cài đặt trong một dự án thực tế. Đó cũng là như vậy, vì với việc thêm của tính năng chèn lấp tự động này, tiện ích hướng dẫn hiện đã hoàn tất mã!

9. Triển khai vào dự án Firebase thực tế

Mặc dù trình mô phỏng tiện ích là một công cụ tuyệt vời giúp lặp lại nhanh trên một trong quá trình phát triển, tại một thời điểm nào đó, bạn sẽ muốn dùng thử dự án.

Để làm như vậy, trước tiên hãy thiết lập dự án mới có bật một số dịch vụ:

  1. Trong bảng điều khiển của Firebase, hãy thêm một dự án.
  2. Nâng cấp dự án cho gói linh hoạt trả tiền theo mức dùng. Cloud Functions dành cho Firebase yêu cầu bạn dự án có tài khoản thanh toán, nên bạn cũng cần có tài khoản thanh toán cài đặt một tiện ích.
  3. Trong dự án mới, hãy bật Cơ sở dữ liệu theo thời gian thực.
  4. Vì bạn muốn kiểm tra khả năng bổ sung dữ liệu hiện có của tiện ích vào hãy nhập một số dữ liệu mẫu vào thực thể cơ sở dữ liệu theo thời gian thực:
    1. Tải một số dữ liệu RTDB gốc xuống.
    2. Trên trang Cơ sở dữ liệu theo thời gian thực trong bảng điều khiển của Firebase, hãy nhấp vào (khác) > Nhập JSON rồi chọn tệp bạn vừa tải xuống.
  5. Để bật hàm chèn lấp nhằm sử dụng phương thức orderByChild, hãy định cấu hình cơ sở dữ liệu để lập chỉ mục thông báo dựa trên giá trị của upper:

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

Bây giờ, hãy cài đặt tiện ích của bạn từ nguồn cục bộ vào dự án mới:

  1. Tạo một thư mục mới cho dự án Firebase của bạn:

    mkdir ~/extensions-live-test && cd ~/extensions-live-test
    
  2. Khởi chạy dự án Firebase trong thư mục đang hoạt động:

    firebase init database
    

    Khi được nhắc, hãy chọn dự án mà bạn vừa tạo.

  3. Cài đặt tiện ích này vào dự án Firebase cục bộ của bạn:

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

    Tại đây, bạn có thể thấy trải nghiệm người dùng như thế nào khi cài đặt bằng công cụ Firebase CLI. Hãy nhớ chọn "có" khi công cụ cấu hình hỏi xem bạn có muốn bổ sung cơ sở dữ liệu hiện có không.

    Sau khi bạn chọn các lựa chọn cấu hình, Firebase CLI sẽ lưu cấu hình trong thư mục extensions và ghi lại nguồn tiện ích vị trí trong tệp firebase.json. Hai bản ghi này được gọi chung là có tên là tệp kê khai tiện ích. Người dùng có thể sử dụng tệp kê khai để lưu định cấu hình tiện ích mở rộng và triển khai tiện ích đó cho các dự án khác nhau.

  4. Triển khai cấu hình tiện ích cho dự án đang hoạt động:

    firebase deploy --only extensions
    

Nếu mọi việc đều suôn sẻ, giao diện dòng lệnh (CLI) của Firebase sẽ tải phần mở rộng lên dự án của bạn và cài đặt ứng dụng đó. Sau khi cài đặt xong, tác vụ chèn lấp sẽ chạy và trong trong vài phút, cơ sở dữ liệu của bạn sẽ được cập nhật bằng các thông báo viết hoa. Thêm một vài các nút mới vào cơ sở dữ liệu thông báo và đảm bảo tiện ích cũng đang hoạt động cho tin nhắn mới.

10. Viết tài liệu

Trước khi chia sẻ tiện ích của mình với người dùng, hãy đảm bảo bạn cung cấp đủ tài liệu hướng dẫn để họ thành công.

Khi bạn khởi chạy dự án tiện ích, Firebase CLI đã tạo mã giả lập của các tài liệu tối thiểu bắt buộc. Cập nhật các tệp này thành chính xác phản ánh tiện ích bạn đã tạo.

tiện ích mở rộng.yaml

Bạn cập nhật tệp này vì bạn đã phát triển phần mở rộng này, do đó bạn không cần cập nhật gì thêm ngay bây giờ.

Tuy nhiên, đừng bỏ qua tầm quan trọng của các tài liệu trong đó . Ngoài thông tin nhận dạng quan trọng của tiện ích như tên, mô tả, tác giả, vị trí kho lưu trữ chính thức – extension.yaml chứa tài liệu dành cho người dùng cho mọi tài nguyên và người dùng có thể định cấu hình . Thông tin này sẽ hiển thị cho người dùng trong bảng điều khiển của Firebase, Trung tâm tiện ích và Firebase CLI.

PREINSTALL.md

Trong tệp này, hãy cung cấp thông tin người dùng cần trước khi họ cài đặt tiện ích: mô tả ngắn gọn chức năng của tiện ích, giải thích mọi điều kiện tiên quyết, đồng thời cung cấp cho người dùng thông tin về ảnh hưởng của việc thanh toán khi cài đặt tiện ích. Nếu bạn có trang web với thông tin bổ sung, đây cũng là nơi tốt để liên kết.

Nội dung của tệp này được hiển thị cho người dùng trong Trung tâm tiện ích và bởi Lệnh firebase ext:info.

Dưới đây là ví dụ về tệp 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

Tệp này chứa thông tin hữu ích cho người dùng sau khi họ đã thành công đã cài đặt tiện ích của bạn: ví dụ: các bước thiết lập tiếp theo, ví dụ về trong thực tế, v.v.

Nội dung của POSTINSTALL.md được hiển thị trong bảng điều khiển của Firebase sau tiện ích đã được định cấu hình và cài đặt. Bạn có thể tham khảo các thông số người dùng trong và chúng sẽ được thay thế bằng các giá trị được định cấu hình.

Dưới đây là tệp ví dụ sau khi cài đặt cho tiện ích hướng dẫn:

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

Hàm CHANGELOG.md

Bạn cũng nên ghi lại những thay đổi mà bạn thực hiện giữa các lần phát hành tiện ích trong tệp CHANGELOG.md.

Vì tiện ích mẫu chưa từng được xuất bản trước đó, nên nhật ký thay đổi chỉ một mục nhập:

## Version 0.0.1

Initial release of the _Convert messages to upper case_ extension.

Hàm README.md

Hầu hết tiện ích cũng cung cấp tệp readme để người dùng truy cập vào kho lưu trữ của tiện ích. bạn có thể tự viết tệp này hoặc tạo bằng lệnh.

Trong phạm vi của hướng dẫn này, hãy bỏ qua bước ghi tệp readme.

Tài liệu bổ sung

Tài liệu được thảo luận ở trên là bộ tài liệu tối thiểu bạn nên đem đến cho người dùng. Nhiều tiện ích yêu cầu tài liệu chi tiết hơn để người dùng sử dụng thành công chúng. Trong trường hợp này, bạn nên viết thêm và lưu trữ tài liệu đó ở nơi bạn có thể hướng người dùng đến.

Trong phạm vi của hướng dẫn này, hãy bỏ qua bước viết tài liệu bao quát hơn.

11. Xuất bản trên Trung tâm tiện ích

Tiện ích của bạn hiện đã hoàn tất mã và được ghi lại, bạn có thể chia sẻ ứng dụng với cả thế giới trên Trung tâm tiện ích. Tuy nhiên, vì đây chỉ là hướng dẫn, đừng thực sự làm điều đó. Bắt đầu viết tiện ích của riêng bạn bằng những gì bạn có đã tìm hiểu ở đây và trong phần còn lại của tài liệu dành cho nhà xuất bản Tiện ích Firebase, và bằng cách kiểm tra nguồn của các tiện ích chính thức, do Firebase viết.

Sau đây là cách thực hiện khi bạn đã sẵn sàng xuất bản tác phẩm của mình trên Trung tâm tiện ích nó:

  1. Nếu đang xuất bản tiện ích đầu tiên, đăng ký làm nhà xuất bản tiện ích. Thời gian bạn đăng ký làm nhà xuất bản tiện ích, hãy tạo mã nhà xuất bản cho phép người dùng nhanh chóng xác định bạn là tác giả của tiện ích.
  2. Lưu trữ mã nguồn của tiện ích ở một vị trí có thể xác minh công khai. Thời gian mã của bạn có sẵn từ một nguồn có thể xác minh, Firebase có thể xuất bản ngay từ vị trí này. Việc này giúp đảm bảo rằng bạn xuất bản phiên bản tiện ích được phát hành hiện tại và giúp người dùng bằng cách để họ kiểm tra mã họ đang cài đặt vào dự án của mình.

    Hiện tại, điều này có nghĩa là cung cấp tiện ích của bạn trong một GitHub công khai kho lưu trữ.

  3. Tải tiện ích của bạn lên Trung tâm tiện ích bằng cách sử dụng firebase ext:dev:upload .

  4. Chuyển đến trang tổng quan nhà xuất bản trong bảng điều khiển của Firebase, tìm tiện ích bạn vừa tải lên rồi nhấp vào "Xuất bản lên Trung tâm tiện ích". Thao tác này yêu cầu một đánh giá của nhân viên đánh giá. Quá trình này có thể mất vài ngày. Nếu được chấp thuận, tiện ích sẽ được xuất bản lên Trung tâm tiện ích. Nếu bị từ chối, bạn sẽ nhận được thông báo giải thích lý do; sau đó bạn có thể giải quyết các vấn đề được báo cáo và gửi lại để được xem xét.