שדרוג אפליקציית האינטרנט באמצעות מעבר ל-Firebase JS SDK המודולרי

1. לפני שמתחילים

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

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

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

מה תפַתחו

בקודלאב הזה נעביר בהדרגה אפליקציית אינטרנט קיימת של רשימת מעקב אחרי מניות שמשתמשת ב-JS SDK בגרסה 8 ל-JS SDK החדש והמודולרי, בשלושה שלבים:

  • שדרוג האפליקציה לשימוש בחבילות התאימות
  • שדרוג האפליקציה מחבילות התאימות ל-API המודולרי, חלק אחרי חלק
  • שימוש ב-Firestore Lite, הטמעה קלה של Firestore SDK, כדי לשפר עוד יותר את הביצועים של האפליקציה

2d351cb47b604ad7.png

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

מה צריך להכין

  • דפדפן לבחירתכם, כמו Chrome
  • סביבת הפיתוח המשולבת (IDE) או עורך הטקסט שבחרתם, כמו WebStorm,‏ Atom,‏ Sublime או VS Code
  • מנהל החבילות npm, שמגיע בדרך כלל עם Node.js
  • קוד לדוגמה ב-Codelab (כדי לקבל את הקוד, עיינו בשלב הבא ב-Codelab).

2. טיפים להגדרה

קבלת הקוד

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

משכפלים את מאגר GitHub של הקודלאב משורת הפקודה:

git clone https://github.com/FirebaseExtended/codelab-modular-sdk.git

לחלופין, אם לא התקנתם את git, תוכלו להוריד את המאגר כקובץ ZIP ולחלץ את קובץ ה-ZIP שהורדתם.

ייבוא האפליקציה

  1. פותחים או מייבאים את התיקייה codelab-modular-sdk באמצעות סביבת הפיתוח המשולבת.
  2. מריצים את npm install כדי להתקין את יחסי התלות הנדרשים לפיתוח גרסת build של האפליקציה ולהרצתה באופן מקומי.
  3. מריצים את הפקודה npm run build כדי ליצור את האפליקציה.
  4. מריצים את הפקודה npm run serve כדי להפעיל את שרת האינטרנט
  5. פותחים כרטיסייה בדפדפן ומזינים את הכתובת http://localhost:8080.

71a8a7d47392e8f4.png

3. הגדרת ערך בסיס

מהי נקודת ההתחלה שלכם?

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

מוודאים שכל הדברים פועלים באפליקציה:

  1. מתחברים באופן אנונימי באמצעות הלחצן login (התחברות) בפינה השמאלית העליונה.
  2. אחרי הכניסה לחשבון, מחפשים את 'NFLX', 'SBUX' ו-'T' ומוסיפים אותם לרשימת הצפייה. לשם כך, לוחצים על הלחצן הוספה, מקלידים את האותיות ולוחצים על השורה של תוצאת החיפוש שמופיעה למטה.
  3. כדי להסיר מניה מרשימת המעקב, לוחצים על x בסוף השורה.
  4. לצפות בעדכונים בזמן אמת של מחיר המניה.
  5. פותחים את כלי הפיתוח ל-Chrome, עוברים לכרטיסייה רשת ומסמנים את התיבות השבתה של המטמון ושימוש בשורות בקשה גדולות. ההגדרה השבתה של המטמון מבטיחה שאנחנו תמיד מקבלים את השינויים האחרונים אחרי רענון, וההגדרה שימוש בשורות בקשה גדולות מאפשרת להציג בשורה גם את הגודל שהוענק וגם את גודל המשאב של משאב. בקודלאב הזה אנחנו מתעניינים בעיקר בגודל של main.js.

48a096debb2aa940.png

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

4397cb2c1327089.png

עכשיו אפשר להתחיל להעביר את האפליקציה ל-API החדש המורכב ממודולים.

4. שימוש בחבילות התאימות

חבילות התאימות מאפשרות לשדרג לגרסת ה-SDK החדשה בלי לשנות את כל הקוד של Firebase בבת אחת. תוכלו לשדרג אותם ל-API המודולרי בהדרגה.

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

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

איך מקבלים את ה-SDK החדש

מחפשים את הקטע dependencies ב-package.json ומחליפים אותו בקוד הבא:

package.json

"dependencies": {
    "firebase": "^9.0.0" 
}

מתקינים מחדש את יחסי התלות

