Nâng cấp từ API không gian tên lên ứng dụng mô-đun

Các ứng dụng sử dụng bất kỳ API web Firebase có không gian tên nào, từ thư viện compat trở về phiên bản 8 trở về trước, nên cân nhắc chuyển sang API mô-đun bằng cách làm theo hướng dẫn trong tài liệu này.

Tài liệu này giả định rằng bạn đã quen thuộc với API có không gian tên và sẽ tận dụng trình đóng gói mô-đun như webpack hoặc Rollup để nâng cấp và phát triển ứng dụng mô-đun liên tục.

Bạn nên sử dụng trình đóng gói mô-đun trong môi trường phát triển. Nếu không sử dụng, bạn sẽ không thể tận dụng các lợi ích chính của API mô-đun trong việc giảm kích thước ứng dụng. Bạn cần npm hoặc yarn để cài đặt SDK.

Các bước nâng cấp trong tài liệu này sẽ dựa trên một ứng dụng web tưởng tượng mà sử dụng SDK AuthenticationCloud Firestore. Bằng cách làm theo các ví dụ, bạn có thể nắm vững các khái niệm và bước thực tế cần thiết để nâng cấp tất cả các SDK web Firebase được hỗ trợ.

Giới thiệu về thư viện có không gian tên (compat)

Có 2 loại thư viện dành cho SDK web Firebase:

  • Mô-đun – một giao diện API mới được thiết kế để tạo điều kiện cho việc loại bỏ mã không dùng đến (tree-shaking) nhằm giúp ứng dụng web của bạn có kích thước nhỏ và nhanh nhất có thể.
  • Có không gian tên (compat) – một giao diện API quen thuộc, hoàn toàn tương thích với các phiên bản SDK trước đó, cho phép bạn nâng cấp mà không cần thay đổi toàn bộ mã Firebase cùng một lúc. Thư viện tương thích có ít hoặc không có lợi thế về kích thước hoặc hiệu suất so với các thư viện có không gian tên tương ứng.

Tài liệu này giả định rằng bạn sẽ tận dụng các thư viện tương thích để tạo điều kiện cho việc nâng cấp. Các thư viện này cho phép bạn tiếp tục sử dụng mã có không gian tên cùng với mã được tái cấu trúc cho API mô-đun. Điều này có nghĩa là bạn có thể biên dịch và gỡ lỗi ứng dụng dễ dàng hơn khi thực hiện quy trình nâng cấp

Đối với các ứng dụng có mức độ tiếp xúc rất nhỏ với SDK web Firebase (ví dụ: một ứng dụng chỉ thực hiện một lệnh gọi đơn giản đến API Authentication), bạn có thể tái cấu trúc mã có không gian tên cũ mà không cần sử dụng thư viện tương thích. Nếu đang nâng cấp một ứng dụng như vậy, bạn có thể làm theo hướng dẫn trong tài liệu này về "API mô-đun" mà không cần sử dụng thư viện tương thích.

Giới thiệu về quy trình nâng cấp

Mỗi bước của quy trình nâng cấp đều được giới hạn để bạn có thể hoàn tất việc chỉnh sửa nguồn cho ứng dụng , sau đó biên dịch và chạy ứng dụng mà không bị lỗi. Tóm lại, bạn sẽ làm như sau để nâng cấp ứng dụng:

  1. Thêm thư viện mô-đun và thư viện tương thích vào ứng dụng.
  2. Cập nhật câu lệnh nhập trong mã của bạn thành tương thích.
  3. Tái cấu trúc mã cho một sản phẩm (ví dụ: Authentication) theo kiểu mô-đun.
  4. Không bắt buộc: tại thời điểm này, hãy xoá thư viện tương thích Authentication và mã tương thích cho Authentication để nhận được lợi ích về kích thước ứng dụng cho Authentication trước khi tiếp tục.
  5. Tái cấu trúc các hàm cho từng sản phẩm (ví dụ: Cloud Firestore, FCM, v.v.) theo kiểu mô-đun, biên dịch và kiểm thử cho đến khi hoàn tất tất cả các khu vực.
  6. Cập nhật mã khởi chạy theo kiểu mô-đun.
  7. Xoá tất cả các câu lệnh tương thích và mã tương thích còn lại khỏi ứng dụng.

Tải phiên bản SDK mới nhất

Để bắt đầu, hãy tải thư viện mô-đun và thư viện tương thích bằng npm:

npm i firebase@12.10.0

# OR

yarn add firebase@12.10.0

Cập nhật tệp nhập thành tương thích

Để giữ cho mã của bạn hoạt động sau khi cập nhật các phần phụ thuộc, hãy thay đổi câu lệnh nhập để sử dụng phiên bản "tương thích" của mỗi tệp nhập. Ví dụ:

Trước: phiên bản 8 trở về trước

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

Sau: tương thích

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

Tái cấu trúc theo kiểu mô-đun

Mặc dù các API có không gian tên dựa trên không gian tên và mẫu dịch vụ được liên kết bằng dấu chấm, nhưng phương pháp mô-đun có nghĩa là mã của bạn sẽ được sắp xếp chủ yếu xung quanh các hàm. Trong API mô-đun, gói firebase/app và các gói khác không trả về một tệp xuất toàn diện chứa tất cả các phương thức từ gói. Thay vào đó, các gói xuất các hàm riêng lẻ.

Trong API mô-đun, các dịch vụ được truyền dưới dạng đối số đầu tiên và sau đó hàm sẽ sử dụng thông tin chi tiết của dịch vụ để thực hiện phần còn lại. Hãy xem xét cách hoạt động này trong 2 ví dụ tái cấu trúc các lệnh gọi đến API AuthenticationCloud Firestore.

Ví dụ 1: tái cấu trúc hàm Authentication

Trước: tương thích

Mã tương thích giống hệt mã có không gian tên, nhưng các tệp nhập đã thay đổi.

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

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

Sau: mô-đun

Hàm getAuth lấy firebaseApp làm tham số đầu tiên. Hàm onAuthStateChanged không được liên kết từ thực thể auth như trong API có không gian tên; thay vào đó, đây là một hàm miễn phí lấy auth làm tham số đầu tiên.

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

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

Cập nhật cách xử lý phương thức Xác thực getRedirectResult

API mô-đun giới thiệu một thay đổi có thể gây lỗi trong getRedirectResult. Khi không có thao tác chuyển hướng nào được gọi, API mô-đun sẽ trả về null thay vì API có không gian tên, API này trả về UserCredential với người dùng null.

Trước: tương thích

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

Sau: mô-đun

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;

Ví dụ 2: tái cấu trúc hàm Cloud Firestore

Trước: tương thích

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

Sau: mô-đun

Hàm getFirestore lấy firebaseApp làm tham số đầu tiên, được trả về từ initializeApp trong một ví dụ trước đó. Lưu ý cách mã để tạo một truy vấn rất khác trong API mô-đun; không có chuỗi và các phương thức như query hoặc where hiện được hiển thị dưới dạng các hàm miễn phí.

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

Cập nhật các tham chiếu đến Firestore DocumentSnapshot.exists

API mô-đun giới thiệu một thay đổi có thể gây lỗi trong đó thuộc tính firestore.DocumentSnapshot.exists đã được thay đổi thành phương thức. Chức năng này về cơ bản là giống nhau (kiểm thử xem một tài liệu có tồn tại hay không), nhưng bạn phải tái cấu trúc mã để sử dụng phương thức mới hơn như minh hoạ:

Trước:tương thích

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

Sau: mô-đun

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

Ví dụ 3: kết hợp các kiểu mã có không gian tên và mô-đun

Việc sử dụng thư viện tương thích trong quá trình nâng cấp cho phép bạn tiếp tục sử dụng mã có không gian tên cùng với mã được tái cấu trúc cho API mô-đun. Điều này có nghĩa là bạn có thể giữ lại mã có không gian tên hiện có cho Cloud Firestore trong khi tái cấu trúc Authentication hoặc mã SDK Firebase khác theo kiểu mô-đun và vẫn biên dịch thành công ứng dụng của mình bằng cả hai kiểu mã. Điều này cũng đúng đối với mã API có không gian tên và mô-đun trong một sản phẩm như là Cloud Firestore; các kiểu mã mới và cũ có thể cùng tồn tại, miễn là bạn đang nhập các gói tương thích:

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

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

Xin lưu ý rằng mặc dù ứng dụng của bạn sẽ biên dịch, nhưng bạn sẽ không nhận được lợi ích về kích thước ứng dụng của mã mô-đun cho đến khi bạn xoá hoàn toàn các câu lệnh và mã tương thích khỏi ứng dụng.

Cập nhật mã khởi chạy

Cập nhật mã khởi chạy của ứng dụng để sử dụng cú pháp mô-đun. Bạn cần cập nhật mã này sau khi hoàn tất việc tái cấu trúc tất cả mã trong ứng dụng; điều này là do firebase.initializeApp() khởi chạy trạng thái chung cho cả API tương thích và mô-đun, trong khi hàm mô-đuninitializeApp() chỉ khởi chạy trạng thái cho mô-đun.

Trước: tương thích

import firebase from "firebase/compat/app"

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

Sau: mô-đun

import { initializeApp } from "firebase/app"

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

Xoá mã tương thích

Để nhận được lợi ích về kích thước của API mô-đun, bạn nên chuyển đổi tất cả các lệnh gọi thành kiểu mô-đun như minh hoạ ở trên và xoá tất cả các câu lệnh import "firebase/compat/* khỏi mã của mình. Khi bạn hoàn tất, sẽ không còn tham chiếu nào đến không gian tên chung firebase.* hoặc bất kỳ mã nào khác theo kiểu API có không gian tên.

Sử dụng thư viện tương thích từ cửa sổ

API mô-đun được tối ưu hoá để hoạt động với các mô-đun thay vì đối tượng window của trình duyệt. Các phiên bản trước của thư viện cho phép tải và quản lý Firebase bằng cách sử dụng không gian tên window.firebase. Bạn không nên sử dụng cách này trong tương lai vì nó không cho phép loại bỏ mã không dùng đến. Tuy nhiên, phiên bản tương thích của SDK JavaScript hoạt động với window đối với những nhà phát triển không muốn bắt đầu ngay lộ trình nâng cấp mô-đun.

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

Thư viện khả năng tương thích sử dụng mã mô-đun ở chế độ nền và cung cấp mã đó bằng cùng một API như API có không gian tên; điều này có nghĩa là bạn có thể tham khảo tài liệu tham khảo API có không gian tên và đoạn mã có không gian tên để biết thông tin chi tiết. Bạn không nên sử dụng phương thức này trong thời gian dài, mà chỉ nên dùng để bắt đầu nâng cấp lên thư viện mô-đun hoàn toàn.

Lợi ích và hạn chế của SDK mô-đun

SDK được mô-đun hoá hoàn toàn có những ưu điểm sau so với các phiên bản trước:

  • SDK mô-đun giúp giảm đáng kể kích thước ứng dụng. SDK này sử dụng định dạng Mô-đun JavaScript hiện đại, cho phép thực hành "loại bỏ mã không dùng đến" trong đó bạn chỉ nhập các cấu phần phần mềm mà ứng dụng của bạn cần. Tuỳ thuộc vào ứng dụng của bạn, việc loại bỏ mã không dùng đến bằng SDK mô-đun có thể giúp giảm 80% số kilobyte so với một ứng dụng tương tự được xây dựng bằng API có không gian tên.
  • SDK mô-đun sẽ tiếp tục hưởng lợi từ việc phát triển tính năng liên tục, trong khi API có không gian tên sẽ không.