ארגון מספר פונקציות

כשמשלבים את Cloud Functions בפרויקט, הקוד יכול להתרחב ולהכיל הרבה פונקציות עצמאיות. יכול להיות שיש לכם יותר מדי פונקציות מכדי שיהיה הגיוני להכניס את כולן לקובץ אחד, או שצוותים שונים פורסים קבוצות שונות של פונקציות, מה שיוצר סיכון שצוות אחד יחליף או ימחק בטעות פונקציות של צוות אחר. ב-Cloud Functions יש כמה דרכים לארגן את הקוד כדי שיהיה קל יותר לנווט בפונקציות ולתחזק אותן.

ארגון פונקציות בבסיסי קוד

אתם יכולים להשתמש במאפיין codebase של אובייקט הגדרת הפונקציות ב-firebase.json כדי לנהל אוסף גדול של פונקציות בכמה מאגרים או חבילות משנה בתוך הגדרת מונוריפו של מאגר יחיד:

# firebase.json
"functions": {
  "codebase": "my-codebase"
  # NOTE: Codebase must be less than 63 characters and can contain only
  # lowercase letters, numeric characters, underscores, and dashes.
}

המאפיין codebase נתמך ב-Firebase CLI מגרסה 10.7.1 ואילך.

ניהול של כמה מאגרים

המאפיין codebase יכול לעזור לכם לנהל כמה מאגרים בקלות. נבחן מקרה שבו יש לכם שני מאגרים שונים שפורסים פונקציות לאותו פרויקט ב-Firebase:

$  tree .
├── repoA
│   ├── firebase.json
│   └── functions
│       ├── index.js
│       └── package.json
└── repoB
    ├── firebase.json
    └── functions
        ├── index.js
        └── package.json

בלי אנוטציות בבסיס הקוד, ה-Firebase CLI היה מבקש מכם למחוק פונקציות שמוגדרות במאגר השני בזמן הפריסה:

$ (cd repoA && firebase deploy --only functions)
...
i  functions: preparing functions directory for uploading...
✔  functions: functions folder uploaded successfully
The following functions are found in your project but do not exist in your local source code:
        fn1FromRepoB
        fn2FromRepoB
        ...
? Would you like to proceed with deletion? Selecting no will continue the rest of the deployments. (y/N)

כדי למנוע את הבעיה הזו, אפשר להוסיף הערה ייחודית של בסיס קוד בקטע של הגדרת הפונקציות בקובץ firebase.json בכל מאגר של פרויקט:

# repoA/firebase.json
"functions": {
  "codebase": "repo-a"
}

# repoB/firebase.json
"functions": {
  "codebase": "repo-b"
}

כשמשתמשים באנוטציות של בסיס הקוד, ה-Firebase CLI לא מבקש יותר למחוק פונקציות שמוגדרות מחוץ למאגר המיידי:

$ (cd repoA && firebase deploy --only functions)
...
i  functions: preparing functions directory for uploading...
✔  functions: functions folder uploaded successfully
#  Gleefully ignores functions from repoB
i  functions: creating Node.js 16 function fnFromRepoA (us-central1)...
✔  Deploy Complete!

ניהול של כמה חבילות מקור (מונוריפו)

המאפיין codebase יכול לעזור לכם לנהל בקלות כמה חבילות מקור במאגר אחד. נבחן מקרה שבו יש לכם ספריית פרויקט ב-Firebase עם הגדרות של פונקציות שפרוסות על פני כמה חבילות משנה:

$  tree .
├── firebase.json
├── teamA
│   ├── index.js
│   └── package.json
└── teamB
    ├── index.js
    └── package.json

ההגדרה הזו מתאימה לתרחישי השימוש הבאים:

  • יש לכם הגדרה של מונוריפו, וצוותים שונים מנהלים את הגדרות הפונקציות שלהם בחבילה מבודדת.
  • יש לכם פונקציה עם תלות חיצונית כבדה והפעלה ארוכה, ואתם רוצים לבודד את הפונקציה הזו מפונקציות אחרות שרגישות לזמן האחזור.