מאחר ששינינו את גרסת התלות, צריך להריץ מחדש את npm install כדי לקבל את הגרסה החדשה של התלות.

שינוי נתיבי הייבוא

חבילות התאימות מוצגות בתת-מודול firebase/compat, לכן נעדכן את נתיבי הייבוא בהתאם:

  1. מעבר לקובץ src/firebase.ts
  2. מחליפים את הייבוא הקיים בייבוא הבא:

src/firebase.ts

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

אימות שהאפליקציה פועלת

  1. מריצים את הפקודה npm run build כדי ליצור מחדש את האפליקציה.
  2. פותחים כרטיסייה בדפדפן ומזינים את הכתובת http://localhost:8080 או מרעננים את הכרטיסייה הקיימת.
  3. משחקים עם האפליקציה. הכול אמור לפעול.

5. שדרוג האימות לשימוש ב-API המודולרי

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

עדכון של Auth initialization

  1. מעבר לקובץ src/firebase.ts
  2. מוסיפים את הייבוא הבא:

src/firebase.ts

import { initializeAuth, indexedDBLocalPersistence } from 'firebase/auth';
  1. מחיקת import ‘firebase/compat/auth'.
  2. מחליפים את export const firebaseAuth = app.auth(); ב:

src/firebase.ts

export const firebaseAuth = initializeAuth(app, { persistence: [indexedDBLocalPersistence] });
  1. מסירים את export type User = firebase.User; בסוף הקובץ. User ייובא ישירות ל-src/auth.ts, שבו תבצעו את השינוי הבא.

עדכון קוד האימות

  1. מעבר לקובץ src/auth.ts
  2. מוסיפים את ייבוא הנתונים הבא לחלק העליון של הקובץ:

src/auth.ts

import { 
    signInAnonymously, 
    signOut,
    onAuthStateChanged,
    User
} from 'firebase/auth';
  1. צריך להסיר את User מ-import { firebaseAuth, User } from './firebase'; כי כבר ייבאת את User מ-‘firebase/auth'.
  2. מעדכנים את הפונקציות כך שישתמשו ב-API המודולרי.

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

בגרסה 9, השירותים מועברים כארגומנטים הראשונים לפונקציות. שירותים הם האובייקטים שמקבלים מהפעלת שירות Firebase, למשל האובייקט שמוחזר מ-getAuth() או מ-initializeAuth(). הם שומרים את המצב של שירות Firebase מסוים, והפונקציה משתמשת במצב כדי לבצע את המשימות שלה. נשתמש בתבנית הזו כדי להטמיע את הפונקציות הבאות:

src/auth.ts

export function firebaseSignInAnonymously() { 
    return signInAnonymously(firebaseAuth); 
} 

export function firebaseSignOut() { 
    return signOut(firebaseAuth); 
} 

export function onUserChange(callback: (user: User | null) => void) { 
    return onAuthStateChanged(firebaseAuth, callback); 
} 

export { User } from 'firebase/auth';

איך מוודאים שהאפליקציה פועלת

  1. מריצים את הפקודה npm run build כדי ליצור מחדש את האפליקציה.
  2. פותחים כרטיסייה בדפדפן ומזינים את הכתובת http://localhost:8080 , או מרעננים את הכרטיסייה הקיימת.
  3. משחקים עם האפליקציה. הכול אמור לפעול.

בדיקת גודל החבילה

  1. פותחים את כלי הפיתוח ל-Chrome.
  2. עוברים לכרטיסייה Network (רשת).
  3. צריך לרענן את הדף כדי לתעד את בקשות הרשת.
  4. מחפשים את הקובץ main.js ובודקים את הגודל שלו. שיניתם רק כמה שורות קוד והקטנתם את גודל החבילה ב-100KB (36KB בפורמט GZIP), או בכ-22%. בנוסף, האתר נטען מהר יותר ב-0.75 שניות בחיבור איטי מסוג 3G.

2e4eafaf66cd829b.png

6. שדרוג של אפליקציית Firebase ו-Firestore לשימוש ב-API המודולרי

עדכון ההפעלה של Firebase

  1. מעבר לקובץ src/firebase.ts.
  2. מחליפים את import firebase from ‘firebase/compat/app'; ב:

src/firebase.ts

import { initializeApp } from 'firebase/app';
  1. מחליפים את const app = firebase.initializeApp({...}); ב:

src/firebase.ts

const app = initializeApp({
    apiKey: "AIzaSyBnRKitQGBX0u8k4COtDTILYxCJuMf7xzE", 
    authDomain: "exchange-rates-adcf6.firebaseapp.com", 
    databaseURL: "https://exchange-rates-adcf6.firebaseio.com", 
    projectId: "exchange-rates-adcf6", 
    storageBucket: "exchange-rates-adcf6.firebasestorage.app", 
    messagingSenderId: "875614679042", 
    appId: "1:875614679042:web:5813c3e70a33e91ba0371b"
});

עדכון ההפעלה של Firestore

  1. באותו קובץ, מחליפים את import 'firebase/compat/firestore'; ב-import 'firebase/compat/firestore';src/firebase.ts,

src/firebase.ts

import { getFirestore } from 'firebase/firestore';
  1. מחליפים את export const firestore = app.firestore(); ב:

src/firebase.ts

export const firestore = getFirestore();
  1. הסרת כל השורות אחרי "export const firestore = ..."

עדכון היבוא

  1. פתיחת הקובץ src/services.ts.
  2. מסירים את FirestoreFieldPath, ‏ FirestoreFieldValue ו-QuerySnapshot מהייבוא. הייבוא מ-'./firebase' אמור להיראות כך:

src/services.ts

import { firestore } from './firebase';
  1. מייבאים את הפונקציות והסוגים שבהם רוצים להשתמש בחלק העליון של הקובץ:
    **src/services.ts**
import { 
    collection, 
    getDocs, 
    doc, 
    setDoc, 
    arrayUnion, 
    arrayRemove, 
    onSnapshot, 
    query, 
    where, 
    documentId, 
    QuerySnapshot
} from 'firebase/firestore';
  1. יוצרים הפניה לאוסף שמכיל את כל הסמלים:

src/services.ts

const tickersCollRef = collection(firestore, 'current');
  1. משתמשים ב-getDocs() כדי לאחזר את כל המסמכים מהאוסף:

src/services.ts

const tickers = await getDocs(tickersCollRef);

הקוד המוגמר מופיע בקובץ search().

עדכון addToWatchList()‎

משתמשים ב-doc() כדי ליצור הפניה למסמך של רשימת המעקב של המשתמש, ואז מוסיפים לו מידע על מניות באמצעות setDoc() עם arrayUnion():

src/services.ts

export function addToWatchList(ticker: string, user: User) {
      const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
      return setDoc(watchlistRef, {
       tickers: arrayUnion(ticker)
   }, { merge: true });
}

עדכון deleteFromWatchList()

באופן דומה, אפשר להסיר אסימון מניות מרשימת הצפייה של משתמש באמצעות setDoc() עם arrayRemove():

src/services.ts

export function deleteFromWatchList(ticker: string, user: User) {
   const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
   return setDoc(watchlistRef, {
       tickers: arrayRemove(ticker)
   }, { merge: true });
}

עדכון subscribeToTickerChanges()

  1. קודם משתמשים ב-doc() כדי ליצור הפניה למסמך של רשימת הצפייה של המשתמש, ואז מקשיבים לשינויים ברשימת הצפייה באמצעות onSnapshot():

src/services.ts

const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
const unsubscribe = onSnapshot(watchlistRef, snapshot => {
   /* subscribe to ticker price changes */
});
  1. אחרי שמוסיפים את הסימונים לרשימת המעקב, משתמשים ב-query() כדי ליצור שאילתה לאחזור המחירים שלהם, וב-onSnapshot() כדי להאזין לשינויים במחירים שלהם:

src/services.ts

const priceQuery = query(
    collection(firestore, 'current'),
    where(documentId(), 'in', tickers)
);
unsubscribePrevTickerChanges = onSnapshot(priceQuery, snapshot => {
               if (firstload) {
                   performance && performance.measure("initial-data-load");
                   firstload = false;
                   logPerformance();
               }
               const stocks = formatSDKStocks(snapshot);
               callback(stocks);
  });

ההטמעה המלאה מפורטת ב-subscribeToTickerChanges()‎.

עדכון subscribeToAllTickerChanges()‎

קודם משתמשים ב-collection() כדי ליצור הפניה לאוסף שמכיל את המחירים של כל המכשירים, ואז משתמשים ב-onSnapshot() כדי להאזין לשינויים במחירים:

src/services.ts

export function subscribeToAllTickerChanges(callback: TickerChangesCallBack) {
   const tickersCollRef = collection(firestore, 'current');
   return onSnapshot(tickersCollRef, snapshot => {
       if (firstload) {
           performance && performance.measure("initial-data-load");
           firstload = false;
           logPerformance();
       }
       const stocks = formatSDKStocks(snapshot);
       callback(stocks);
   });
}

איך מוודאים שהאפליקציה פועלת

  1. מריצים את הפקודה npm run build כדי ליצור מחדש את האפליקציה.
  2. פותחים כרטיסייה בדפדפן ומזינים את הכתובת http://localhost:8080 , או מרעננים את הכרטיסייה הקיימת.
  3. משחקים עם האפליקציה. הכול אמור לפעול.

בדיקת גודל החבילה

  1. פותחים את כלי הפיתוח ל-Chrome.
  2. עוברים לכרטיסייה Network (רשת).
  3. צריך לרענן את הדף כדי לתעד את בקשות הרשת.
  4. מחפשים את main.js ובודקים את הגודל שלו. שוב, אפשר להשוות את הגודל של החבילה המאוחדת לגודל המקורי שלה – הפחתנו את גודל החבילה ב-200KB (63.8KB בפורמט GZIP), כלומר ב-50%, וכתוצאה מכך זמן הטעינה קצר ב-1.3 שניות!

7660cdc574ee8571.png

7. שימוש ב-Firestore Lite כדי לזרז את עיבוד הדף הראשוני

מהו Firestore Lite?

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

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

בשלב הזה תלמדו איך להשתמש ב-Firestore lite כדי לצמצם את גודל החבילה ולהאיץ את העיבוד הראשוני של הדף, ואז לטעון באופן דינמי את ה-SDK הראשי של Firestore כדי להירשם לעדכונים בזמן אמת.

תבצעו ריפרקטור (refactor) של הקוד כדי:

  1. העברת שירותים בזמן אמת לקובץ נפרד, כדי שאפשר יהיה לטעון אותם באופן דינמי באמצעות ייבוא דינמי.
  2. יצירת פונקציות חדשות לשימוש ב-Firestore Lite כדי לאחזר את רשימת המניות למעקב ואת מחירי המניות.
  3. משתמשים בפונקציות החדשות של Firestore Lite כדי לאחזר נתונים לצורך עיבוד ראשוני של הדף, ולאחר מכן מעמיסים באופן דינמי את השירותים בזמן אמת כדי להאזין לעדכונים בזמן אמת.

העברת שירותים בזמן אמת לקובץ חדש

  1. יוצרים קובץ חדש בשם src/services.realtime.ts.
  2. מעבירים את הפונקציות subscribeToTickerChanges() ו-subscribeToAllTickerChanges() מ-src/services.ts לקובץ החדש.
  3. מוסיפים את הייבוא הנדרש בחלק העליון של הקובץ החדש.

עדיין צריך לבצע כמה שינויים כאן:

  1. קודם צריך ליצור מכונה של Firestore מ-Firestore SDK הראשי בחלק העליון של הקובץ, כדי להשתמש בה בפונקציות. לא ניתן לייבא את המכונה של Firestore מ-firebase.ts כאן, כי תשנו אותה למכונה של Firestore Lite בכמה שלבים, ותשתמשו בה רק לצורך עיבוד הדף הראשוני.
  2. בשלב השני, מסירים את המשתנה firstload ואת בלוק ה-if שמוגן על ידו. הפונקציונליות שלהן תועבר לפונקציות חדשות שתיצרו בשלב הבא.

src/services.realtime.ts

import { User } from './auth'
import { TickerChange } from './models';
import { collection, doc, onSnapshot, query, where, documentId, getFirestore } from 'firebase/firestore';
import { formatSDKStocks } from './services';

const firestore = getFirestore();
type TickerChangesCallBack = (changes: TickerChange[]) => void

export function subscribeToTickerChanges(user: User, callback: TickerChangesCallBack) {

   let unsubscribePrevTickerChanges: () => void;

   // Subscribe to watchlist changes. We will get an update whenever a ticker is added/deleted to the watchlist
   const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
   const unsubscribe = onSnapshot(watchlistRef, snapshot => {
       const doc = snapshot.data();
       const tickers = doc ? doc.tickers : [];

       if (unsubscribePrevTickerChanges) {
           unsubscribePrevTickerChanges();
       }

       if (tickers.length === 0) {
           callback([]);
       } else {
           // Query to get current price for tickers in the watchlist
           const priceQuery = query(
               collection(firestore, 'current'),
               where(documentId(), 'in', tickers)
           );

           // Subscribe to price changes for tickers in the watchlist
           unsubscribePrevTickerChanges = onSnapshot(priceQuery, snapshot => {
               const stocks = formatSDKStocks(snapshot);
               callback(stocks);
           });
       }
   });
   return () => {
       if (unsubscribePrevTickerChanges) {
           unsubscribePrevTickerChanges();
       }
       unsubscribe();
   };
}

