از API فضای نامی به برنامه مدولار ارتقا دهید

برنامه‌هایی که از هرگونه API وب Firebase با فضای نام، از کتابخانه‌های compat گرفته تا نسخه ۸ یا قبل‌تر، استفاده می‌کنند، باید با استفاده از دستورالعمل‌های این راهنما، مهاجرت به API ماژولار را در نظر بگیرند.

این راهنما فرض می‌کند که شما با API با فضای نام (namespaced API) آشنا هستید و از یک بسته نرم‌افزاری ماژول مانند webpack یا Rollup برای ارتقاء و توسعه مداوم برنامه‌های ماژولار استفاده خواهید کرد.

استفاده از یک module bundler در محیط توسعه‌تان اکیداً توصیه می‌شود. اگر از آن استفاده نکنید، نمی‌توانید از مزایای اصلی API ماژولار در کاهش حجم برنامه بهره‌مند شوید. برای نصب SDK به npm یا yarn نیاز دارید.

مراحل ارتقاء در این راهنما بر اساس یک برنامه وب فرضی خواهد بود که از SDK های Authentication و Cloud Firestore استفاده می‌کند. با کار کردن از طریق مثال‌ها، می‌توانید بر مفاهیم و مراحل عملی مورد نیاز برای ارتقاء همه SDK های وب پشتیبانی شده Firebase تسلط پیدا کنید.

درباره کتابخانه‌های namespaced ( compat )

دو نوع کتابخانه برای SDK وب فایربیس موجود است:

  • ماژولار - یک سطح API جدید که برای تسهیل tree-shaking (حذف کدهای استفاده نشده) طراحی شده است تا برنامه وب شما تا حد امکان کوچک و سریع شود.
  • Namespaced ( compat ) - یک سطح API آشنا که کاملاً با نسخه‌های قبلی SDK سازگار است و به شما امکان می‌دهد بدون تغییر یکباره تمام کد Firebase خود، آن را ارتقا دهید. کتابخانه‌های Compat نسبت به همتایان namespaced خود، از نظر اندازه یا عملکرد، مزیت کمی دارند یا اصلاً هیچ مزیتی ندارند.

این راهنما فرض می‌کند که شما از کتابخانه‌های compat برای تسهیل ارتقاء خود استفاده خواهید کرد. این کتابخانه‌ها به شما امکان می‌دهند در کنار کد بازسازی‌شده برای API ماژولار، از کد namespaced نیز استفاده کنید. این بدان معناست که می‌توانید در حین انجام فرآیند ارتقاء، برنامه خود را راحت‌تر کامپایل و اشکال‌زدایی کنید.

برای برنامه‌هایی که دسترسی بسیار کمی به SDK وب Firebase دارند - برای مثال، برنامه‌ای که فقط یک فراخوانی ساده به APIهای Authentication انجام می‌دهد - ممکن است بازسازی کد قدیمی‌تر با فضای نام بدون استفاده از کتابخانه‌های compat عملی باشد. اگر در حال ارتقاء چنین برنامه‌ای هستید، می‌توانید دستورالعمل‌های این راهنما را برای "API ماژولار" بدون استفاده از کتابخانه‌های compat دنبال کنید.

درباره فرآیند ارتقا

هر مرحله از فرآیند ارتقا به گونه‌ای محدود شده است که بتوانید ویرایش کد منبع برنامه خود را به پایان رسانده و سپس آن را بدون مشکل کامپایل و اجرا کنید. به طور خلاصه، در اینجا کارهایی که برای ارتقای یک برنامه انجام خواهید داد، آورده شده است:

  1. کتابخانه‌های ماژولار و کتابخانه‌های compat را به برنامه خود اضافه کنید.
  2. دستورات import را در کد خود برای compat به‌روزرسانی کنید.
  3. کد یک محصول واحد (مثلاً Authentication ) را به سبک ماژولار بازنویسی کنید.
  4. اختیاری: در این مرحله، قبل از ادامه، کتابخانه Authentication compat و کد compat مربوط به Authentication را حذف کنید تا از مزیت حجم برنامه برای Authentication بهره‌مند شوید.
  5. توابع هر محصول (مثلاً Cloud Firestore ، FCM و غیره) را به سبک ماژولار بازسازی کنید، کامپایل و آزمایش کنید تا همه قسمت‌ها تکمیل شوند.
  6. کد مقداردهی اولیه را به سبک ماژولار به‌روزرسانی کنید.
  7. تمام دستورات compat و کد compat باقی مانده را از برنامه خود حذف کنید.

آخرین نسخه SDK را دریافت کنید

برای شروع، کتابخانه‌های ماژولار و کتابخانه‌های compat را با استفاده از npm دریافت کنید:

npm i firebase@12.5.0

# OR

yarn add firebase@12.5.0

به‌روزرسانی واردات به compat

برای اینکه کد شما پس از به‌روزرسانی وابستگی‌ها همچنان به درستی کار کند، دستورات import خود را طوری تغییر دهید که از نسخه "compat" هر import استفاده کند. برای مثال:

قبل از: نسخه ۸ یا قبل از آن

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

بعد از: سازگار

// compat packages are API compatible with namespaced code
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

ریفکتور به سبک ماژولار

