שדרוג מ-API במרחב שמות לאפליקציה מודולרית

אם אתם משתמשים באפליקציות ב-Firebase web API עם מרחב שמות כלשהו, החל מגרסה 8 או גרסאות קודמות של compat הספריות ואילך, כדאי לעבור ל-API מודולרי באמצעות ההוראות במדריך הזה.

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

מומלץ מאוד להשתמש בכלי לאריזת מודולים בסביבת הפיתוח. אם לא משתמשים באחד מהם, לא ניתן ליהנות מהיתרונות העיקריים של ה-API המודולרי, כמו הקטנת גודל האפליקציה. כדי להתקין את ה-SDK, צריך npm או yarn.

השלבים לשדרוג במדריך הזה מבוססים על אפליקציית אינטרנט דמיונית שמשתמשת בערכות ה-SDK‏ Authentication ו-Cloud Firestore. בעזרת הדוגמאות תוכלו להבין את המושגים ואת השלבים המעשיים שנדרשים לשדרוג כל ערכות ה-SDK לאינטרנט של Firebase שנתמכות.

מידע על ספריות עם מרחב שמות (compat)

יש שני סוגים של ספריות שזמינות ל-Firebase web SDK:

  • מודולרי – ממשק API חדש שנועד להקל על הסרת קוד שלא נמצא בשימוש (tree-shaking) כדי להקטין את אפליקציית האינטרנט ולשפר את המהירות שלה.
  • Namespaced ‏ (compat) – ממשק API מוכר שתואם באופן מלא לגרסאות קודמות של ה-SDK, כך שאפשר לשדרג בלי לשנות את כל קוד Firebase בבת אחת. לספריות תאימות אין יתרונות משמעותיים בגודל או בביצועים בהשוואה למקבילות שלהן במרחב השמות.

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

באפליקציות עם חשיפה קטנה מאוד ל-Firebase web SDK – למשל, אפליקציה שמבצעת רק קריאה פשוטה ל-API של Authentication – יכול להיות שיהיה מעשי לבצע refactoring של קוד ישן עם מרחבי שמות בלי להשתמש בספריות התאימות. אם אתם משדרגים אפליקציה כזו, אתם יכולים לפעול לפי ההוראות במדריך הזה בנושא 'ה-API המודולרי' בלי להשתמש בספריות התאימות.

מידע על תהליך השדרוג

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

  1. מוסיפים את הספריות המודולריות ואת ספריות התאימות לאפליקציה.
  2. צריך לעדכן את הצהרות הייבוא בקוד ל-compat.
  3. לשכתב קוד של מוצר יחיד (לדוגמה, Authentication) בסגנון מודולרי.
  4. אופציונלי: בשלב הזה, כדי ליהנות מהיתרון של גודל האפליקציה עבור Authentication, כדאי להסיר את ספריית התאימות Authentication ואת קוד התאימות של Authentication לפני שממשיכים.
  5. משנים את המבנה של הפונקציות לכל מוצר (לדוגמה, Cloud Firestore,‏ FCM וכו') לסגנון מודולרי, מבצעים קומפילציה ובדיקה עד שכל האזורים מושלמים.
  6. עדכון קוד האתחול לסגנון מודולרי.
  7. מסירים את כל הצהרות התאימות שנותרו ואת קוד התאימות מהאפליקציה.

הורדת הגרסה האחרונה של ה-SDK

כדי להתחיל, מורידים את הספריות המודולריות ואת ספריות התאימות באמצעות npm:

npm i firebase@12.0.0

# OR

yarn add firebase@12.0.0

עדכון הייבוא כדי שיתאים לגרסה החדשה

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

לפני כן: גרסה 8 או גרסה מוקדמת יותר

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

אחרי: compat

// compat packages are API compatible with namespaced code
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

שינוי מבנה הקוד לסגנון מודולרי

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

ב-API המודולרי, השירותים מועברים כארגומנט הראשון, והפונקציה משתמשת בפרטי השירות כדי לבצע את שאר הפעולות. נבחן איך זה עובד בשתי דוגמאות שבהן מתבצע ארגון מחדש של קריאות לממשקי ה-API‏ Authentication ו-Cloud Firestore.

דוגמה 1: שינוי מבנה של פונקציית Authentication

לפני: compat

קוד התאימות זהה לקוד עם מרחב השמות, אבל שורות ה-imports השתנו.

import firebase from "firebase/compat/app";
import "firebase/compat/auth";

const auth = firebase.auth();
auth.onAuthStateChanged(user => { 
  // Check for user status
});

אחרי: מודולרי

הפונקציה getAuth מקבלת את firebaseApp כפרמטר הראשון שלה. הפונקציה onAuthStateChanged לא משורשרת ממופע auth כמו בממשק ה-API עם מרחב שמות, אלא היא פונקציה חופשית שמקבלת את auth כפרמטר הראשון שלה.

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
  // Check for user status
});

עדכון הטיפול בשיטת האימות getRedirectResult

ב-API המודולרי יש שינוי שעלול לשבור את התאימות לאחור ב-getRedirectResult. כשלא קוראים לפעולת הפניה אוטומטית, ה-API המודולרי מחזיר null, בניגוד ל-API עם מרחב שמות שמחזיר UserCredential עם משתמש null.

לפני: compat

const result = await auth.getRedirectResult()
if (result.user === null && result.credential === null) {
  return null;
}
return result;

אחרי: מודולרי

const result = await getRedirectResult(auth);
// Provider of the access token could be Facebook, Github, etc.
if (result === null || provider.credentialFromResult(result) === null) {
  return null;
}
return result;

דוגמה 2: שינוי מבנה של פונקציית Cloud Firestore

לפני: compat

import "firebase/compat/firestore"

const db = firebase.firestore();
db.collection("cities").where("capital", "==", true)
    .get()
    .then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch((error) => {
        console.log("Error getting documents: ", error);
    });

אחרי: מודולרי

הפונקציה getFirestore מקבלת את firebaseApp כפרמטר הראשון שלה, שהוחזר מ-initializeApp בדוגמה הקודמת. שימו לב שהקוד ליצירת שאילתה שונה מאוד ב-API המודולרי. אין שרשור, ושיטות כמו query או where נחשפות עכשיו כפונקציות חופשיות.

import { getFirestore, collection, query, where, getDocs } from "firebase/firestore";

const db = getFirestore(firebaseApp);

const q = query(collection(db, "cities"), where("capital", "==", true));

const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  // doc.data() is never undefined for query doc snapshots
  console.log(doc.id, " => ", doc.data());
});

עדכון ההפניות ל-Firestore DocumentSnapshot.exists

ב-API המודולרי יש שינוי שעלול לשבור את התאימות לאחור. במסגרת השינוי הזה, המאפיין firestore.DocumentSnapshot.exists הפך לשיטה. הפונקציונליות היא בעצם אותה פונקציונליות (בדיקה אם מסמך קיים), אבל צריך לשנות את הקוד כדי להשתמש בשיטה החדשה יותר, כמו שמוצג כאן:

לפני:compat

if (snapshot.exists) {
  console.log("the document exists");
}

אחרי: מודולרי

if (snapshot.exists()) {
  console.log("the document exists");
}

דוגמה 3: שילוב של סגנונות קוד ממרחב שמות וסגנונות קוד מודולריים

השימוש בספריות התאימות במהלך השדרוג מאפשר לכם להמשיך להשתמש בקוד עם מרחב שמות לצד קוד שעבר רפקטורינג ל-API מודולרי. המשמעות היא שאפשר לשמור על קוד קיים עם מרחב שמות ל-Cloud Firestore בזמן שמבצעים רפקטורינג ל-Authentication או לקוד אחר של Firebase SDK לסגנון מודולרי, ועדיין להדר את האפליקציה בהצלחה עם שני סגנונות הקוד. אותו הדבר נכון לגבי קוד API מודולרי עם מרחב שמות בתוך מוצר כמו Cloud Firestore. סגנונות קוד חדשים וישנים יכולים להתקיים יחד, כל עוד מייבאים את חבילות התאימות:

import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import { getDoc } from 'firebase/firestore'

const docRef = firebase.firestore().doc();
getDoc(docRef);

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

עדכון קוד האתחול

מעדכנים את קוד האתחול של האפליקציה כדי להשתמש בתחביר מודולרי. חשוב לעדכן את הקוד הזה אחרי שמסיימים את הארגון מחדש של כל הקוד באפליקציה, כי הפונקציה firebase.initializeApp() מאתחלת את המצב הגלובלי גם עבור ממשקי ה-API של התאימות וגם עבור ממשקי ה-API המודולריים, ואילו הפונקציה המודולרית initializeApp() מאתחלת רק את המצב המודולרי.

לפני: compat

import firebase from "firebase/compat/app"

firebase.initializeApp({ /* config */ });

אחרי: מודולרי

import { initializeApp } from "firebase/app"

const firebaseApp = initializeApp({ /* config */ });

הסרת קוד התאימות

כדי ליהנות מהיתרונות של ה-API המודולרי מבחינת גודל, בסופו של דבר צריך להמיר את כל הקריאות לסגנון המודולרי שמוצג למעלה ולהסיר את כל ההצהרות import "firebase/compat/* מהקוד. בסיום, לא אמורות להיות יותר הפניות לfirebase.* מרחב השמות הגלובלי או לקוד אחר בסגנון API עם מרחב שמות.

שימוש בספריית התאימות מהחלון

ה-API המודולרי מותאם לעבודה עם מודולים ולא עם אובייקט window של הדפדפן. בגרסאות קודמות של הספרייה אפשר היה לטעון את Firebase ולנהל אותה באמצעות מרחב השמות window.firebase. לא מומלץ להשתמש בשיטה הזו בעתיד כי היא לא מאפשרת להסיר קוד שלא נמצא בשימוש. עם זאת, גרסת התאימות של JavaScript SDK פועלת עם window למפתחים שלא מעדיפים להתחיל מיד בתהליך השדרוג המודולרי.

<script src="https://www.gstatic.com/firebasejs/12.0.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/12.0.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/12.0.0/firebase-auth-compat.js"></script>
<script>
   const firebaseApp = firebase.initializeApp({ /* Firebase config */ });
   const db = firebaseApp.firestore();
   const auth = firebaseApp.auth();
</script>

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

היתרונות והמגבלות של ה-SDK המודולרי

ל-SDK המודולרי לחלוטין יש יתרונות לעומת גרסאות קודמות:

  • ה-SDK המודולרי מאפשר להקטין באופן משמעותי את גודל האפליקציה. הוא מבוסס על פורמט מודול JavaScript מודרני, שמאפשר שימוש בטכניקות של 'הסרת ענפים' (tree shaking), שבהן מייבאים רק את הארטיפקטים שהאפליקציה צריכה. בהתאם לאפליקציה שלכם, שימוש ב-tree-shaking עם ה-SDK המודולרי יכול להקטין את גודל האפליקציה ב-80% בהשוואה לאפליקציה דומה שנבנתה באמצעות API עם מרחב שמות.
  • ערכת ה-SDK המודולרית תמשיך ליהנות מפיתוח תכונות שוטף, ואילו ה-API עם מרחב השמות לא ייהנה מכך.