export function subscribeToAllTickerChanges(callback: TickerChangesCallBack) {
   const tickersCollRef = collection(firestore, 'current');
   return onSnapshot(tickersCollRef, snapshot => {
       const stocks = formatSDKStocks(snapshot);
       callback(stocks);
   });
}

שימוש ב-Firestore lite לאחזור נתונים

  1. פתיחה של src/services.ts.
  2. שינוי נתיב הייבוא מ-‘firebase/firestore' ל-‘firebase/firestore/lite',, הוספת getDoc והסרת onSnapshot מרשימת הייבוא:

src/services.ts

import { 
    collection, 
    getDocs, 
    doc, 
    setDoc, 
    arrayUnion, 
    arrayRemove,
//  onSnapshot, // firestore lite doesn't support realtime updates
    query, 
    where, 
    documentId, 
    QuerySnapshot, 
    getDoc // add this import
} from 'firebase/firestore/lite';
  1. מוסיפים פונקציות לאחזור הנתונים הנדרשים לעיבוד הראשוני של הדף באמצעות Firestore Lite:

src/services.ts

export async function getTickerChanges(tickers: string[]): Promise<TickerChange[]> {

   if (tickers.length === 0) {
       return [];
   }

   const priceQuery = query(
       collection(firestore, 'current'),
       where(documentId(), 'in', tickers)
   );
   const snapshot = await getDocs(priceQuery);
   performance && performance.measure("initial-data-load");
   logPerformance();
   return formatSDKStocks(snapshot);
}

export async function getTickers(user: User): Promise<string[]> {
   const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
   const data =  (await getDoc(watchlistRef)).data();

   return data ? data.tickers : [];
}

export async function getAllTickerChanges(): Promise<TickerChange[]> {
   const tickersCollRef = collection(firestore, 'current');
   const snapshot = await getDocs(tickersCollRef);
   performance && performance.measure("initial-data-load");
   logPerformance();
   return formatSDKStocks(snapshot);
}
  1. פותחים את src/firebase.ts ומשנים את נתיב הייבוא מ-‘firebase/firestore' ל-‘firebase/firestore/lite':.

src/firebase.ts

import { getFirestore } from 'firebase/firestore/lite';

איך משלבים את כל הנתונים

  1. פתיחה של src/main.ts.
  2. תצטרכו את הפונקציות החדשות שיצרתם כדי לאחזר נתונים לעיבוד הראשוני של הדף, וכמה פונקציות עזר כדי לנהל את מצב האפליקציה. עכשיו מעדכנים את הייבוא:

src/main.ts

import { renderLoginPage, renderUserPage } from './renderer';
import { getAllTickerChanges, getTickerChanges, getTickers } from './services';
import { onUserChange } from './auth';
import { getState, setRealtimeServicesLoaded, setUser } from './state';
import './styles.scss';
  1. טוענים את src/services.realtime באמצעות ייבוא דינמי בחלק העליון של הקובץ. המשתנה loadRealtimeService הוא הבטחה שתיפתר עם השירותים בזמן אמת אחרי שהקוד ייטען. בהמשך תשתמשו בו כדי להירשם לקבלת עדכונים בזמן אמת.

src/main.ts

const loadRealtimeService = import('./services.realtime');
loadRealtimeService.then(() => {
   setRealtimeServicesLoaded(true);
});
  1. משנים את הקריאה החוזרת (callback) של onUserChange() לפונקציית async, כדי שנוכל להשתמש ב-await בגוף הפונקציה:

src/main.ts

onUserChange(async user => {
 // callback body
});
  1. עכשיו מאחזרים את הנתונים כדי לבצע את העיבוד הראשוני של הדף באמצעות הפונקציות החדשות שיצרנו בשלב הקודם.

ב-callback של onUserChange(), מחפשים את תנאי ה-if שבו המשתמש מחובר לחשבון, מעתיקים את הקוד ומדביקים אותו בתוך משפט ה-if:

