อัปเกรดจาก API ที่มีเนมสเปซเป็นแอปพลิเคชันแบบโมดูล

แอปที่ใช้ Firebase Web API ที่มี Namespace ใดๆ จากไลบรารี compat ย้อนกลับไปจนถึงเวอร์ชัน 8 หรือก่อนหน้า ควรพิจารณาย้ายข้อมูลไปยัง API แบบแยกส่วนโดยใช้คำแนะนำในคู่มือนี้

คู่มือนี้ถือว่าคุณคุ้นเคยกับ API ที่มี Namespace และจะใช้ประโยชน์จาก Module Bundler เช่น Webpack หรือ Rollup สำหรับการอัปเกรดและการพัฒนาแอปแบบแยกส่วนอย่างต่อเนื่อง

เราขอแนะนำอย่างยิ่งให้ใช้ Module Bundler ในสภาพแวดล้อมการพัฒนา หากไม่ใช้ คุณจะใช้ประโยชน์หลักของ API แบบแยกส่วนในการลดขนาดแอปไม่ได้ คุณจะต้องใช้ npm หรือ yarn เพื่อติดตั้ง SDK

ขั้นตอนการอัปเกรดในคู่มือนี้จะอิงตามเว็บแอปสมมติที่ ใช้ SDK ของ Authentication และ Cloud Firestore เมื่อทำตามตัวอย่าง คุณจะเชี่ยวชาญแนวคิดและขั้นตอนการปฏิบัติที่จำเป็นในการอัปเกรด Firebase Web SDK ที่รองรับทั้งหมด

เกี่ยวกับไลบรารีที่มี Namespace (compat)

Firebase Web SDK มีไลบรารี 2 ประเภทดังนี้

  • แบบแยกส่วน - พื้นผิว API ใหม่ที่ออกแบบมาเพื่อช่วยในการทำ Tree-Shaking (การนำโค้ดที่ไม่ได้ใช้ออก) เพื่อให้เว็บแอปมีขนาดเล็กและทำงานได้เร็วที่สุด
  • ที่มี Namespace (compat) - พื้นผิว API ที่คุ้นเคยซึ่งเข้ากันได้กับ SDK เวอร์ชันก่อนหน้าอย่างสมบูรณ์ ทำให้คุณอัปเกรดได้โดยไม่ต้องเปลี่ยนโค้ด Firebase ทั้งหมดพร้อมกัน ไลบรารี Compat มีข้อดีด้านขนาดหรือประสิทธิภาพเล็กน้อยหรือไม่มีเลยเมื่อเทียบกับไลบรารีที่มี Namespace

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

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

เกี่ยวกับการอัปเกรด

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

  1. เพิ่มไลบรารีแบบแยกส่วนและไลบรารี Compat ลงในแอป
  2. อัปเดตคำสั่งนำเข้าในโค้ดเป็น Compat
  3. ปรับโครงสร้างโค้ดสำหรับผลิตภัณฑ์เดียว (เช่น Authentication) เป็น สไตล์แบบแยกส่วน
  4. ไม่บังคับ: ในขั้นตอนนี้ ให้นำไลบรารี Compat ของ Authentication และโค้ด Compat สำหรับ Authentication ออกเพื่อ รับประโยชน์ด้านขนาดแอปสำหรับการ Authentication ก่อนดำเนินการต่อ
  5. ปรับโครงสร้างฟังก์ชันสำหรับแต่ละผลิตภัณฑ์ (เช่น Cloud Firestore, FCM, ฯลฯ) เป็นสไตล์แบบแยกส่วน โดยคอมไพล์และ ทดสอบจนกว่าทุกส่วนจะเสร็จสมบูรณ์
  6. อัปเดตโค้ดการเริ่มต้นเป็นสไตล์แบบแยกส่วน
  7. นำคำสั่ง Compat และโค้ด Compat ที่เหลือทั้งหมดออกจากแอป

รับ SDK เวอร์ชันล่าสุด

