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

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

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

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

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

เกี่ยวกับไลบรารีที่มีเนมสเปซ (compat)

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

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

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

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

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

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

ก่อน: compat

โค้ดที่เข้ากันได้จะเหมือนกับโค้ดที่มีเนมสเปซ แต่มีการเปลี่ยนแปลงการนำเข้า

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

Modular API จะมีการเปลี่ยนแปลงที่ไม่รองรับการทำงานย้อนหลังใน getRedirectResult เมื่อไม่มีการเรียกใช้การดำเนินการเปลี่ยนเส้นทาง Modular API จะแสดง null ซึ่งแตกต่างจาก Namespaced 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: การรวมรูปแบบโค้ดแบบ Namespace และแบบแยกส่วน

การใช้ไลบรารีความเข้ากันได้ในระหว่างการอัปเกรดจะช่วยให้คุณใช้โค้ดที่มี 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);

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

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

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