Mengupgrade dari API dengan namespace ke API modular

Aplikasi yang saat ini menggunakan Firebase Web API dengan namespace, mulai dari library compat hingga versi 8 atau yang lebih lama, sebaiknya melakukan migrasi ke API modular dengan mengikuti petunjuk dalam panduan ini.

Panduan ini mengasumsikan bahwa Anda sudah memahami API dengan namespace dan akan memanfaatkan pemaket modul seperti webpack atau Rollup untuk upgrade dan pengembangan aplikasi modular yang sedang berjalan.

Kami sangat menyarankan penggunaan pemaket modul di lingkungan pengembangan Anda. Jika tidak menggunakannya, Anda tidak akan bisa mendapatkan manfaat utama API modular berupa ukuran aplikasi yang lebih kecil. Anda memerlukan npm atau yarn untuk menginstal SDK.

Langkah-langkah upgrade dalam panduan ini akan didasarkan pada aplikasi web fiktif yang menggunakan Authentication dan Cloud Firestore SDK. Dengan mengikuti contoh-contoh di bawah, Anda akan menguasai konsep dan langkah praktis yang diperlukan untuk mengupgrade semua Firebase Web SDK yang didukung.

Tentang library (compat) dengan namespace

Ada dua jenis library yang tersedia untuk Firebase Web SDK:

  • Modular - platform API baru yang didesain untuk memfasilitasi tree shaking (penghapusan kode yang tidak digunakan) agar aplikasi web Anda menjadi sekecil dan secepat mungkin.
  • Dengan namespace (compat) - platform API yang tidak asing yang sepenuhnya kompatibel dengan versi SDK sebelumnya, sehingga Anda dapat melakukan upgrade tanpa mengubah semua kode Firebase Anda sekaligus. Dibandingkan library dengan namespace, keunggulan library compat dalam hal ukuran atau performa tidak berbeda jauh.

Panduan ini mengasumsikan bahwa Anda akan memanfaatkan library compat untuk memfasilitasi upgrade. Dengan library ini, Anda dapat terus menggunakan kode dengan namespace serta kode yang difaktorkan ulang untuk API modular. Artinya, Anda dapat mengompilasi dan men-debug aplikasi dengan lebih mudah saat melakukan proses upgrade.

Untuk aplikasi yang tidak banyak berhubungan dengan Firebase Web SDK, misalnya aplikasi yang hanya melakukan panggilan sederhana ke Authentication API, mungkin akan lebih praktis untuk melakukan pemfaktoran ulang kode dengan namespace tanpa menggunakan library compat. Jika mengupgrade aplikasi semacam ini, Anda dapat mengikuti petunjuk dalam panduan ini untuk "API modular" tanpa menggunakan library compat.

Tentang proses upgrade

Setiap langkah pada proses upgrade tercakup sedemikian rupa agar Anda dapat menyelesaikan pengeditan sumber untuk aplikasi, lalu mengompilasi dan menjalankannya tanpa menimbulkan kerusakan. Singkatnya, berikut yang akan Anda lakukan untuk mengupgrade aplikasi:

  1. Tambahkan library modular dan library compat ke aplikasi Anda.
  2. Perbarui pernyataan impor dalam kode ke compat.
  3. Faktorkan ulang kode untuk satu produk (misalnya, Authentication) ke gaya modular.
  4. Opsional: pada tahap ini, hapus library compat Authentication dan kode compat untuk Authentication guna merealisasikan manfaat ukuran aplikasi untuk Authentication sebelum melanjutkan.
  5. Faktorkan ulang fungsi untuk setiap produk (misalnya, Cloud Firestore, FCM, dll.) ke gaya modular, sambil melakukan kompilasi dan pengujian sampai semua area selesai.
  6. Perbarui kode inisialisasi menjadi gaya modular.
  7. Hapus semua pernyataan compat dan kode compat yang tersisa dari aplikasi Anda.

Mendapatkan SDK versi terbaru

Untuk memulai, dapatkan library modular dan library compat menggunakan npm:

npm i firebase@10.4.0

# OR

yarn add firebase@10.4.0

Memperbarui pernyataan impor ke compat

Agar kode tetap berfungsi setelah dependensi diperbarui, ubah pernyataan impor agar menggunakan versi "compat" setiap impor. Contoh:

Sebelum: versi 8 atau yang lebih lama

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

Sesudah: compat

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

Memfaktorkan ulang ke gaya modular

Meskipun API dengan namespace didasarkan pada pola layanan dan namespace menggunakan dot-chaining, pendekatan modular berarti bahwa kode Anda akan diatur berdasarkan fungsi. Dalam API modular, paket firebase/app dan paket lainnya tidak menampilkan ekspor komprehensif yang berisi semua metode dari paket tersebut. Sebagai gantinya, paket tersebut mengekspor fungsi satu per satu.

Dalam API modular, layanan diteruskan sebagai argumen pertama. Selanjutnya, fungsi menggunakan detail layanan untuk mengerjakan sisanya. Mari pelajari cara kerjanya di dua contoh yang memfaktorkan ulang panggilan ke Authentication dan Cloud Firestore API.

Contoh 1: memfaktorkan ulang fungsi Authentication

Sebelum: compat

Kode compat identik dengan kode dengan namespace, tetapi pernyataan impornya telah berubah.

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

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

Sesudah: modular

