בדף הזה מוסבר איך ליצור תוסף פשוט ל-Firebase, שאפשר להתקין בפרויקטים או לשתף עם אחרים. בדוגמה הפשוטה הזו של תוסף ל-Firebase, המערכת תבדוק את המסרים במסד הנתונים בזמן אמת ותמיר אותם לאותיות רישיות.
1. הגדרת הסביבה והפעלת פרויקט
לפני שמתחילים לפתח תוסף, צריך להגדיר סביבה לפיתוח עם הכלים הנדרשים.
מתקינים את Node.js בגרסה 16 ואילך. אחת מהדרכים להתקין את Node היא באמצעות nvm (או nvm-windows).
מתקינים או מעדכנים את הגרסה האחרונה של Firebase CLI. כדי להתקין או לעדכן באמצעות
npm
, מריצים את הפקודה הבאה:npm install -g firebase-tools
עכשיו משתמשים ב-CLI של Firebase כדי לאתחל פרויקט חדש של תוסף:
יוצרים ספרייה לתוסף ואז
cd
לתוכה:mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
מריצים את הפקודה
ext:dev:init
ב-CLI של Firebase:firebase ext:dev:init
כשתתבקשו, בחרו את JavaScript בתור השפה לפונקציות (אבל שימו לב שאפשר להשתמש ב-TypeScript גם כשמפתחים תוסף משלכם). כשתתבקשו להתקין יחסי תלות, ענו 'כן'. (מאשרים את ברירת המחדל של כל האפשרויות האחרות). הפקודה הזו תגדיר בסיס קוד בסיסי לתוסף חדש, שממנו תוכלו להתחיל לפתח את התוסף.
2. רוצה לנסות את התוסף לדוגמה באמצעות האמולטור?
כש-Firebase CLI הפעיל את ספריית התוספים החדשה, הוא יצר פונקציית דוגמה פשוטה וספרייה integration-tests
שמכילה את הקבצים הנדרשים להפעלת תוסף באמצעות חבילת המהדמנים של Firebase.
נסו להריץ את התוסף לדוגמה במהדורת האדמין:
עוברים לספרייה
integration-tests
:cd functions/integration-tests
מפעילים את האמולטור בפרויקט הדגמה:
firebase emulators:start --project=demo-test
הסימולטור טוען את התוסף לפרויקט 'דמה' מוגדר מראש (
demo-test
). התוסף מורכב עד כה מפונקציה אחת שמופעל על ידי HTTP, greetTheWorld
, שמחזירה את ההודעה 'hello world' כשנכנסים אליה.כשהמכונה הווירטואלית עדיין פועלת, אפשר לנסות את הפונקציה
greetTheWorld
של התוסף על ידי כניסה לכתובת ה-URL שהודפסה כשהפעלתם אותה.בדפדפן תוצג ההודעה 'Hello World from greet-the-world'.
קוד המקור של הפונקציה הזו נמצא בתיקייה
functions
של התוסף. פותחים את המקור בכלי העריכה או בסביבת הפיתוח המשולבת (IDE) שבחרתם:functions/index.js
const functions = require("firebase-functions/v1"); exports.greetTheWorld = functions.https.onRequest((req, res) => { // Here we reference a user-provided parameter // (its value is provided by the user during installation) const consumerProvidedGreeting = process.env.GREETING; // And here we reference an auto-populated parameter // (its value is provided by Firebase after installation) const instanceId = process.env.EXT_INSTANCE_ID; const greeting = `${consumerProvidedGreeting} World from ${instanceId}`; res.send(greeting); });
בזמן שהאמולטור פועל, הוא יטען מחדש באופן אוטומטי את כל השינויים שתבצעו בקוד של Functions. כדאי לנסות לבצע שינוי קטן בפונקציה
greetTheWorld
:functions/index.js
const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
שומרים את השינויים. הסימולטור יטען מחדש את הקוד, ועכשיו, כשנכנסים לכתובת ה-URL של הפונקציה, מופיעה ההודעה המעודכנת.
3. הוספת מידע בסיסי לקובץ extension.yaml
עכשיו, אחרי שהגדרתם את סביבת הפיתוח והפעלתם את אמולטור התוספים, תוכלו להתחיל לכתוב תוסף משלכם.
בשלב ראשון, עורכים את המטא-נתונים המוגדרים מראש של התוסף כך שישקפו את התוסף שרוצים לכתוב במקום greet-the-world
. המטא-נתונים האלה מאוחסנים בקובץ extension.yaml
.
פותחים את הקובץ
extension.yaml
בכלי העריכה ומחליפים את כל תוכן הקובץ בקוד הבא:name: rtdb-uppercase-messages version: 0.0.1 specVersion: v1beta # Firebase Extensions specification version; don't change # Friendly display name for your extension (~3-5 words) displayName: Convert messages to upper case # Brief description of the task your extension performs (~1 sentence) description: >- Converts messages in RTDB to upper case author: authorName: Your Name url: https://your-site.example.com license: Apache-2.0 # Required license # Public URL for the source code of your extension sourceUrl: https://github.com/your-name/your-repo
שימו לב למוסכמה למתן שמות בשדה
name
: לתוספים הרשמיים של Firebase, השם כולל קידומת שמציינת את מוצר Firebase הראשי שבו פועל התוסף, ואחריה תיאור של מה שהתוסף עושה. עליך להשתמש באותה מוסכמה בתוספים שלך.מאחר ששיניתם את שם התוסף, עליכם לעדכן גם את ההגדרות של המהדר בשם החדש:
- ב-
functions/integration-tests/firebase.json
, משנים אתgreet-the-world
ל-rtdb-uppercase-messages
. - משנים את השם של
functions/integration-tests/extensions/greet-the-world.env
ל-functions/integration-tests/extensions/rtdb-uppercase-messages.env
.
- ב-
עדיין יש כמה שרידים של התוסף greet-the-world
בקוד התוסף, אבל בשלב הזה אפשר להשאיר אותם. בשלבים הבאים נסביר איך מעדכנים את הפרטים האלה.
4. כתיבת פונקציה של Cloud Functions והצהרה עליה כמשאב תוסף
עכשיו אפשר להתחיל לכתוב קוד. בשלב הזה כתבו פונקציית Cloud Functions שתבצע את המשימה המרכזית של התוסף, כלומר לבדוק אם יש הודעות ב-Realtime Database ולהמיר אותן לאותיות רישיות.
פותחים את המקור של הפונקציות של התוסף (בתיקייה
functions
של התוסף) בכלי העריכה או בסביבת הפיתוח המשולבת (IDE) שבחרתם. מחליפים את התוכן שלו בדברים הבאים:functions/index.js
import { database, logger } from "firebase-functions/v1"; const app = initializeApp(); // Listens for new messages added to /messages/{pushId}/original and creates an // uppercase version of the message to /messages/{pushId}/uppercase // for all databases in 'us-central1' export const makeuppercase = database .ref("/messages/{pushId}/uppercase") .onCreate(async (snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); // Convert it to upper case. logger.log("Uppercasing", context.params.pushId, original); const uppercase = original.toUpperCase(); // Setting an "uppercase" sibling in the Realtime Database. const upperRef = snapshot.ref.parent.child("upper"); await upperRef.set(uppercase); });
הפונקציה הישנה, אותה החלפתם, הייתה פונקציה שמופעלת על ידי HTTP, שפועלת כשמתבצעת גישה לנקודת קצה (endpoint) של HTTP. הפונקציה החדשה מופעלת על ידי אירועים בזמן אמת במסד הנתונים: היא מחפשת פריטים חדשים בנתיב מסוים, וכשהיא מזהה פריט כזה היא כותבת את גרסת הערך באותיות רישיות בחזרה למסד הנתונים.
דרך אגב, בקובץ החדש הזה נעשה שימוש בסינטקס של מודול ECMAScript (
import
ו-export
) במקום ב-CommonJS (require
). כדי להשתמש במודולים של ES ב-Node, צריך לציין את"type": "module"
ב-functions/package.json
:{ "name": "rtdb-uppercase-messages", "main": "index.js", "type": "module", … }
כל פונקציה בתוסף צריכה להוצהר בקובץ
extension.yaml
. בתוסף לדוגמה צויןgreetTheWorld
כפונקציה של Cloud Functions היחידה. עכשיו, אחרי שהחלפתם אותו ב-makeuppercase
, צריך גם לעדכן את ההצהרה שלו.פותחים את
extension.yaml
ומוסיפים שדהresources
:resources: - name: makeuppercase type: firebaseextensions.v1beta.function properties: eventTrigger: eventType: providers/google.firebase.database/eventTypes/ref.create # DATABASE_INSTANCE (project's default instance) is an auto-populated # parameter value. You can also specify an instance. resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original runtime: "nodejs18"
מאחר שהתוסף משתמש עכשיו ב-Realtime Database כטריגר, צריך לעדכן את הגדרות הסימולטור כדי להריץ את הסימולטור של RTDB לצד הסימולטור של Cloud Functions:
אם הסימולטור עדיין פועל, לוחצים על Ctrl-C כדי להפסיק אותו.
מהספרייה
functions/integration-tests
, מריצים את הפקודה הבאה:firebase init emulators
כשמתבקשים, מדלגים על הגדרת פרויקט ברירת מחדל ובוחרים את המהדמנים של Functions ושל מסדי נתונים. מאשרים את יציאות ברירת המחדל ומאפשרים לכלי ההגדרה להוריד את כל הקבצים הנדרשים.
מפעילים מחדש את האמולטור:
firebase emulators:start --project=demo-test
בודקים את התוסף המעודכן:
פותחים את ממשק המשתמש של אמולטור מסדי הנתונים באמצעות הקישור שהאמולטור הדפיס כשהפעלתם אותו.
עורכים את צומת הבסיס של מסד הנתונים:
- שדה:
messages
- סוג:
json
- ערך:
{"11": {"original": "recipe"}}
אם הכול מוגדר כמו שצריך, כששומרים את השינויים במסד הנתונים, הפונקציה
makeuppercase
של התוסף אמורה לפעול ומוסיפה רשומת צאצא להודעה 11 עם התוכן"upper": "RECIPE"
. בודקים את היומנים ואת הכרטיסיות של מסדי הנתונים בממשק המשתמש של המהדר כדי לוודא שהתוצאות הן כצפוי.- שדה:
נסו להוסיף עוד כמה צאצאים לצומת
messages
({"original":"any text"}
). בכל פעם שמוסיפים רשומה חדשה, התוסף צריך להוסיף שדהuppercase
שמכיל את התוכן באותיות רישיות של השדהoriginal
.
עכשיו יש לכם תוסף מלא, אבל פשוט, שפועל במכונת RTDB. בקטעים הבאים נוסיף לתוסף הזה כמה תכונות נוספות. לאחר מכן, תלמדו איך להכין את התוסף להפצה לאחרים, ואז איך לפרסם אותו במרכז התוספים.
5. הצהרה על ממשקי API ותפקידים
מערכת Firebase מעניקה לכל מכונה של תוסף מותקן גישה מוגבלת לפרויקט ולנתונים שלו באמצעות חשבון שירות לכל מכונה. לכל חשבון יש את ההרשאות המינימליות הנדרשות כדי לפעול. לכן, עליכם להצהיר באופן מפורש על כל תפקידי ה-IAM הנדרשים לתוסף. כשמשתמשים מתקינים את התוסף, מערכת Firebase יוצרת חשבון שירות עם התפקידים האלה ומשתמשת בו כדי להפעיל את התוסף.
לא צריך להצהיר על תפקידים כדי להפעיל אירועים של מוצר, אבל צריך להצהיר על תפקיד כדי לנהל איתו אינטראקציה אחרת. מכיוון שהפונקציה שהוספתם בשלב האחרון כותבת ב-Realtime Database, צריך להוסיף את ההצהרה הבאה ל-extension.yaml
:
roles:
- role: firebasedatabase.admin
reason: Allows the extension to write to RTDB.
באופן דומה, מגדירים את ממשקי Google API שבהם התוסף משתמש בשדה apis
. כשמשתמשים מתקינים את התוסף, הם מתבקשים להפעיל את ממשקי ה-API האלה באופן אוטומטי בפרויקט שלהם. בדרך כלל, הדבר נדרש רק לממשקי Google API שאינם של Firebase, ולא נדרש במדריך הזה.
6. הגדרת פרמטרים שניתנים להגדרה על ידי משתמשים
הפונקציה שיצרתם בשני השלבים האחרונים פקדה על מיקום ספציפי ב-RTDB כדי לבדוק אם יש הודעות נכנסות. לפעמים, מעקב אחרי מיקום ספציפי הוא מה שאתם באמת רוצים, למשל כשהתוסף פועל על מבנה מסד נתונים שאתם משתמשים בו באופן בלעדי עבור התוסף. עם זאת, ברוב המקרים כדאי לאפשר למשתמשים שמתקינים את התוסף בפרויקטים שלהם לקבוע את הערכים האלה. כך המשתמשים יוכלו להשתמש בתוסף שלכם עם הגדרות מסד הנתונים הקיימות שלהם.
מאפשרים למשתמש להגדיר את הנתיב שבו התוסף מחפש הודעות חדשות:
בקובץ
extension.yaml
, מוסיפים את הקטעparams
:- param: MESSAGE_PATH label: Message path description: >- What is the path at which the original text of a message can be found? type: string default: /messages/{pushId}/original required: true immutable: false
בהגדרה הזו מוגדר פרמטר מחרוזת חדש שהמשתמשים יתבקשו להגדיר כשהם יתקינו את התוסף.
עדיין בקובץ
extension.yaml
, חוזרים להצהרהmakeuppercase
ומשנים את השדהresource
כך:resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
האסימון
${param:MESSAGE_PATH}
הוא הפניה לפרמטר שהגדרתם עכשיו. כשהתוסף יפעל, האסימון הזה יוחלף בערך שהמשתמש הגדיר לפרמטר הזה, וכתוצאה מכך הפונקציהmakeuppercase
תקשיב לנתיב שהמשתמש ציין. אפשר להשתמש בתחביר הזה כדי להפנות לכל פרמטר שהוגדר על ידי משתמש בכל מקום ב-extension.yaml
(וגם ב-POSTINSTALL.md
– נרחיב על כך בהמשך).אפשר לגשת לפרמטרים שהוגדרו על ידי המשתמש גם מקוד הפונקציות.
בפונקציה שכתבתם בקטע הקודם, קבעתם את הנתיב לבדיקה של השינויים באופן קבוע. משנים את הגדרת הטריגר כך שתתייחס לערך שהוגדר על ידי המשתמש:
functions/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
שימו לב שבתוספים ל-Firebase, השינוי הזה חל רק למטרות התיעוד: כשפונקציה של Cloud Functions פרוסה כחלק מתוסף, היא משתמשת בהגדרת הטריגר מהקובץ
extension.yaml
ומתעלמת מהערך שצוין בהגדרת הפונקציה. עם זאת, מומלץ לתעד בקוד את המקור של הערך הזה.אולי זה מאכזב לבצע שינוי בקוד שלא משפיע על זמן הריצה, אבל חשוב לזכור שאפשר לגשת לכל פרמטר שהוגדר על ידי המשתמש בקוד הפונקציה ולהשתמש בו כערך רגיל בלוגיקה של הפונקציה. כדי להדגים את היכולת הזו, מוסיפים את הצהרת היומן הבאה כדי להראות שאתם אכן ניגשים לערך שהמשתמש הגדיר:
functions/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate( async (snapshot, context) => { logger.log("Found new message at ", snapshot.ref); // Grab the current value of what was written to the Realtime Database. ...
בדרך כלל, המשתמשים מתבקשים לספק ערכים לפרמטרים כשהם מתקינים תוסף. עם זאת, כשמשתמשים במהדורת האדמולטור לצורכי בדיקה ופיתוח, מדלגים על תהליך ההתקנה, ולכן במקום זאת מספקים ערכים לפרמטרים מוגדרי-משתמש באמצעות קובץ
env
.פותחים את הקובץ
functions/integration-tests/extensions/rtdb-uppercase-messages.env
ומחליפים את ההגדרה שלGREETING
בהגדרה הבאה:MESSAGE_PATH=/msgs/{pushId}/original
שימו לב שהנתיב שלמעלה שונה מנתיב ברירת המחדל ומהנתיב שהגדרתם קודם. המטרה היא רק להוכיח לעצמכם כשאתם מנסים את התוסף המעודכן, שההגדרה שלכם נכנסה לתוקף.
עכשיו מפעילים מחדש את האמולטור ונכנסים שוב לממשק המשתמש של אמולטור מסדי הנתונים.
עורכים את צומת הרמה הבסיסית (root) של מסד הנתונים, באמצעות הנתיב שהגדרתם למעלה:
- שדה:
msgs
- סוג:
json
- ערך:
{"11": {"original": "recipe"}}
כששומרים את השינויים במסד הנתונים, הפונקציה
makeuppercase
של התוסף אמורה להופעל כמו קודם, אבל עכשיו היא אמורה גם להדפיס את הפרמטר שהוגדר על ידי המשתמש ביומן המסוף.- שדה:
7. הוספת אירועי הוק לצורך לוגיקה מוגדרת על ידי משתמש
ככותבי תוספים, כבר ראינו איך מוצר של Firebase יכול להפעיל את הלוגיקה שסיפקתם בתוסף: יצירת רשומות חדשות ב-Realtime Database מפעילה את הפונקציה makeuppercase
. לתוסף יכולה להיות מערכת יחסים דומה עם המשתמשים שמתקינים אותו: התוסף יכול להפעיל לוגיקה שהמשתמש מגדיר.
תוסף יכול לספק וו hooks סינכרוניים, וו hooks אסינכרוניים או את שניהם. באמצעות הוקס סינכרוניים, המשתמשים יכולים לבצע משימות שמונעות את השלמת אחת מהפונקציות של התוסף. אפשר להשתמש באפשרות הזו, למשל, כדי לתת למשתמשים דרך לבצע עיבוד מקדים בהתאמה אישית לפני שהתוסף יבצע את הפעולה שלו.
במדריך הזה תלמדו איך להוסיף ל-extension הוק אסינכרוני, שיאפשר למשתמשים להגדיר את שלבי העיבוד שלהם שיופעלו אחרי שה-extension יכתוב את ההודעה באותיות רישיות ל-Realtime Database. ב-hooks אסינכרונים נעשה שימוש ב-Eventarc כדי להפעיל פונקציות בהגדרת המשתמש. התוספים מכריזים על סוגי האירועים שהם משדרים, וכשהמשתמשים מתקינים את התוסף, הם בוחרים את סוגי האירועים שמעניינים אותם. אם הם יבחרו אירוע אחד לפחות, מערכת Firebase תקצה לערוץ Eventarc עבור התוסף כחלק מתהליך ההתקנה. לאחר מכן, המשתמשים יוכלו לפרוס פונקציות משלהם ב-Cloud שיאזינו בערוץ הזה ויופעלו כשהתוסף יפרסם אירועים חדשים.
כדי להוסיף הוק אסינכרוני:
בקובץ
extension.yaml
, מוסיפים את הקטע הבא, שמצהיר על סוג האירוע היחיד שהתוסף פולט:events: - type: test-publisher.rtdb-uppercase-messages.v1.complete description: >- Occurs when message uppercasing completes. The event subject will contain the RTDB URL of the uppercase message.
סוגי האירועים חייבים להיות ייחודיים באופן אוניברסלי. כדי להבטיח את הייחודיות, תמיד צריך לתת שמות לאירועים בפורמט הבא:
<publisher-id>.<extension-id>.<version>.<description>
. (עדיין אין לכם מזהה בעל תוכן דיגיטלי, לכן תוכלו להשתמש ב-test-publisher
בינתיים).בסוף הפונקציה
makeuppercase
, מוסיפים קוד שמפרסם אירוע מהסוג שהצהרתם עליו:functions/index.js
// Import the Eventarc library: import { initializeApp } from "firebase-admin/app"; import { getEventarc } from "firebase-admin/eventarc"; const app = initializeApp(); // In makeuppercase, after upperRef.set(uppercase), add: // Set eventChannel to a newly-initialized channel, or `undefined` if events // aren't enabled. const eventChannel = process.env.EVENTARC_CHANNEL && getEventarc().channel(process.env.EVENTARC_CHANNEL, { allowedEventTypes: process.env.EXT_SELECTED_EVENTS, }); // If events are enabled, publish a `complete` event to the configured // channel. eventChannel && eventChannel.publish({ type: "test-publisher.rtdb-uppercase-messages.v1.complete", subject: upperRef.toString(), data: { "original": original, "uppercase": uppercase, }, });
הקוד לדוגמה הזה מנצל את העובדה שמשתנה הסביבה
EVENTARC_CHANNEL
מוגדר רק כשהמשתמש מפעיל לפחות סוג אירוע אחד. אםEVENTARC_CHANNEL
לא מוגדר, הקוד לא מנסה לפרסם אירועים.אתם יכולים לצרף מידע נוסף לאירוע Eventarc. בדוגמה שלמעלה, לאירוע יש שדה
subject
שמכיל הפניה לערך שנוצר, ועומס נתונים (payload) מסוגdata
שמכיל את ההודעות המקוריות וההודעות באותיות רישיות. פונקציות מוגדרות על ידי המשתמש שמפעילות את האירוע יכולות להשתמש במידע הזה.בדרך כלל, משתני הסביבה
EVENTARC_CHANNEL
ו-EXT_SELECTED_EVENTS
מוגדרים על סמך האפשרויות שהמשתמש בחר במהלך ההתקנה. כדי לבדוק באמצעות הסימולטור, מגדירים את המשתנים האלה באופן ידני בקובץrtdb-uppercase-messages.env
:EVENTARC_CHANNEL=locations/us-central1/channels/firebase EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
בשלב הזה, סיימתם את השלבים הנדרשים להוספת הוק אירועים אסינכררוני לתוסף.
כדי לנסות את התכונה החדשה שהטמעתם, בשלבים הבאים תיכנסו לתפקיד של משתמש שמתקין את התוסף:
בתיקייה
functions/integration-tests
, מאתחלים פרויקט Firebase חדש:firebase init functions
כשמוצגת בקשה, מבטלים את ההגדרה של פרויקט ברירת מחדל, בוחרים ב-JavaScript כשפת Cloud Functions ומתקינים את יחסי התלות הנדרשים. הפרויקט הזה מייצג פרויקט של משתמש שבו התוסף שלכם מותקן.
עורכים את הקובץ
integration-tests/functions/index.js
ומדביקים את הקוד הבא:import { logger } from "firebase-functions/v1"; import { onCustomEventPublished } from "firebase-functions/v2/eventarc"; import { initializeApp } from "firebase-admin/app"; import { getDatabase } from "firebase-admin/database"; const app = initializeApp(); export const extraemphasis = onCustomEventPublished( "test-publisher.rtdb-uppercase-messages.v1.complete", async (event) => { logger.info("Received makeuppercase completed event", event); const refUrl = event.subject; const ref = getDatabase().refFromURL(refUrl); const upper = (await ref.get()).val(); return ref.set(`${upper}!!!`); } );
זו דוגמה לפונקציית עיבוד נתונים לאחר העיבוד שיכול להיות שמשתמש יכתוב. במקרה הזה, הפונקציה מקשיבה לפרסום אירוע
complete
על ידי התוסף, וכשהיא מופעלת, היא מוסיפה שלוש נקודות קריאה להודעה החדשה שהאותיות שלה הופכות לגדולות.מפעילים מחדש את הסימולטור. האמולטור יטען את הפונקציות של התוסף, וגם את הפונקציה לאחר עיבוד שה'משתמש' הגדיר.
נכנסים לממשק המשתמש של האמולטור של מסד הנתונים ועורכים את הצומת הבסיסי (root) של מסד הנתונים, באמצעות הנתיב שהגדרתם למעלה:
- שדה:
msgs
- סוג:
json
- ערך:
{"11": {"original": "recipe"}}
כששומרים את השינויים במסד הנתונים, הפונקציה
makeuppercase
של התוסף והפונקציהextraemphasis
של המשתמש אמורות לפעול ברצף, וכתוצאה מכך השדהupper
יקבל את הערךRECIPE!!!
.- שדה:
8. הוספת גורמים מטפלים באירועים במחזור החיים
התוסף שכתבתם עד עכשיו מעבד הודעות בזמן היצירה שלהן. אבל מה אם למשתמשים כבר יש מסד נתונים של הודעות כשהם מתקינים את התוסף? בתוספים של Firebase יש תכונה שנקראת הקאות לאירועים במחזור החיים, שאפשר להשתמש בה כדי להפעיל פעולות כשהתוסף מותקן, מתעדכן או מוגדר מחדש. בקטע הזה תלמדו איך להשתמש באירועי ה-lifecycle כדי למלא את מסד הנתונים הקיים של ההודעות בפרויקט בהודעות באותיות רישיות כשמשתמש מתקין את התוסף.
התוספים של Firebase משתמשים ב-Cloud Tasks כדי להריץ את פונקציות הטיפול באירועים במחזור החיים. מגדירים פונקציות טיפול באירועים באמצעות Cloud Functions. בכל פעם שמכונה של התוסף מגיעה לאחד מאירועי מחזור החיים הנתמכים, אם הגדרתם פונקציית טיפול באירועים, היא תוסיף את הפונקציה הזו לתור של Cloud Tasks. לאחר מכן, Cloud Tasks יבצע את הטיפול באופן אסינכרוני. בזמן שפועל טיפול באירוע של מחזור חיים, מסוף Firebase ידווח למשתמש שיש משימה עיבוד מתמשכת במכונה של התוסף. פונקציית הטיפול היא זו שצריכה לדווח למשתמש על הסטטוס המתמשך ועל השלמת המשימה.
כדי להוסיף טיפול באירועי מחזור חיים שממלאים הודעות קיימות, מבצעים את הפעולות הבאות:
מגדירים פונקציה חדשה של Cloud Functions שמופעלת על ידי אירועים בתור המשימות:
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 Function. מכיוון שאין לכם אפשרות לחזות כמה הודעות כבר יכולות להיות במסד הנתונים של משתמש כשהוא מתקין את התוסף, זוהי אסטרטגיה מתאימה.
בקובץ
extension.yaml
, מצהירים על פונקציית המילוי החוזר כמשאב תוסף עם המאפייןtaskQueueTrigger
:resources: - name: makeuppercase ... - name: backfilldata type: firebaseextensions.v1beta.function description: >- Backfill existing messages with uppercase versions properties: runtime: "nodejs18" taskQueueTrigger: {}
לאחר מכן מגדירים את הפונקציה כמתאם לאירועי מחזור החיים
onInstall
:lifecycleEvents: onInstall: function: backfilldata processingMessage: Uppercasing existing messages
אמנם נחמד שאפשר למלא את הנתונים החסרים של הודעות קיימות, אבל התוסף עדיין יכול לפעול בלי זה. במצבים כאלה, כדאי להגדיר את ההפעלה של הגורמים שמטפלים באירועים במחזור החיים כאופציונלית.
כדי לעשות זאת, מוסיפים פרמטר חדש ל-
extension.yaml
:- param: DO_BACKFILL label: Backfill existing messages description: >- Generate uppercase versions of existing messages? type: select required: true options: - label: Yes value: true - label: No value: false
לאחר מכן, בתחילת פונקציית המילוי החוזר, בודקים את הערך של הפרמטר
DO_BACKFILL
ויוצאים מוקדם אם הוא לא מוגדר:functions/index.js
if (!process.env.DO_BACKFILL) { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped."); }
בעקבות השינויים שלמעלה, התוסף יהפוך הודעות קיימות לאותיות רישיות אחרי ההתקנה.
עד עכשיו השתמשתם במהנתר התוספים כדי לפתח את התוסף ולבדוק את השינויים המתמשכים. עם זאת, אמולטור התוספים מדלג על תהליך ההתקנה, כך שצריך להתקין את התוסף בפרויקט אמיתי כדי לבדוק את פונקציית הטיפול באירוע onInstall
. לא פחות מכך, כשהוספנו את תכונת המילוי החוזר האוטומטית, תוסף המדריך הושלם באמצעות קוד!
9. פריסה בפרויקט Firebase אמיתי
למרות שמהדמטור של התוספים הוא כלי מצוין ליצירת גרסאות אב מהירות של תוסף במהלך הפיתוח, בשלב מסוים כדאי לנסות אותו בפרויקט אמיתי.
כדי לעשות זאת, קודם צריך להגדיר פרויקט חדש עם כמה שירותים מופעלים:
- מוסיפים פרויקט חדש במסוף Firebase.
- משדרגים את הפרויקט לתוכנית Blaze לתשלום לפי שימוש. כדי להשתמש ב-Cloud Functions for Firebase, נדרש חשבון לחיוב בפרויקט, ולכן נדרש חשבון לחיוב גם כדי להתקין תוסף.
- בפרויקט החדש, מפעילים את מסד הנתונים Real-time.
- כדי לבדוק את היכולת של התוסף למלא נתונים קיימים במהלך ההתקנה, צריך לייבא נתונים לדוגמה למכונה של מסד הנתונים בזמן אמת:
- הורד נתוני RTDB של זרועים.
- בדף Real-time Database במסוף Firebase, לוחצים על (עוד) > Import JSON ובוחרים את הקובץ שהורדתם.
כדי לאפשר לפונקציית המילוי לאחור להשתמש בשיטה
orderByChild
, צריך להגדיר את מסד הנתונים כך שיוסיף לאינדקס הודעות לפי הערך שלupper
:{ "rules": { ".read": false, ".write": false, "messages": { ".indexOn": "upper" } } }
עכשיו מתקינים את התוסף מהמקור המקומי בפרויקט החדש:
יוצרים ספרייה חדשה לפרויקט Firebase:
mkdir ~/extensions-live-test && cd ~/extensions-live-test
מפעילים את פרויקט Firebase בספריית העבודה:
firebase init database
כשתוצג הבקשה, בוחרים את הפרויקט שיצרתם.
מתקינים את התוסף בפרויקט Firebase המקומי:
firebase ext:install /path/to/rtdb-uppercase-messages
כאן אפשר לראות איך חוויית המשתמש נראית כשמתקינים תוסף באמצעות הכלי Firebase CLI. חשוב לבחור באפשרות 'כן' כשכלי ההגדרה שואל אם רוצים למלא את מסדי הנתונים הקיימים.
אחרי שבוחרים את אפשרויות ההגדרה, ה-CLI של Firebase ישמור את ההגדרות בתיקייה
extensions
ויתעדה את מיקום המקור של התוסף בקובץfirebase.json
. שתי הרשומות האלה נקראות יחד מניפסט התוספים. המשתמשים יכולים להשתמש במניפסט כדי לשמור את ההגדרות של התוספים ולפרוס אותן בפרויקטים שונים.פורסים את תצורת התוסף בפרויקט הפעיל:
firebase deploy --only extensions
אם הכל יתבצע כראוי, ה-CLI של Firebase אמור להעלות את התוסף לפרויקט ולהתקין אותו. בסיום ההתקנה, המשימה של מילוי החסר תפעל, ובתוך כמה דקות מסד הנתונים יתעדכן בהודעות באותיות רישיות. מוסיפים כמה צמתים חדשים למסד הנתונים של ההודעות ומוודאים שהתוסף פועל גם בהודעות חדשות.
10. כתיבת תיעוד
לפני שמשתפים את התוסף עם משתמשים, צריך לספק מספיק מסמכים כדי שהתוסף יצליח.
כשאתם מאתחלים את פרויקט התוסף, ה-CLI של Firebase יוצר גרסאות של stubs למסמכי העזרה הנדרשים. עדכנו את הקבצים האלה כך שישקפו במדויק את התוסף שיצרתם.
export.yaml
כבר עדכנת את הקובץ הזה מכיוון שפיתחת את התוסף הזה, כך שאין צורך לבצע עדכונים נוספים כרגע.
עם זאת, אל תזניחו את החשיבות של המסמכים שמופיעים בקובץ הזה. בנוסף לפרטים המזהים החיוניים של התוסף – שם, תיאור, מחבר, מיקום המאגר הרשמי – הקובץ extension.yaml
מכיל תיעוד גלוי למשתמשים לכל משאב ופרמטר שאפשר להגדיר על ידי המשתמש. המידע הזה מוצג למשתמשים במסוף Firebase, ב-Extensions Hub וב-Firebase CLI.
PREINSTALL.md
בקובץ הזה צריך לספק למשתמש את המידע שנחוץ לו לפני התקנת התוסף: לתאר בקצרה מה התוסף עושה, להסביר את הדרישות המוקדמות ולספק למשתמש מידע על ההשלכות על החיוב של התקנת התוסף. אם יש לכם אתר עם מידע נוסף, זהו גם מקום טוב לקשר אליו.
הטקסט של הקובץ הזה מוצג למשתמש ב-תוספים 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.
כשתהיו מוכנים לפרסם את העבודה שלכם במרכז התוספים, תוכלו לפעול לפי השלבים הבאים:
- אם אתם מפרסמים את התוסף הראשון שלכם, עליכם להירשם כמפרסמים של תוספים. כשאתם נרשמים כבעלים של תוספי Chrome, אתם יוצרים מזהה בעל תוכן דיגיטלי שמאפשר למשתמשים לזהות אתכם במהירות ככותבים של התוספים.
אירוח קוד המקור של התוסף במיקום שאפשר לאמת באופן ציבורי. כשהקוד זמין ממקור שאפשר לאמת, מערכת Firebase יכולה לפרסם את התוסף ישירות מהמיקום הזה. כך תוכלו לוודא שאתם מפרסמים את הגרסה הנוכחית של התוסף, ושהמשתמשים יוכלו לבדוק את הקוד שהם מתקינים בפרויקטים שלהם.
נכון לעכשיו, המשמעות היא שהתוסף צריך להיות זמין במאגר ציבורי ב-GitHub.
מעלים את התוסף ל-Extensions Hub באמצעות הפקודה
firebase ext:dev:upload
.עוברים למרכז הבקרה של בעלי האפליקציות במסוף Firebase, מחפשים את התוסף שהעליתם ולוחצים על 'פרסום ב-Extensions Hub'. הבקשה תישלח לבדיקה של צוות הבדיקה שלנו, והתהליך עשוי להימשך כמה ימים. אם הבקשה תאושר, התוסף יפורסם במרכז התוספים. אם הבקשה תידחה, תקבלו הודעה עם הסבר על הסיבה לדחייה. לאחר מכן תוכלו לטפל בבעיות שדווחו ולשלוח את הבקשה לבדיקה מחדש.