در حالی که APIهای namespaced بر اساس الگوی namespace و سرویس زنجیره‌ای نقطه‌ای هستند، رویکرد ماژولار به این معنی است که کد شما عمدتاً حول توابع سازماندهی می‌شود. در API ماژولار، پکیج firebase/app و سایر پکیج‌ها، export جامعی که شامل تمام متدهای پکیج باشد را برنمی‌گردانند. در عوض، پکیج‌ها توابع منفرد را export می‌کنند.

در API ماژولار، سرویس‌ها به عنوان اولین آرگومان ارسال می‌شوند و سپس تابع از جزئیات سرویس برای انجام بقیه کارها استفاده می‌کند. بیایید نحوه عملکرد این را در دو مثال که فراخوانی‌های refactor را به APIهای Authentication و Cloud Firestore فراخوانی می‌کنند، بررسی کنیم.

مثال ۱: بازسازی یک تابع Authentication

قبل از: سازگار

کد compat با کد namespaced یکسان است، اما importها تغییر کرده‌اند.

import firebase from "firebase/compat/app";
import "firebase/compat/auth";

const auth = firebase.auth();
auth.onAuthStateChanged(user => { 
  // Check for user status
});

بعد از: ماژولار

تابع getAuth ، firebaseApp به عنوان اولین پارامتر خود دریافت می‌کند. تابع onAuthStateChanged برخلاف API با فضای نام، به نمونه auth زنجیر نشده است؛ در عوض، یک تابع آزاد است که auth به عنوان اولین پارامتر خود دریافت می‌کند.

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

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

مدیریت به‌روزرسانی روش Auth getRedirectResult

API ماژولار یک تغییر اساسی در getRedirectResult ایجاد می‌کند. وقتی هیچ عملیات ریدایرکتی فراخوانی نشود، API ماژولار null برمی‌گرداند، برخلاف API با فضای نام که یک UserCredential با کاربر null برمی‌گرداند.

قبل از: سازگار

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;

مثال ۲: بازسازی یک تابع Cloud Firestore

قبل از: سازگار

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 به یک متد تغییر یافته است. عملکرد اساساً یکسان است (بررسی وجود یک سند) اما شما باید کد خود را برای استفاده از متد جدیدتر، همانطور که نشان داده شده است، بازسازی کنید:

قبل از: سازگار

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

بعد از: ماژولار

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

مثال ۳: ترکیب سبک‌های کد namespaced و modular

استفاده از کتابخانه‌های compat در حین ارتقا به شما این امکان را می‌دهد که در کنار کد بازسازی‌شده برای API ماژولار، از کد namespaced نیز استفاده کنید. این بدان معناست که می‌توانید کد namespaced موجود برای Cloud Firestore را در حین بازسازی Authentication یا سایر کدهای Firebase SDK به سبک ماژولار، حفظ کنید و همچنان برنامه خود را با هر دو سبک کد با موفقیت کامپایل کنید. همین امر در مورد کد namespaced و API ماژولار در محصولی مانند 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 سازگار و ماژولار مقداردهی اولیه می‌کند، در حالی که تابع modular initializeApp() فقط وضعیت را برای ماژولار مقداردهی اولیه می‌کند.

قبل از: سازگار

import firebase from "firebase/compat/app"

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

بعد از: ماژولار

import { initializeApp } from "firebase/app"

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

کد سازگاری را حذف کنید

برای درک مزایای اندازه API ماژولار، در نهایت باید تمام فراخوانی‌ها را به سبک ماژولار نشان داده شده در بالا تبدیل کنید و تمام دستورات import "firebase/compat/* را از کد خود حذف کنید. وقتی کار شما تمام شد، دیگر نباید هیچ ارجاعی به فضای نام جهانی firebase.* یا هر کد دیگری در سبک API با فضای نام وجود داشته باشد.

استفاده از کتابخانه compat از پنجره

API ماژولار برای کار با ماژول‌ها به جای شیء window مرورگر بهینه شده است. نسخه‌های قبلی این کتابخانه امکان بارگذاری و مدیریت Firebase را با استفاده از فضای نام window.firebase فراهم می‌کردند. این روش در آینده توصیه نمی‌شود زیرا امکان حذف کدهای استفاده نشده را فراهم نمی‌کند. با این حال، نسخه compat از SDK جاوا اسکریپت برای توسعه‌دهندگانی که ترجیح می‌دهند بلافاصله مسیر ارتقاء ماژولار را شروع نکنند، با window کار می‌کند.

<script src="https://www.gstatic.com/firebasejs/12.5.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/12.5.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/12.5.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 ماژولار، حجم برنامه را به طرز چشمگیری کاهش می‌دهد. این SDK از فرمت ماژول مدرن جاوا اسکریپت استفاده می‌کند و امکان «تغییر درخت» را فراهم می‌کند که در آن فقط مصنوعاتی را که برنامه شما نیاز دارد، وارد می‌کنید. بسته به برنامه شما، تغییر درخت با SDK ماژولار می‌تواند منجر به ۸۰٪ کیلوبایت کمتر نسبت به یک برنامه مشابه ساخته شده با استفاده از API با فضای نام شود.
  • SDK ماژولار همچنان از توسعه مداوم ویژگی‌ها بهره‌مند خواهد شد، در حالی که API با نام فضای نام‌گذاری شده این امکان را نخواهد داشت.