หากต้องการเริ่มต้นใช้งาน ให้รับไลบรารีแบบแยกส่วนและไลบรารี Compat โดยใช้ npm ดังนี้

npm i firebase@12.15.0

# OR

yarn add firebase@12.15.0

อัปเดตการนำเข้าเป็น Compat

หากต้องการให้โค้ดทำงานได้ต่อไปหลังจากอัปเดตการขึ้นต่อกัน ให้เปลี่ยนคำสั่งนำเข้าเพื่อใช้เวอร์ชัน "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 ที่มี Namespace จะอิงตาม Namespace ที่เชื่อมต่อด้วยจุดและรูปแบบบริการ แต่แนวทางแบบแยกส่วนหมายความว่าโค้ดของคุณจะจัดระเบียบโดยหลักๆ แล้วจะอิงตามฟังก์ชัน ใน API แบบแยกส่วน แพ็กเกจ firebase/app และแพ็กเกจอื่นๆ จะไม่แสดงการส่งออกที่ครอบคลุมซึ่งมีเมธอดทั้งหมดจากแพ็กเกจ แต่แพ็กเกจจะส่งออกฟังก์ชันแต่ละรายการแทน

ใน API แบบแยกส่วน ระบบจะส่งบริการเป็นอาร์กิวเมนต์แรก จากนั้นฟังก์ชันจะใช้รายละเอียดของบริการเพื่อดำเนินการที่เหลือ มาดูวิธีการทำงานนี้ใน 2 ตัวอย่างที่ปรับโครงสร้างการเรียกใช้ API ของ Authentication และ Cloud Firestore

ตัวอย่างที่ 1: การปรับโครงสร้างฟังก์ชัน Authentication

ก่อน: compat

โค้ด Compat เหมือนกับโค้ดที่มี Namespace แต่การนำเข้ามีการเปลี่ยนแปลง

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 ที่มี Namespace แต่เป็นฟังก์ชันอิสระที่ใช้ auth เป็นพารามิเตอร์แรก

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

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

อัปเดตการจัดการเมธอด getRedirectResult ของการตรวจสอบสิทธิ์

API แบบแยกส่วนมีการเปลี่ยนแปลงที่ทำให้เกิดข้อผิดพลาดใน getRedirectResult เมื่อไม่มีการเรียกใช้การดำเนินการเปลี่ยนเส้นทาง API แบบแยกส่วนจะแสดงผล null ซึ่งแตกต่างจาก API ที่มี Namespace ซึ่งแสดงผล 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());
});

อัปเดตรีเฟอเรนซ์เป็น DocumentSnapshot.exists ของ Firestore

API แบบแยกส่วนมีการเปลี่ยนแปลงที่ทำให้เกิดข้อผิดพลาด โดยพร็อพเพอร์ตี้ firestore.DocumentSnapshot.exists เปลี่ยนเป็น เมธอด ฟังก์ชันการทำงานโดยพื้นฐานแล้วจะเหมือนกัน (ทดสอบว่ามีเอกสารอยู่หรือไม่) แต่คุณต้องปรับโครงสร้างโค้ดเพื่อใช้เมธอดใหม่กว่าดังที่แสดง

ก่อน:compat

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

หลัง: แบบแยกส่วน

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

ตัวอย่างที่ 3: การรวมสไตล์โค้ดที่มี Namespace และแบบแยกส่วน

การใช้ไลบรารี Compat ระหว่างการอัปเกรดช่วยให้คุณใช้โค้ดที่มี Namespace ควบคู่ไปกับโค้ดที่ปรับโครงสร้างใหม่สำหรับ API แบบแยกส่วนได้ ซึ่งหมายความว่าคุณสามารถเก็บ โค้ดที่มี Namespace ที่มีอยู่สำหรับ Cloud Firestore ไว้ขณะที่ปรับโครงสร้าง Authentication หรือโค้ด Firebase SDK อื่นๆ เป็น สไตล์แบบแยกส่วน และยังคงคอมไพล์แอปด้วยโค้ดทั้ง 2 สไตล์ได้สำเร็จ เช่นเดียวกับโค้ด API ที่มี Namespace และแบบแยกส่วน ภายใน ผลิตภัณฑ์ เช่น Cloud Firestore โดยโค้ดสไตล์ใหม่และเก่าสามารถอยู่ร่วมกันได้ ตราบใดที่คุณ นำเข้าแพ็กเกจ Compat

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

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

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