Fungsi getAuth menggunakan firebaseApp sebagai parameter pertama. Fungsi onAuthStateChanged tidak dirantai dari instance auth seperti pada API dengan namespace. Sebaliknya, fungsi tersebut adalah fungsi bebas yang menggunakan auth sebagai parameter pertamanya.

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

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

Memperbarui penanganan metode Auth getRedirectResult

API modular memperkenalkan perubahan yang dapat menyebabkan gangguan di getRedirectResult. Jika tidak ada operasi pengalihan yang dipanggil, API modular akan menampilkan null, bukan API dengan namespace, yang menampilkan UserCredential dengan pengguna null.

Sebelum: compat

const result = await auth.getRedirectResult()
if (result.user === null && result.credential === null) {
  return null;
}
return result;

Sesudah: modular

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;

Contoh 2: memfaktorkan ulang fungsi Cloud Firestore

Sebelum: 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);
    });

Sesudah: modular

Fungsi getFirestore menggunakan firebaseApp sebagai parameter pertamanya, yang ditampilkan dari initializeApp dalam contoh sebelumnya. Perhatikan bahwa kode untuk membentuk kueri sangatlah berbeda dalam API modular. Tidak ada pembentukan rantai, dan metode seperti query atau where kini diekspos sebagai fungsi bebas.

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

Memperbarui referensi ke DocumentSnapshot.exists Firestore

API modular memperkenalkan perubahan yang dapat menyebabkan gangguan, yaitu properti firestore.DocumentSnapshot.exists telah berubah menjadi metode. Fungsi ini pada dasarnya sama (menguji apakah dokumen ada atau tidak), tetapi Anda harus memfaktorkan ulang kode untuk menggunakan metode yang lebih baru seperti yang ditunjukkan di bawah:

Sebelum: compat

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

Sesudah: modular

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

Contoh 3: menggabungkan gaya kode dengan namespace dan gaya kode modular

Dengan menggunakan library compat selama proses upgrade, Anda dapat terus menggunakan kode dengan namespace bersama kode yang difaktorkan ulang untuk API modular. Ini berarti Anda dapat mempertahankan kode dengan namespace yang sudah ada untuk Cloud Firestore saat Anda memfaktorkan ulang kode Authentication atau Firebase SDK lainnya menjadi bergaya modular, dan tetap dapat mengompilasi aplikasi dengan kedua gaya kode. Hal yang sama berlaku untuk kode API dengan namespace dan modular dalam produk seperti Cloud Firestore. Gaya kode baru dan lama dapat beroperasi berdampingan, asalkan Anda mengimpor paket compat:

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

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

Perlu diingat bahwa, meskipun aplikasi akan tetap dapat dikompilasi, keunggulan ukuran aplikasi yang lebih kecil pada kode modular tidak akan Anda rasakan sebelum kode dan pernyataan compat sepenuhnya dihapus dari aplikasi.

Memperbarui kode inisialisasi

Perbarui kode inisialisasi aplikasi Anda agar menggunakan sintaksis modular. Anda harus memperbarui kode ini setelah menyelesaikan pemfaktoran ulang semua kode di aplikasi, karena firebase.initializeApp() menginisialisasi status global baik untuk API compat maupun modular, sedangkan fungsi initializeApp() modular hanya menginisialisasi status untuk modular.

Sebelum: compat

import firebase from "firebase/compat/app"

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

Sesudah: modular

import { initializeApp } from "firebase/app"

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

Menghapus kode compat

Untuk menikmati manfaat API modular dalam hal ukuran, Anda tetap harus mengonversi semua pemanggilan ke gaya modular yang ditunjukkan di atas dan menghapus semua pernyataan import "firebase/compat/* dari kode Anda. Setelah selesai, seharusnya tidak ada lagi referensi ke namespace global firebase.* atau kode lain dalam gaya API dengan namespace.

Menggunakan library compat dari jendela

API modular dioptimalkan untuk berfungsi dengan modul, bukan objek window browser. Versi library sebelumnya memungkinkan pemuatan dan pengelolaan Firebase menggunakan namespace window.firebase. Hal ini tidak direkomendasikan untuk ke depannya karena tidak memungkinkan penghapusan kode yang tidak digunakan. Namun, versi compat JavaScript SDK dapat berfungsi dengan window bagi developer yang memilih untuk tidak langsung memulai jalur upgrade modular.

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

Pada prinsipnya, library compat menggunakan kode modular dan menyediakan API yang sama seperti API dengan namespace. Artinya, Anda dapat melihat referensi API dengan namespace dan cuplikan kode dengan namespace untuk mengetahui detailnya. Metode ini tidak direkomendasikan untuk penggunaan jangka panjang, tetapi dapat digunakan sebagai awal untuk mengupgrade aplikasi ke library yang sepenuhnya modular.

Manfaat dan batasan SDK modular

SDK yang sepenuhnya modular memiliki keuntungan berikut dibandingkan versi sebelumnya:

  • SDK modular memungkinkan pemangkasan ukuran aplikasi secara drastis. Versi ini mengadopsi format Modul JavaScript modern, sehingga memungkinkan proses "tree shaking" yang mengimpor artefak yang dibutuhkan aplikasi saja. Bergantung pada aplikasi Anda, tree shaking dengan SDK modular dapat menghasilkan pemangkasan kilobyte hingga 80% dibandingkan aplikasi serupa yang dibangun menggunakan API dengan namespace.
  • SDK modular akan terus mendapatkan manfaat dari pengembangan fitur yang masih terus berlangsung, sedangkan API dengan namespace tidak.