כשתתחילו לשלב את Cloud Functions בפרויקט, הקוד שלכם יכול להתרחב כך שיכיל הרבה פונקציות עצמאיות. יכול להיות שיש לכם יותר מדי פונקציות מכדי שתוכלו להכניס אותן בקובץ אחד, או שצוותים שונים יכולים לפרוס קבוצות שונות של פונקציות, וכך להגדיל את הסיכון שצוות אחד יחליף או ימחק בטעות את הפונקציות של צוות אחר. ב-Cloud Functions יש כמה דרכים לארגן את הקוד כדי שיהיה קל יותר לנווט בפונקציות ולנהל אותן.
ארגון פונקציות בקוד
אפשר להשתמש במאפיין codebase
של אובייקט ההגדרות של הפונקציות ב-firebase.json
כדי לנהל אוסף גדול של פונקציות במספר מאגרים או חבילות משנה במסגרת הגדרה של מאגר יחיד (monorepo):
# 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
ללא הערות לגבי קוד המקור, ה-CLI של Firebase היה מבקש מכם למחוק את הפונקציות שהוגדרו במאגר השני בזמן הפריסה:
$ (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)
כדי למנוע את הבעיה הזו, אפשר להוסיף הערה ייחודית של Codebase בקטע של הגדרת הפונקציות ב-firebase.json
בכל מאגר של פרויקט:
# repoA/firebase.json
"functions": {
"codebase": "repo-a"
}
# repoB/firebase.json
"functions": {
"codebase": "repo-b"
}
באמצעות הערה של Codebase, ב-CLI של Firebase לא מופיעה יותר בקשה למחוק פונקציות שהוגדרו מחוץ למאגר המיידי:
$ (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!
ניהול של כמה חבילות מקור (monorepo)
המאפיין codebase
יכול לעזור לפשט את הניהול של מספר חבילות מקור במאגר יחיד. נבחן מקרה שבו יש ספרייה של פרויקט ב-Firebase עם הגדרות פונקציות שמפוזרות בכמה חבילות משנה:
$ tree .
├── firebase.json
├── teamA
│ ├── index.js
│ └── package.json
└── teamB
├── index.js
└── package.json
ההגדרה הזו מתאימה לתרחישי השימוש הבאים:
- יש לכם הגדרה של monorepo, וצוותים שונים מנהלים את הגדרות הפונקציות שלהם בחבילה מבודדת.
- יש לכם פונקציה עם תלות חיצונית כבדה והפעלה ראשונית ממושכת, ואתם רוצים לבודד את הפונקציה הזו מפונקציות אחרות שרגישות לזמן אחזור.
כדי לתמוך בהגדרה של monrepo כזו, צריך להגדיר כמה הגדרות של פונקציות ב-firebase.json
:
"functions": [
{
"source": "teamA",
"codebase": "team-a"
},
{
"source": "teamB",
"codebase": "team-b"
},
]
בהתאם להגדרה הזו, ה-CLI של Firebase פורס פונקציות מכל החבילות באמצעות פקודת פריסה אחת:
$ 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 זמין במאמרים הבאים: