เพิ่มพลังให้เว็บแอปของคุณโดยเปลี่ยนไปใช้ Firebase JS SDK แบบโมดูล

1. ก่อนเริ่มต้น

Firebase JS SDK แบบโมดูลเป็นการเขียน JS SDK ที่มีอยู่ใหม่และจะเปิดตัวเป็นเวอร์ชันหลักเวอร์ชันถัดไป ซึ่งช่วยให้นักพัฒนาแอปยกเว้นโค้ดที่ไม่ได้ใช้จาก Firebase JS SDK เพื่อสร้างแพ็กเกจขนาดเล็กลงและมีประสิทธิภาพดีขึ้น

ความแตกต่างที่เห็นได้ชัดที่สุดของ JS SDK แบบโมดูลคือตอนนี้ฟีเจอร์ต่างๆ จะจัดระเบียบไว้ในฟังก์ชันแบบลอยอิสระที่คุณจะนําเข้า แทนที่จะอยู่ในเนมสเปซ firebase เดียวที่มีทุกอย่าง วิธีใหม่ในการจัดระเบียบโค้ดนี้ช่วยให้สามารถแยกไฟล์ที่ไม่จำเป็นออกได้ และคุณจะได้เรียนรู้วิธีอัปเกรดแอปที่ใช้ Firebase JS SDK เวอร์ชัน 8 อยู่ให้เป็นเวอร์ชันใหม่แบบโมดูล

เรามีชุดแพ็กเกจความเข้ากันได้เพื่อให้กระบวนการอัปเกรดเป็นไปอย่างราบรื่น ในโค้ดแล็บนี้ คุณจะได้เรียนรู้วิธีใช้แพ็กเกจความเข้ากันได้เพื่อพอร์ตแอปทีละส่วน

สิ่งที่คุณจะสร้าง

ในโค้ดแล็บนี้ คุณจะค่อยๆ ย้ายข้อมูลเว็บแอปรายการติดตามหุ้นที่มีอยู่ซึ่งใช้ JS SDK เวอร์ชัน 8 ไปยัง JS SDK แบบโมดูลใหม่ใน 3 ระยะ ดังนี้

  • อัปเกรดแอปเพื่อใช้แพ็กเกจความเข้ากันได้
  • อัปเกรดแอปจากแพ็กเกจความเข้ากันได้เป็น 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. ใช้ IDE เพื่อเปิดหรือนําเข้าไดเรกทอรี codelab-modular-sdk
  2. เรียกใช้ npm install เพื่อติดตั้งไลบรารีที่จำเป็นต่อการสร้างและเรียกใช้แอปในเครื่อง
  3. เรียกใช้ npm run build เพื่อสร้างแอป
  4. เรียกใช้ npm run serve เพื่อเริ่มเว็บเซิร์ฟเวอร์
  5. เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:8080

71a8a7d47392e8f4.png

3. กำหนดพื้นฐาน

จุดเริ่มต้นของคุณคืออะไร

จุดเริ่มต้นของคุณคือแอปรายการติดตามหุ้นที่ออกแบบมาสำหรับ Codelab นี้ โค้ดนี้เรียบง่ายขึ้นเพื่อแสดงแนวคิดในโค้ดแล็บนี้ และมีการแก้ไขข้อผิดพลาดเพียงเล็กน้อย หากเลือกที่จะนำโค้ดนี้มาใช้ซ้ำในแอปเวอร์ชันที่ใช้งานจริง โปรดตรวจสอบว่าคุณจัดการข้อผิดพลาดและทดสอบโค้ดทั้งหมดอย่างสมบูรณ์แล้ว

ตรวจสอบว่าทุกอย่างในแอปใช้งานได้ โดยทำดังนี้

  1. เข้าสู่ระบบแบบไม่ระบุตัวตนโดยใช้ปุ่มเข้าสู่ระบบที่มุมขวาบน
  2. หลังจากเข้าสู่ระบบแล้ว ให้ค้นหาและเพิ่ม "NFLX", "SBUX" และ "T" ลงในรายการติดตามโดยคลิกปุ่มเพิ่ม พิมพ์ตัวอักษร และคลิกแถวผลการค้นหาที่ปรากฏขึ้นด้านล่าง
  3. นำหุ้นออกจากรายการติดตามโดยคลิก x ที่ท้ายแถว
  4. ดูการอัปเดตราคาหุ้นแบบเรียลไทม์
  5. เปิดเครื่องมือสําหรับนักพัฒนาเว็บใน Chrome ไปที่แท็บ Network แล้วเลือกปิดใช้แคชและใช้แถวคําขอขนาดใหญ่ ปิดใช้แคชช่วยให้เราได้รับการเปลี่ยนแปลงล่าสุดเสมอหลังจากการรีเฟรช และใช้แถวคำขอขนาดใหญ่จะทำให้แถวแสดงทั้งขนาดที่ส่งและขนาดทรัพยากรของทรัพยากร ใน Codelab นี้ เราสนใจขนาดของ main.js เป็นหลัก

48a096debb2aa940.png

  1. โหลดแอปภายใต้เงื่อนไขเครือข่ายที่ต่างกันโดยใช้การควบคุมแบบจําลอง คุณจะใช้ 3G ที่ช้าเพื่อวัดเวลาในการโหลดในโค้ดแล็บนี้ เนื่องจากเป็นเครือข่ายที่ขนาด Bundle ที่เล็กลงจะมีประโยชน์มากที่สุด

4397cb2c1327089.png

ตอนนี้ก็เริ่มย้ายข้อมูลแอปไปยัง API แบบโมดูลใหม่ได้เลย

4. ใช้แพ็กเกจความเข้ากันได้

แพ็กเกจความเข้ากันได้ช่วยให้คุณอัปเกรดเป็น SDK เวอร์ชันใหม่ได้โดยไม่ต้องเปลี่ยนโค้ด Firebase ทั้งหมดพร้อมกัน คุณสามารถอัปเกรดเป็น API แบบโมดูลทีละน้อยได้

ในขั้นตอนนี้ คุณจะอัปเกรดไลบรารี Firebase จาก v8 เป็นเวอร์ชันใหม่และเปลี่ยนโค้ดให้ใช้แพ็กเกจความเข้ากันได้ ในขั้นตอนต่อไปนี้ คุณจะได้เรียนรู้วิธีอัปเกรดเฉพาะโค้ด Firebase Auth เพื่อใช้ API แบบโมดูลก่อน จากนั้นจึงอัปเกรดโค้ด Firestore

เมื่อสิ้นสุดแต่ละขั้นตอน คุณควรจะคอมไพล์และเรียกใช้แอปได้โดยไม่มีปัญหา และเห็นขนาด App Bundle ลดลงเมื่อเราย้ายข้อมูลผลิตภัณฑ์แต่ละรายการ

รับ SDK ใหม่

ค้นหาส่วน Dependency ใน 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. อัปเกรด Auth เพื่อใช้ API แบบโมดูล

คุณอัปเกรดผลิตภัณฑ์ Firebase ได้ทุกลำดับ ในโค้ดแล็บนี้ คุณจะอัปเกรด Auth ก่อนเพื่อเรียนรู้แนวคิดพื้นฐาน เนื่องจาก Auth API ค่อนข้างง่าย การอัปเกรด Firestore นั้นซับซ้อนกว่าเล็กน้อย และคุณจะได้ดูวิธีดำเนินการในลำดับถัดไป

อัปเดตการเริ่มต้นการตรวจสอบสิทธิ์

  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 ที่ใช้รูปแบบบริการและเนมสเปซแบบเชนจุด การจัดระเบียบโค้ดใหม่นี้ช่วยให้สามารถแยกโค้ดที่ไม่ได้ใช้ออกได้ เนื่องจากช่วยให้เครื่องมือสร้างวิเคราะห์ได้ว่าโค้ดใดมีการใช้งานและโค้ดใดไม่มีการใช้งาน

ในเวอร์ชัน 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. เปลี่ยนไปใช้แท็บเครือข่าย
  3. รีเฟรชหน้าเว็บเพื่อบันทึกคําขอเครือข่าย
  4. มองหา main.js และตรวจสอบขนาด คุณได้ลดขนาดแพ็กเกจลง 100 KB (36 KB เมื่อใช้การบีบอัดข้อมูลด้วย 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. ในไฟล์เดียวกัน src/firebase.ts, ให้แทนที่ import 'firebase/compat/firestore'; ด้วย

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()

ในทำนองเดียวกัน ให้นำข้อมูล Ticker ออกจากรายการที่อยากดูของผู้ใช้โดยใช้ 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. เมื่อเพิ่มข้อมูล Ticker ไว้ในรายการติดตามแล้ว ให้ใช้ 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. เปลี่ยนไปใช้แท็บเครือข่าย
  3. รีเฟรชหน้าเว็บเพื่อบันทึกคําขอเครือข่าย
  4. มองหา main.js และตรวจสอบขนาด เมื่อเปรียบเทียบกับขนาด App Bundle เดิม เราลดขนาด App Bundle ลงได้กว่า 200 KB (63.8 KB เมื่อใช้การบีบอัดข้อมูลด้วย GZIP) หรือเล็กลง 50% ซึ่งทำให้เวลาในการโหลดเร็วขึ้น 1.3 วินาที

7660cdc574ee8571.png

7. ใช้ Firestore Lite เพื่อเพิ่มความเร็วในการแสดงผลหน้าเว็บครั้งแรก

Firestore Lite คืออะไร

Firestore SDK มีแคชที่ซับซ้อน สตรีมมิงแบบเรียลไทม์ พื้นที่เก็บข้อมูลถาวร การซิงค์แบบออฟไลน์หลายแท็บ การลองอีกครั้ง การทํางานพร้อมกันแบบมองโลกในแง่ดี และอื่นๆ อีกมากมาย จึงมีขนาดใหญ่ แต่คุณอาจต้องการรับข้อมูลเพียงครั้งเดียวโดยไม่จำเป็นต้องใช้ฟีเจอร์ขั้นสูงใดๆ สำหรับกรณีดังกล่าว Firestore ได้สร้างโซลูชันที่เรียบง่ายและเบาแพ็กเกจใหม่อย่าง Firestore Lite

Use Case ที่ยอดเยี่ยมอย่างหนึ่งของ Firestore Lite คือการเพิ่มประสิทธิภาพการแสดงผลหน้าเว็บครั้งแรก โดยคุณเพียงต้องทราบว่าผู้ใช้เข้าสู่ระบบอยู่หรือไม่ จากนั้นอ่านข้อมูลบางอย่างจาก Firestore เพื่อแสดง

ในขั้นตอนนี้ คุณจะได้เรียนรู้วิธีใช้ Firestore Lite เพื่อลดขนาด Bundle เพื่อเร่งการแสดงผลหน้าเว็บครั้งแรก จากนั้นโหลด Firestore SDK หลักแบบไดนามิกเพื่อสมัครรับการอัปเดตแบบเรียลไทม์

คุณจะเปลี่ยนรูปแบบโค้ดเพื่อดำเนินการต่อไปนี้

  1. ย้ายบริการแบบเรียลไทม์ไปยังไฟล์แยกต่างหากเพื่อให้โหลดแบบไดนามิกได้โดยใช้การนําเข้าแบบไดนามิก
  2. สร้างฟังก์ชันใหม่เพื่อใช้ Firestore Lite เพื่อดึงข้อมูลรายการติดตามและราคาหุ้น
  3. ใช้ฟังก์ชัน Firestore Lite ใหม่เพื่อดึงข้อมูลเพื่อทำการแสดงผลหน้าเว็บครั้งแรก จากนั้นโหลดบริการแบบเรียลไทม์แบบไดนามิกเพื่อรับการอัปเดตแบบเรียลไทม์

ย้ายบริการแบบเรียลไทม์ไปยังไฟล์ใหม่

  1. สร้างไฟล์ใหม่ชื่อ src/services.realtime.ts.
  2. ย้ายฟังก์ชัน subscribeToTickerChanges() และ subscribeToAllTickerChanges() จาก src/services.ts ไปยังไฟล์ใหม่
  3. เพิ่มการนําเข้าที่จําเป็นไว้ที่ด้านบนของไฟล์ใหม่

คุณยังต้องทําการเปลี่ยนแปลงอีก 2-3 อย่างที่นี่

  1. ก่อนอื่น ให้สร้างอินสแตนซ์ Firestore จาก Firestore SDK หลักที่ด้านบนของไฟล์เพื่อใช้ในฟังก์ชัน คุณไม่สามารถนําเข้าอินสแตนซ์ Firestore จาก firebase.ts ที่นี่ได้ เนื่องจากคุณจะเปลี่ยนเป็นอินสแตนซ์ Firestore Lite ในอีก 2-3 ขั้นตอน ซึ่งจะใช้สําหรับการแสดงผลหน้าเว็บครั้งแรกเท่านั้น
  2. ประการที่ 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. คุณจะต้องมีฟังก์ชันที่สร้างขึ้นใหม่เพื่อดึงข้อมูลสำหรับการแสดงผลหน้าเว็บครั้งแรก และฟังก์ชันตัวช่วย 2-3 รายการเพื่อจัดการสถานะแอป ดังนั้นให้อัปเดตการนําเข้าดังนี้

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. เปลี่ยนการเรียกกลับของ onUserChange() เป็นฟังก์ชัน async เพื่อให้เราใช้ await ในเนื้อหาของฟังก์ชันได้

src/main.ts

onUserChange(async user => {
 // callback body
});
  1. ตอนนี้ให้ดึงข้อมูลเพื่อทำให้หน้าเว็บแสดงผลครั้งแรกโดยใช้ฟังก์ชันใหม่ที่สร้างขึ้นในขั้นตอนก่อนหน้า

ใน onUserChange() callback ให้ค้นหาเงื่อนไข 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. เปลี่ยนไปใช้แท็บเครือข่าย
  3. รีเฟรชหน้าเว็บเพื่อบันทึกคําขอเครือข่าย
  4. มองหา main.js แล้วตรวจสอบขนาด
  5. ตอนนี้เหลือเพียง 115 KB (34.5 KB เมื่อใช้การบีบอัดไฟล์ GZIP) ซึ่งเล็กกว่าขนาดเดิมของกลุ่มที่ 446 KB(138 KB เมื่อใช้การบีบอัด GZIP) 75% ด้วยเหตุนี้ เว็บไซต์จึงโหลดเร็วขึ้นกว่า 2 วินาทีในการเชื่อมต่อ 3G ซึ่งเป็นการปรับปรุงประสิทธิภาพและประสบการณ์ของผู้ใช้ที่ยอดเยี่ยม

9ea7398a8c8ef81b.png

8. ขอแสดงความยินดี

ขอแสดงความยินดี คุณได้อัปเกรดแอปให้เล็กลงและเร็วขึ้นเรียบร้อยแล้ว

คุณใช้แพ็กเกจ compat เพื่ออัปเกรดแอปทีละส่วน และใช้ Firestore Lite เพื่อเร่งการแสดงผลหน้าเว็บครั้งแรก จากนั้นโหลด Firestore หลักแบบไดนามิกเพื่อสตรีมการเปลี่ยนแปลงราคา

นอกจากนี้ คุณยังลดขนาดของ Bundle และปรับปรุงเวลาในการโหลดตลอดระยะเวลาของ Codelab นี้ด้วย

main.js

ขนาดทรัพยากร (KB)

ขนาดไฟล์ที่บีบอัด (KB)

เวลาที่ใช้ในการโหลด (วินาที) (ผ่าน 3G ที่ช้า)

v8

446

138

4.92

v9 compat

429

124

4.65

การตรวจสอบสิทธิ์แบบโมดูลของ v9 เท่านั้น

348

102

4.2

v9 แบบโมดูลทั้งหมด

244

74.6

3.66

v9 แบบโมดูลทั้งหมด + Firestore Lite

117

34.9

2.88

32a71bd5a774e035.png

ตอนนี้คุณทราบขั้นตอนสําคัญที่จําเป็นในการอัปเกรดเว็บแอปที่ใช้ Firebase JS SDK เวอร์ชัน 8 เพื่อใช้ JS SDK แบบโมดูลใหม่แล้ว

อ่านเพิ่มเติม

เอกสารอ้างอิง