1. ก่อนที่คุณจะเริ่ม
โมดูลาร์ Firebase JS SDK เป็นการเขียนใหม่ของ JS SDK ที่มีอยู่ และจะเปิดตัวเป็นเวอร์ชันหลักถัดไป ช่วยให้นักพัฒนาสามารถแยกโค้ดที่ไม่ได้ใช้ออกจาก Firebase JS SDK เพื่อสร้างบันเดิลขนาดเล็กลงและมีประสิทธิภาพดีขึ้น
ความแตกต่างที่เห็นได้ชัดเจนที่สุดในโมดูลาร์ JS SDK คือตอนนี้ฟีเจอร์ต่างๆ ได้รับการจัดระเบียบในฟังก์ชันลอยตัวฟรีที่คุณจะนำเข้า ซึ่งต่างจากเนมสเปซ firebase
เดียวที่รวมทุกอย่างไว้ วิธีใหม่ในการจัดระเบียบโค้ดคือสิ่งที่ทำให้เกิดการเขย่าแบบทรี และคุณจะได้เรียนรู้วิธีอัปเกรดแอปใดๆ ที่ใช้ Firebase JS SDK เวอร์ชัน 8 ในปัจจุบันเป็นแอปแบบโมดูลาร์ใหม่
เพื่อให้กระบวนการอัปเกรดราบรื่น จึงมีการจัดเตรียมชุดแพ็คเกจความเข้ากันได้ไว้ ใน Codelab นี้ คุณจะได้เรียนรู้วิธีใช้แพ็คเกจความเข้ากันได้เพื่อย้ายแอปทีละชิ้น
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะค่อยๆ ย้ายเว็บแอปรายการเฝ้าดูหุ้นที่มีอยู่ซึ่งใช้ v8 JS SDK ไปยัง JS SDK แบบโมดูลาร์ใหม่ในสามขั้นตอน:
- อัปเกรดแอปเพื่อใช้แพ็คเกจความเข้ากันได้
- อัปเกรดแอปจากแพ็คเกจความเข้ากันได้เป็น API แบบโมดูลาร์ทีละชิ้น
- ใช้ Firestore Lite ซึ่งเป็นการนำ Firestore SDK ไปใช้เพียงเล็กน้อย เพื่อปรับปรุงประสิทธิภาพของแอปให้ดียิ่งขึ้น
Codelab นี้มุ่งเน้นไปที่การอัปเกรด Firebase SDK แนวคิดและบล็อคโค้ดอื่นๆ จะถูกกลบทับไว้และมีไว้ให้คุณคัดลอกและวางได้อย่างง่ายดาย
สิ่งที่คุณต้องการ
2. ตั้งค่า
รับรหัส
ทุกสิ่งที่คุณต้องการสำหรับโปรเจ็กต์นี้อยู่ใน repo Git ในการเริ่มต้น คุณจะต้องคว้าโค้ดและเปิดมันในสภาพแวดล้อมการพัฒนาที่คุณชื่นชอบ
โคลน ที่เก็บ Github ของ codelab จากบรรทัดคำสั่ง:
git clone https://github.com/FirebaseExtended/codelab-modular-sdk.git
หรือหากคุณไม่ได้ติดตั้ง git คุณสามารถ ดาวน์โหลดที่เก็บเป็นไฟล์ ZIP และแตกไฟล์ zip ที่ดาวน์โหลดมาได้
นำเข้าแอป
- ใช้ IDE ของคุณเปิดหรือนำเข้าไดเรกทอรี
codelab-modular-sdk
- เรียกใช้
npm install
เพื่อติดตั้งการขึ้นต่อกันที่จำเป็นในการสร้างและเรียกใช้แอปในเครื่อง - รัน
npm run build
เพื่อสร้างแอป - เรียกใช้
npm run serve
เพื่อเริ่มเว็บเซิร์ฟเวอร์ - เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:8080
3. สร้างพื้นฐาน
จุดเริ่มต้นของคุณคืออะไร?
จุดเริ่มต้นของคุณคือแอปเฝ้าดูหุ้นที่ออกแบบมาสำหรับ Codelab นี้ โค้ดได้รับการปรับให้ง่ายขึ้นเพื่อแสดงแนวคิดใน Codelab นี้ และมีการจัดการข้อผิดพลาดเพียงเล็กน้อย หากคุณเลือกที่จะใช้โค้ดใดๆ นี้ซ้ำในแอปที่ใช้งานจริง ตรวจสอบให้แน่ใจว่าคุณจัดการกับข้อผิดพลาดใดๆ และทดสอบโค้ดทั้งหมดอย่างสมบูรณ์
ตรวจสอบให้แน่ใจว่าทุกอย่างใช้งานได้ในแอป:
- เข้าสู่ระบบโดยไม่ระบุชื่อโดยใช้ปุ่ม เข้าสู่ระบบ ที่มุมขวาบน
- หลังจากเข้าสู่ระบบ ให้ค้นหาและเพิ่ม "NFLX", "SBUX" และ "T" ลงในรายการเฝ้าดูโดยคลิกปุ่ม เพิ่ม พิมพ์ตัวอักษร และคลิกแถวผลการค้นหาที่ปรากฏขึ้นด้านล่าง
- ลบหุ้นออกจากรายการเฝ้าดูโดยคลิก x ที่ท้ายแถว
- ชมการอัพเดตราคาหุ้นแบบเรียลไทม์
- เปิด Chrome DevTools ไปที่แท็บ เครือข่าย แล้วทำเครื่องหมายที่ ปิดใช้งานแคช และ ใช้แถวคำขอขนาดใหญ่ ปิดใช้งานแคช ทำให้แน่ใจว่าเราได้รับการเปลี่ยนแปลงล่าสุดเสมอหลังจากการรีเฟรช และ การใช้แถวคำขอขนาดใหญ่ ทำให้แถวแสดงทั้งขนาดที่ส่งและขนาดทรัพยากรสำหรับทรัพยากร ใน Codelab นี้ เราสนใจขนาดของ
main.js
เป็นหลัก
- โหลดแอปภายใต้เงื่อนไขเครือข่ายที่แตกต่างกันโดยใช้การควบคุมปริมาณจำลอง คุณจะใช้ Slow 3G เพื่อวัดเวลาในการโหลดใน Codelab นี้ เนื่องจากเป็นที่ที่ขนาดบันเดิลที่เล็กกว่าจะช่วยได้มากที่สุด
ตอนนี้ให้กระโดดและเริ่มย้ายแอปไปยัง API แบบโมดูลาร์ใหม่
4. ใช้แพ็คเกจความเข้ากันได้
แพ็คเกจความเข้ากันได้ช่วยให้คุณสามารถอัปเกรดเป็น SDK เวอร์ชันใหม่ได้โดยไม่ต้องเปลี่ยนโค้ด Firebase ทั้งหมดในคราวเดียว คุณสามารถอัปเกรดเป็นโมดูลาร์ API ได้ทีละน้อย
ในขั้นตอนนี้ คุณจะอัปเกรดไลบรารี Firebase จาก v8 เป็นเวอร์ชันใหม่และเปลี่ยนโค้ดเพื่อใช้แพ็คเกจความเข้ากันได้ ในขั้นตอนต่อไปนี้ คุณจะได้เรียนรู้วิธีอัปเกรดเฉพาะโค้ด Firebase Auth เพื่อใช้ Modular API ก่อน จากนั้นจึงอัปเกรดโค้ด Firestore
เมื่อสิ้นสุดแต่ละขั้นตอน คุณควรจะสามารถคอมไพล์และรันแอปได้โดยไม่เกิดความเสียหาย และเห็นขนาดมัดที่ลดลงเมื่อเราย้ายแต่ละผลิตภัณฑ์
รับ SDK ใหม่
ค้นหาส่วนการขึ้นต่อกันใน package.json
และแทนที่ด้วยส่วนต่อไปนี้:
แพ็คเกจ.json
"dependencies": {
"firebase": "^9.0.0"
}
ติดตั้งการอ้างอิงอีกครั้ง
เนื่องจากเราเปลี่ยนเวอร์ชันของการขึ้นต่อกัน เราจำเป็นต้องรัน npm install
อีกครั้งเพื่อรับการขึ้นต่อกันเวอร์ชันใหม่
เปลี่ยนเส้นทางการนำเข้า
แพ็คเกจความเข้ากันได้จะถูกเปิดเผยภายใต้ submodule firebase/compat
ดังนั้นเราจะอัปเดตเส้นทางการนำเข้าตาม:
- ไปที่ไฟล์
src/firebase.ts
- แทนที่การนำเข้าที่มีอยู่ด้วยการนำเข้าต่อไปนี้:
src/firebase.ts
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
ตรวจสอบการทำงานของแอป
- รัน
npm run build
เพื่อสร้างแอปใหม่ - เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:8080 หรือรีเฟรชแท็บที่มีอยู่
- เล่นกับแอพ ทุกอย่างควรจะยังคงทำงานอยู่
5. อัปเกรด Auth เพื่อใช้ Modular API
คุณจะอัปเกรดผลิตภัณฑ์ Firebase ตามลำดับใดก็ได้ ใน Codelab นี้ คุณจะต้องอัปเกรด Auth ก่อนเพื่อเรียนรู้แนวคิดพื้นฐานเนื่องจาก Auth API นั้นค่อนข้างง่าย การอัปเกรด Firestore มีส่วนเกี่ยวข้องมากกว่าเล็กน้อย และคุณจะได้เรียนรู้วิธีดำเนินการดังกล่าวต่อไป
อัปเดตการเริ่มต้นการตรวจสอบสิทธิ์
- ไปที่ไฟล์
src/firebase.ts
- เพิ่มการนำเข้าต่อไปนี้:
src/firebase.ts
import { initializeAuth, indexedDBLocalPersistence } from 'firebase/auth';
- ลบ
import 'firebase/compat/auth'.
- แทนที่
export const firebaseAuth = app.auth();
กับ:
src/firebase.ts
export const firebaseAuth = initializeAuth(app, { persistence: [indexedDBLocalPersistence] });
- ลบ
export type User = firebase.User;
ที่ส่วนท้ายของไฟล์User
จะถูกส่งออกโดยตรงในsrc/auth.ts
ซึ่งคุณจะเปลี่ยนแปลงต่อไป
อัพเดตรหัสยืนยันตัวตน
- ไปที่ไฟล์
src/auth.ts
- เพิ่มการนำเข้าต่อไปนี้ที่ด้านบนของไฟล์:
src/auth.ts
import {
signInAnonymously,
signOut,
onAuthStateChanged,
User
} from 'firebase/auth';
- ลบ
User
ออกจากimport { firebaseAuth, User } from './firebase';
เนื่องจากคุณได้นำเข้าUser
จาก'firebase/auth'.
แล้ว - อัปเดตฟังก์ชันเพื่อใช้ API แบบโมดูลาร์
ดังที่คุณได้เห็นแล้วก่อนหน้านี้เมื่อเราอัปเดตคำสั่งการนำเข้า แพ็คเกจในเวอร์ชัน 9 ได้รับการจัดระเบียบตามฟังก์ชันที่คุณสามารถนำเข้าได้ ตรงกันข้ามกับ API เวอร์ชัน 8 ซึ่งอิงตามเนมสเปซแบบ dot-chained และรูปแบบบริการ การจัดระเบียบโค้ดแบบใหม่นี้ทำให้สามารถเขย่าโค้ดที่ไม่ได้ใช้ได้ เนื่องจากช่วยให้เครื่องมือสร้างสามารถวิเคราะห์โค้ดที่ใช้และโค้ดที่ไม่ได้ใช้
ในเวอร์ชัน 9 บริการจะถูกส่งผ่านเป็นอาร์กิวเมนต์แรกไปยังฟังก์ชัน Services คือออบเจ็กต์ที่คุณได้รับจากการเริ่มต้นบริการ 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';
ตรวจสอบการทำงานของแอป
- รัน
npm run build
เพื่อสร้างแอปใหม่ - เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:8080 หรือรีเฟรชแท็บที่มีอยู่
- เล่นกับแอพ ทุกอย่างควรจะยังคงทำงานอยู่
ตรวจสอบขนาดมัด
- เปิด Chrome DevTools
- สลับไปที่แท็บ เครือข่าย
- รีเฟรชเพจเพื่อบันทึกคำขอเครือข่าย
- มองหา main.js และตรวจสอบขนาดของมัน คุณได้ลดขนาดบันเดิลลง 100KB (36 KB gzipped) หรือเล็กลงประมาณ 22% โดยการเปลี่ยนโค้ดเพียงไม่กี่บรรทัด! ไซต์ยังโหลดเร็วขึ้น 0.75 วินาทีด้วยการเชื่อมต่อ 3g ที่ช้า
6. อัปเกรดแอป Firebase และ Firestore เพื่อใช้ Modular API
อัปเดตการเริ่มต้น Firebase
- ไปที่ไฟล์
src/firebase.ts.
- แทนที่
import firebase from 'firebase/compat/app';
กับ:
src/firebase.ts
import { initializeApp } from 'firebase/app';
- แทนที่
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.appspot.com",
messagingSenderId: "875614679042",
appId: "1:875614679042:web:5813c3e70a33e91ba0371b"
});
อัปเดตการเริ่มต้น Firestore
- ในไฟล์เดียวกัน
src/firebase.ts,
ให้แทนที่import 'firebase/compat/firestore';
กับ
src/firebase.ts
import { getFirestore } from 'firebase/firestore';
- แทนที่
export const firestore = app.firestore();
กับ:
src/firebase.ts
export const firestore = getFirestore();
- ลบบรรทัดทั้งหมดหลัง "
export const firestore = ...
"
อัพเดทการนำเข้า
- เปิดไฟล์
src/services.ts.
- ลบ
FirestoreFieldPath
,FirestoreFieldValue
และQuerySnapshot
จากการนำเข้า ตอนนี้การนำเข้าจาก'./firebase'
ควรมีลักษณะดังนี้:
src/services.ts
import { firestore } from './firebase';
- นำเข้าฟังก์ชันและประเภทที่คุณจะใช้ที่ด้านบนของไฟล์:
**src/services.ts**
import {
collection,
getDocs,
doc,
setDoc,
arrayUnion,
arrayRemove,
onSnapshot,
query,
where,
documentId,
QuerySnapshot
} from 'firebase/firestore';
อัปเดตการค้นหา()
- สร้างการอ้างอิงถึงคอลเลกชันที่มีสัญลักษณ์ทั้งหมด:
src/services.ts
const tickersCollRef = collection(firestore, 'current');
- ใช้
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()
- ใช้
doc()
เพื่อสร้างเอกสารอ้างอิงถึงรายการเฝ้าดูของผู้ใช้ก่อน จากนั้นฟังการเปลี่ยนแปลงรายการเฝ้าดูโดยใช้onSnapshot()
:
src/services.ts
const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
const unsubscribe = onSnapshot(watchlistRef, snapshot => {
/* subscribe to ticker price changes */
});
- เมื่อคุณมีสัญลักษณ์ในรายการเฝ้าดูแล้ว ให้ใช้
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() สำหรับการใช้งานที่สมบูรณ์
อัปเดตการสมัครสมาชิกToAllTickerChanges()
ขั้นแรก คุณจะต้องใช้ 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);
});
}
ตรวจสอบการทำงานของแอป
- รัน
npm run build
เพื่อสร้างแอปใหม่ - เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:8080 หรือรีเฟรชแท็บที่มีอยู่
- เล่นกับแอพ ทุกอย่างควรจะยังคงทำงานอยู่
ตรวจสอบขนาดมัด
- เปิด Chrome DevTools
- สลับไปที่แท็บ เครือข่าย
- รีเฟรชเพจเพื่อบันทึกคำขอเครือข่าย
- มองหา
main.js
และตรวจสอบขนาดของมัน เปรียบเทียบกับขนาดบันเดิลเดิมอีกครั้ง - เราได้ลดขนาดบันเดิลลงกว่า 200KB (63.8 KB gzipped) หรือเล็กลง 50% ซึ่งแปลว่าโหลดเร็วขึ้น 1.3 วินาที!
7. ใช้ Firestore Lite เพื่อเพิ่มความเร็วในการเรนเดอร์หน้าแรก
Firestore Lite คืออะไร?
Firestore SDK นำเสนอแคชที่ซับซ้อน การสตรีมแบบเรียลไทม์ พื้นที่จัดเก็บถาวร การซิงค์ออฟไลน์แบบหลายแท็บ การลองใหม่ การทำงานพร้อมกันในแง่ดี และอื่นๆ อีกมากมาย ดังนั้นจึงมีขนาดค่อนข้างใหญ่ แต่คุณอาจต้องการรับข้อมูลเพียงครั้งเดียว โดยไม่ต้องใช้ฟีเจอร์ขั้นสูงใดๆ ในกรณีเหล่านั้น Firestore ได้สร้างโซลูชันที่เรียบง่ายและเบา ซึ่งเป็นแพ็คเกจใหม่ล่าสุด — Firestore Lite
กรณีการใช้งานที่ยอดเยี่ยมอย่างหนึ่งสำหรับ Firestore Lite คือการเพิ่มประสิทธิภาพการแสดงผลหน้าแรก โดยคุณเพียงแค่ต้องรู้ว่าผู้ใช้เข้าสู่ระบบหรือไม่ จากนั้นจึงอ่านข้อมูลบางส่วนจาก Firetore เพื่อแสดง
ในขั้นตอนนี้ คุณจะได้เรียนรู้วิธีใช้ Firestore lite เพื่อลดขนาดบันเดิลเพื่อเพิ่มความเร็วในการเรนเดอร์หน้าแรก จากนั้นโหลด Firestore SDK หลักแบบไดนามิกเพื่อสมัครรับการอัปเดตแบบเรียลไทม์
คุณจะปรับโครงสร้างโค้ดใหม่เป็น:
- ย้ายบริการแบบเรียลไทม์ไปยังไฟล์แยกต่างหาก เพื่อให้สามารถโหลดบริการแบบไดนามิกได้โดยใช้การนำเข้าแบบไดนามิก
- สร้างฟังก์ชันใหม่เพื่อใช้ Firestore Lite เพื่อดึงข้อมูลรายการเฝ้าดูและราคาหุ้น
- ใช้ฟังก์ชัน Firestore Lite ใหม่เพื่อดึงข้อมูลเพื่อสร้างการแสดงผลหน้าแรก จากนั้นโหลดบริการแบบเรียลไทม์แบบไดนามิกเพื่อฟังการอัปเดตแบบเรียลไทม์
ย้ายบริการแบบเรียลไทม์ไปยังไฟล์ใหม่
- สร้างไฟล์ใหม่ชื่อ
src/services.realtime.ts.
- ย้ายฟังก์ชัน
subscribeToTickerChanges()
และsubscribeToAllTickerChanges()
จากsrc/services.ts
ไปยังไฟล์ใหม่ - เพิ่มการนำเข้าที่จำเป็นที่ด้านบนของไฟล์ใหม่
คุณยังต้องทำการเปลี่ยนแปลงบางอย่างที่นี่:
- ขั้นแรก สร้างอินสแตนซ์ Firestore จาก Firestore SDK หลักที่ด้านบนของไฟล์เพื่อใช้ในฟังก์ชันต่างๆ คุณไม่สามารถนำเข้าอินสแตนซ์ Firestore จาก
firebase.ts
ที่นี่ได้ เนื่องจากคุณจะเปลี่ยนเป็นอินสแตนซ์ Firestore Lite ได้ในไม่กี่ขั้นตอน ซึ่งจะใช้สำหรับการแสดงผลหน้าแรกเท่านั้น - ประการที่สอง กำจัดตัวแปร
firstload
และ if block ที่ป้องกันไว้ ฟังก์ชันการทำงานจะถูกย้ายไปยังฟังก์ชันใหม่ที่คุณจะสร้างขึ้นในขั้นตอนถัดไป
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 เพื่อดึงข้อมูล
- เปิด
src/services.ts.
- เปลี่ยนเส้นทางการนำเข้าจาก
'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';
- เพิ่มฟังก์ชันเพื่อดึงข้อมูลที่จำเป็นสำหรับการแสดงผลหน้าแรกโดยใช้ 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);
}
- เปิด
src/firebase.ts
และเปลี่ยนเส้นทางการนำเข้าจาก'firebase/firestore'
เป็น'firebase/firestore/lite':
src/firebase.ts
import { getFirestore } from 'firebase/firestore/lite';
ผูกไว้ด้วยกัน
- เปิด
src/main.ts.
- คุณจะต้องมีฟังก์ชันที่สร้างขึ้นใหม่เพื่อดึงข้อมูลสำหรับการแสดงผลหน้าแรก และฟังก์ชันตัวช่วยสองสามตัวเพื่อจัดการสถานะแอป ตอนนี้อัปเดตการนำเข้า:
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';
- โหลด
src/services.realtime
โดยใช้การนำเข้าแบบไดนามิกที่ด้านบนของไฟล์ VariableloadRealtimeService
คือคำมั่นสัญญาที่จะแก้ไขด้วยบริการแบบเรียลไทม์เมื่อโหลดโค้ดแล้ว คุณจะใช้ในภายหลังเพื่อสมัครรับการอัปเดตแบบเรียลไทม์
src/main.ts
const loadRealtimeService = import('./services.realtime');
loadRealtimeService.then(() => {
setRealtimeServicesLoaded(true);
});
- เปลี่ยนการเรียกกลับของ
onUserChange()
เป็นฟังก์ชันasync
เพื่อให้เราสามารถใช้await
ในส่วนของฟังก์ชัน:
src/main.ts
onUserChange(async user => {
// callback body
});
- ตอนนี้ดึงข้อมูลเพื่อสร้างการแสดงผลหน้าแรกโดยใช้ฟังก์ชันใหม่ที่เราสร้างขึ้นในขั้นตอนก่อนหน้า
ในการเรียกกลับ 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
}
}
- ในบล็อก 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 สำหรับโค้ดที่เสร็จสมบูรณ์
ตรวจสอบการทำงานของแอป
- รัน
npm run build
เพื่อสร้างแอปใหม่ - เปิดแท็บเบราว์เซอร์ไปที่ http://localhost:8080 หรือรีเฟรชแท็บที่มีอยู่
ตรวจสอบขนาดมัด
- เปิด Chrome Devtools
- สลับไปที่แท็บ เครือข่าย
- รีเฟรชเพจเพื่อบันทึกคำขอเครือข่าย
- มองหา
main.js
และตรวจสอบขนาดของมัน - ตอนนี้มีขนาดเพียง 115KB (34.5KB gzipped) ซึ่งมีขนาดเล็กกว่าขนาดบันเดิลเดิมถึง 75% ซึ่งก็คือ 446KB(138KB gzipped)! ด้วยเหตุนี้ ไซต์จึงโหลดเร็วขึ้นกว่า 2 วินาทีบนการเชื่อมต่อ 3G ซึ่งเป็นการปรับปรุงประสิทธิภาพและประสบการณ์ผู้ใช้ที่ยอดเยี่ยม!
8. ขอแสดงความยินดี
ยินดีด้วย คุณอัปเกรดแอปสำเร็จแล้วและทำให้มันเล็กลงและเร็วขึ้น!
คุณใช้แพ็คเกจที่เข้ากันได้เพื่ออัปเกรดแอปทีละชิ้น และใช้ Firestore Lite เพื่อเพิ่มความเร็วในการเรนเดอร์หน้าแรก จากนั้นโหลด Firestore หลักแบบไดนามิกเพื่อสตรีมการเปลี่ยนแปลงราคา
คุณยังลดขนาดบันเดิลและปรับปรุงเวลาในการโหลดตลอดหลักสูตร Codelab นี้ด้วย:
main.js | ขนาดทรัพยากร (kb) | ขนาดไฟล์ gzip (kb) | เวลาในการโหลด (มากกว่า 3g ช้า) |
v8 | 446 | 138 | 4.92 |
รองรับ v9 | 429 | 124 | 4.65 |
v9 การรับรองความถูกต้องแบบโมดูลาร์เท่านั้น | 348 | 102 | 4.2 |
v9 แบบโมดูลาร์เต็มรูปแบบ | 244 | 74.6 | 3.66 |
v9 แบบแยกส่วนอย่างสมบูรณ์ + Firestore lite | 117 | 34.9 | 2.88 |
ตอนนี้คุณรู้ขั้นตอนสำคัญที่จำเป็นในการอัปเกรดเว็บแอปที่ใช้ v8 Firebase JS SDK เพื่อใช้ JS SDK แบบโมดูลาร์ใหม่