อัปเดตโค้ดการเริ่มต้น

อัปเดตโค้ดการเริ่มต้นของแอปให้ใช้ไวยากรณ์แบบแยกส่วน คุณต้องอัปเดตโค้ดนี้ หลังจากปรับโครงสร้างโค้ดทั้งหมดในแอปเสร็จแล้ว เนื่องจาก firebase.initializeApp() จะเริ่มต้นสถานะส่วนกลาง สำหรับทั้ง API แบบ Compat และแบบแยกส่วน ในขณะที่ ฟังก์ชันinitializeApp()แบบแยกส่วนจะเริ่มต้นสถานะสำหรับแบบแยกส่วนเท่านั้น

ก่อน: compat

import firebase from "firebase/compat/app"

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

หลัง: แบบแยกส่วน

import { initializeApp } from "firebase/app"

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

นำโค้ด Compat ออก

หากต้องการรับประโยชน์ด้านขนาดจาก API แบบแยกส่วน คุณควรแปลงการเรียกใช้ทั้งหมดเป็นสไตล์แบบแยกส่วนที่แสดงด้านบน และนำคำสั่ง import "firebase/compat/* ทั้งหมดออกจากโค้ด เมื่อดำเนินการเสร็จแล้ว จะไม่มีการอ้างอิง Namespace ส่วนกลาง firebase.* หรือโค้ดอื่นๆ ในสไตล์ API ที่มี Namespace อีกต่อไป

การใช้ไลบรารี Compat จากหน้าต่าง

API แบบแยกส่วนได้รับการเพิ่มประสิทธิภาพให้ทำงานร่วมกับโมดูลแทนออบเจ็กต์ window ของเบราว์เซอร์ ไลบรารีเวอร์ชันก่อนหน้าอนุญาตให้โหลดและจัดการ Firebase ได้โดยใช้ Namespace window.firebase เราไม่แนะนำให้ใช้วิธีนี้ต่อไปเนื่องจากไม่สามารถนำโค้ดที่ไม่ได้ใช้ออกได้ อย่างไรก็ตาม JavaScript SDK เวอร์ชัน Compat จะทำงานร่วมกับ window สำหรับนักพัฒนาแอปที่ไม่ต้องการเริ่มเส้นทางการอัปเกรดแบบแยกส่วนในทันที

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

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

ข้อดีและข้อจำกัดของ SDK แบบแยกส่วน

SDK ที่แยกส่วนอย่างสมบูรณ์มีข้อดีดังต่อไปนี้เมื่อเทียบกับเวอร์ชันก่อนหน้า

  • SDK แบบแยกส่วนช่วยลดขนาดแอปได้อย่างมาก โดยใช้รูปแบบโมดูล JavaScript ที่ทันสมัย ซึ่งช่วยให้สามารถใช้แนวทางปฏิบัติ "Tree-Shaking" ที่คุณนำเข้าเฉพาะอาร์ติแฟกต์ที่แอปต้องการ การทำ Tree-Shaking ด้วย SDK แบบแยกส่วนอาจทำให้แอปมีขนาดเล็กลงถึง 80% เมื่อเทียบกับแอปที่เทียบเคียงกันซึ่งสร้างขึ้นโดยใช้ API ที่มี Namespace ทั้งนี้ขึ้นอยู่กับแอปของคุณ
  • SDK แบบแยกส่วนจะได้รับประโยชน์จากการพัฒนาฟีเจอร์อย่างต่อเนื่อง ในขณะที่ API ที่มี Namespace จะไม่ได้รับประโยชน์ดังกล่าว