src/main.ts

onUserChange(async user => {
      // LEAVE THE EXISTING CODE UNCHANGED HERE
      ...

      if (user) {
       // REPLACE THESE LINES

       // user page
       setUser(user);

       // show loading screen in 500ms
       const timeoutId = setTimeout(() => {
           renderUserPage(user, {
               loading: true,
               tableData: []
           });
       }, 500);

       // get data once if realtime services haven't been loaded
       if (!getState().realtimeServicesLoaded) {
           const tickers = await getTickers(user);
           const tickerData = await getTickerChanges(tickers);
           clearTimeout(timeoutId);
           renderUserPage(user, { tableData: tickerData });
       }

       // subscribe to realtime updates once realtime services are loaded
       loadRealtimeService.then(({ subscribeToTickerChanges }) => {
           unsubscribeTickerChanges = subscribeToTickerChanges(user, stockData => {
               clearTimeout(timeoutId);
               renderUserPage(user, { tableData: stockData })
           });
       });
   } else {
     // DON'T EDIT THIS PART, YET   
   }
}
  1. בבלוק else, שבו אף משתמש לא מחובר, מאחזרים את פרטי המחירים של כל המניות באמצעות firestore lite, מעבדים את הדף ואז מקשיבים לשינויים במחירים אחרי שהשירותים בזמן אמת נטענים:

src/main.ts

if (user) {
   // DON'T EDIT THIS PART, WHICH WE JUST CHANGED ABOVE
   ...
} else {
   // REPLACE THESE LINES

   // login page
   setUser(null);

   // show loading screen in 500ms
   const timeoutId = setTimeout(() => {
       renderLoginPage('Landing page', {
           loading: true,
           tableData: []
       });
   }, 500);

   // get data once if realtime services haven't been loaded
   if (!getState().realtimeServicesLoaded) {
       const tickerData = await getAllTickerChanges();
       clearTimeout(timeoutId);
       renderLoginPage('Landing page', { tableData: tickerData });
   }

   // subscribe to realtime updates once realtime services are loaded
   loadRealtimeService.then(({ subscribeToAllTickerChanges }) => {
       unsubscribeAllTickerChanges = subscribeToAllTickerChanges(stockData => {
           clearTimeout(timeoutId);
           renderLoginPage('Landing page', { tableData: stockData })
       });
   });
}

הקוד המוגמר נמצא בקובץ src/main.ts.

אימות שהאפליקציה פועלת

  1. מריצים את הפקודה npm run build כדי ליצור מחדש את האפליקציה.
  2. פותחים כרטיסייה בדפדפן ומזינים את הכתובת http://localhost:8080 או מרעננים את הכרטיסייה הקיימת.

בדיקת גודל החבילה

  1. פותחים את כלי הפיתוח ל-Chrome.
  2. עוברים לכרטיסייה Network (רשת).
  3. צריך לרענן את הדף כדי לתעד את בקשות הרשת
  4. מחפשים את main.js ובודקים את הגודל שלו.
  5. עכשיו הוא רק 115KB (34.5KB ב-Gzip). הגודל הזה קטן ב-75% מגודל החבילה המקורית, שהיה 446KB‏(138KB בפורמט GZIP)! כתוצאה מכך, האתר נטען מהר יותר ביותר מ-2 שניות בחיבור 3G – שיפור משמעותי בביצועים ובחוויית המשתמש!

9ea7398a8c8ef81b.png

8. מזל טוב

הצלחת לשדרג את האפליקציה ולהפוך אותה לקטנה ומהירה יותר!

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

במהלך הקודלאב הזה הפחתתם גם את גודל החבילה ושפרתם את זמן הטעינה שלה:

main.js

גודל המשאב (KB)

גודל הקובץ בפורמט gzip (KB)

זמן הטעינה (שניות) (ב-3G איטי)

v8

446

138

4.92

v9 compat

429

124

4.65

אימות מודולרי בגרסה 9 בלבד

348

102

4.2

גרסה 9 – מודולרית לחלוטין

244

74.6

3.66

גרסה 9 מודולרית לחלוטין + Firestore lite

117

34.9

2.88

32a71bd5a774e035.png

עכשיו אתם יודעים מהם השלבים העיקריים לשדרוג אפליקציית אינטרנט שמשתמשת ב-Firebase JS SDK מגרסה 8 ל-JS SDK המודולרי החדש.

מקורות מידע נוספים

מסמכי עזרה