כדי לתמוך בהגדרה של monorepo כזו, מגדירים כמה פונקציות ב-firebase.json:

"functions": [
  {
    "source": "teamA",
    "codebase": "team-a"
  },
  {
    "source": "teamB",
    "codebase": "team-b"
  },
]

עם ההגדרה הזו, ה-Firebase CLI פורס פונקציות מכל החבילות בפקודת פריסה אחת:

$ firebase deploy --only functions
i  deploying functions
i  functions: preparing codebase team-a for deployment
i  functions: preparing codebase team-b for deployment
i  functions: creating Node.js 16 function team-a:helloATeam(us-central1)...
i  functions: creating Node.js 16 function team-b:helloBTeam(us-central1)...
...

אפשר גם לפרוס בסיס קוד ספציפי:

$ firebase deploy --only functions:team-b
i  deploying functions
i  functions: preparing codebase team-b for deployment
i  functions: updating Node.js 16 function team-b:helloBTeam(us-central1)...
...

כתיבת פונקציות בכמה קבצים

כשמתחילים לעבוד עם Cloud Functions, אפשר להוסיף את הפונקציות הראשונות לקובץ אחד:

index.js

const functions = require('firebase-functions/v1');
exports.foo = functions.https.onRequest((request, response) => {
  // ...
});
exports.bar = functions.https.onRequest((request, response) => {
  // ...
});

main.py

from firebase_functions import https_fn

@https_fn.on_request()
def foo(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

@https_fn.on_request()
def bar(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello bar!")

אם יש יותר מכמה פונקציות, יכול להיות שיהיה קשה לנהל את זה. במקום זאת, אפשר להכניס את כל הלוגיקה של כל פונקציה לקובץ משלה, ולהשתמש בקובץ המקור כרשימה של פונקציות לייצוא:

Node.js

foo.js

const functions = require('firebase-functions/v1');
exports.foo = functions.https.onRequest((request, response) => {
  // ...
});

bar.js

const functions = require('firebase-functions/v1');
exports.bar = functions.https.onRequest((request, response) => {
  // ...
});

index.js

const foo = require('./foo');
const bar = require('./bar');
exports.foo = foo.foo;
exports.bar = bar.bar;

Python

foo.py

from firebase_functions import https_fn

@https_fn.on_request()
def foo(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

bar.py

from firebase_functions import https_fn

@https_fn.on_request()
def bar(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello foo!")

main.py

from fn_impl.foo import *
from fn_impl.bar import *

בהגדרה הזו, מבנה הספרייה של הפרויקט נראה כך:

my-project
├── firebase.json
└── functions
    ├── fn_impl
    │   ├── __init__.py
    │   ├── foo.py
    │   └── bar.py
    ├── main.py
    └── requirements.txt

‫fn_impl: יכול להיות כל שם

‫__init__.py: חובה, אבל יכול להיות ריק

פונקציות קבוצתיות

בפרויקטים רבים, אפשר להפריד פונקציות לקבוצות לוגיות שצריך לפרוס ולתחזק ביחד. לדוגמה, יכול להיות שיש לכם קבוצה של פונקציות שמשמשות לדיווח על מדדים:

metrics.js


const functions = require('firebase-functions/v1');
exports.usageStats = functions.https.onRequest((request, response) => {
  // ...
});
exports.nightlyReport = functions.https.onRequest((request, response) => {
  // ...
});

אפשר לקבץ את הפונקציות האלה כשמייצאים אותן בקובץ index.js:

index.js


// Export both functions from metrics.js in the "metrics" group:
//  - metrics-usageStats
//  - metrics-nightlyReport
exports.metrics = require('./metrics');

כשפורסים פונקציות, השם של הקבוצה שלהן מתווסף בתחילת השם. בדוגמה הזו, הפונקציות ייקראו metrics-usageStats ו-metrics-nightlyReport.

כשפורסים פונקציות, אפשר להגביל את הפעולה לקבוצה אחת:


firebase deploy --only functions:metrics

השלבים הבאים

מידע נוסף על Cloud Functions זמין במאמרים הבאים: