Tăng hiệu quả cho ứng dụng web của bạn bằng cách di chuyển sang Firebase JS SDK mô-đun

1. Trước khi bắt đầu

Firebase JS SDK theo mô-đun là phiên bản viết lại của JS SDK hiện có và sẽ được phát hành dưới dạng phiên bản chính tiếp theo. Nhờ đó, các nhà phát triển có thể loại trừ mã không dùng đến khỏi Firebase JS SDK để tạo các gói nhỏ hơn và đạt được hiệu suất tốt hơn.

Điểm khác biệt đáng chú ý nhất trong SDK JS theo mô-đun là các tính năng hiện được sắp xếp trong các hàm thả nổi miễn phí mà bạn sẽ nhập, thay vì trong một không gian tên firebase duy nhất bao gồm mọi thứ. Cách tổ chức mã mới này cho phép loại bỏ mã không dùng đến và bạn sẽ tìm hiểu cách nâng cấp mọi ứng dụng hiện đang sử dụng Firebase JS SDK phiên bản 8 lên phiên bản mô-đun mới.

Để mang đến quy trình nâng cấp suôn sẻ, chúng tôi cung cấp một bộ gói tương thích. Trong lớp học lập trình này, bạn sẽ tìm hiểu cách sử dụng các gói tương thích để chuyển ứng dụng từng phần.

Sản phẩm bạn sẽ tạo ra

Trong lớp học lập trình này, bạn sẽ di chuyển dần một ứng dụng web danh sách theo dõi cổ phiếu hiện có sử dụng JS SDK phiên bản 8 sang JS SDK theo mô-đun mới theo 3 giai đoạn:

  • Nâng cấp ứng dụng để sử dụng các gói tương thích
  • Nâng cấp ứng dụng từ các gói tương thích lên API theo mô-đun từng bước
  • Sử dụng Firestore Lite, một phiên bản triển khai nhẹ của Firestore SDK, để cải thiện hơn nữa hiệu suất của ứng dụng

2d351cb47b604ad7.png

Lớp học lập trình này tập trung vào việc nâng cấp SDK Firebase. Các khái niệm và khối mã khác được tinh chỉnh và cung cấp cho bạn, chỉ cần sao chép và dán.

Bạn cần

  • Một trình duyệt mà bạn chọn, chẳng hạn như Chrome
  • IDE/trình chỉnh sửa văn bản mà bạn chọn, chẳng hạn như WebStorm, Atom, Sublime hoặc VS Code
  • Trình quản lý gói npm, thường đi kèm với Node.js
  • Mã mẫu của lớp học lập trình (Xem bước tiếp theo của lớp học lập trình để biết cách lấy mã.)

2. Bắt đầu thiết lập

Lấy mã nguồn

Mọi thứ bạn cần cho dự án này đều nằm trong một kho lưu trữ Git. Để bắt đầu, bạn cần lấy mã và mở mã đó trong môi trường phát triển mà bạn yêu thích.

Sao chép kho lưu trữ Github của lớp học lập trình từ dòng lệnh:

git clone https://github.com/FirebaseExtended/codelab-modular-sdk.git

Ngoài ra, nếu chưa cài đặt git, bạn có thể tải kho lưu trữ xuống dưới dạng tệp ZIP rồi giải nén tệp ZIP đã tải xuống.

Nhập ứng dụng

  1. Dùng IDE để mở hoặc nhập thư mục codelab-modular-sdk.
  2. Chạy npm install để cài đặt các phần phụ thuộc cần thiết để tạo và chạy ứng dụng cục bộ.
  3. Chạy npm run build để tạo ứng dụng.
  4. Chạy npm run serve để khởi động máy chủ web
  5. Mở một thẻ trình duyệt đến http://localhost:8080

71a8a7d47392e8f4.png

3. Thiết lập đường cơ sở

Điểm xuất phát của bạn là gì?

Điểm bắt đầu của bạn là một ứng dụng danh sách theo dõi cổ phiếu được thiết kế cho lớp học lập trình này. Mã này đã được đơn giản hoá để minh hoạ các khái niệm trong lớp học lập trình này và có rất ít tính năng xử lý lỗi. Nếu bạn chọn sử dụng lại bất kỳ mã nào trong số này trong một ứng dụng phát hành công khai, hãy đảm bảo rằng bạn xử lý mọi lỗi và kiểm thử đầy đủ tất cả mã.

Đảm bảo mọi thứ đều hoạt động trong ứng dụng:

  1. Đăng nhập ẩn danh bằng nút đăng nhập ở góc trên bên phải.
  2. Sau khi đăng nhập, hãy tìm và thêm "NFLX", "SBUX" và "T" vào danh sách theo dõi bằng cách nhấp vào nút Thêm, nhập các chữ cái rồi nhấp vào hàng kết quả tìm kiếm xuất hiện bên dưới.
  3. Xoá một cổ phiếu khỏi danh sách theo dõi bằng cách nhấp vào dấu x ở cuối hàng.
  4. Xem thông tin cập nhật theo thời gian thực về giá cổ phiếu.
  5. Mở Công cụ của Chrome cho nhà phát triển, chuyển đến thẻ Mạng rồi đánh dấu vào Tắt bộ nhớ đệmDùng các hàng yêu cầu lớn. Tắt bộ nhớ đệm đảm bảo chúng ta luôn nhận được những thay đổi mới nhất sau khi làm mới và Sử dụng các hàng yêu cầu lớn giúp hàng hiển thị cả kích thước đã truyền và kích thước tài nguyên cho một tài nguyên. Trong lớp học lập trình này, chúng ta chủ yếu quan tâm đến kích thước của main.js.

48a096debb2aa940.png

  1. Tải ứng dụng trong nhiều điều kiện mạng bằng cách sử dụng tính năng điều tiết mô phỏng. Bạn sẽ sử dụng 3G chậm để đo thời gian tải trong lớp học lập trình này vì đây là nơi kích thước gói nhỏ hơn sẽ hữu ích nhất.

4397cb2c1327089.png

Bây giờ, hãy bắt đầu di chuyển ứng dụng sang API theo mô-đun mới.

4. Sử dụng các gói tương thích

Các gói tương thích cho phép bạn nâng cấp lên phiên bản SDK mới mà không cần thay đổi tất cả mã Firebase cùng một lúc. Bạn có thể nâng cấp dần các API này lên API theo mô-đun.

Trong bước này, bạn sẽ nâng cấp thư viện Firebase từ phiên bản 8 lên phiên bản mới và thay đổi mã để sử dụng các gói tương thích. Trong các bước sau, bạn sẽ tìm hiểu cách nâng cấp chỉ mã Firebase Auth để dùng API theo mô-đun trước, sau đó nâng cấp mã Firestore.

Ở cuối mỗi bước, bạn sẽ có thể biên dịch và chạy ứng dụng mà không gặp lỗi, đồng thời thấy kích thước gói giảm xuống khi chúng ta di chuyển từng sản phẩm.

Tải SDK mới xuống

Tìm mục phần phụ thuộc trong package.json rồi thay thế bằng nội dung sau:

package.json

"dependencies": {
    "firebase": "^9.0.0" 
}

Cài đặt lại các phần phụ thuộc

Vì đã thay đổi phiên bản của phần phụ thuộc, nên chúng ta cần chạy lại npm install để lấy phiên bản mới của phần phụ thuộc.

Thay đổi đường dẫn nhập

Các gói tương thích được hiển thị trong mô-đun con firebase/compat, vì vậy, chúng ta sẽ cập nhật các đường dẫn nhập tương ứng:

  1. Chuyển đến tệp src/firebase.ts
  2. Thay thế các mục nhập nhập hiện có bằng các mục nhập nhập sau:

src/firebase.ts

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

Xác minh ứng dụng hoạt động

  1. Chạy npm run build để tạo lại ứng dụng.
  2. Mở một thẻ trình duyệt đến http://localhost:8080 hoặc làm mới thẻ hiện có.
  3. Chơi với ứng dụng. Mọi thứ vẫn hoạt động bình thường.

5. Nâng cấp Auth để sử dụng API theo mô-đun

Bạn có thể nâng cấp các sản phẩm của Firebase theo bất kỳ thứ tự nào. Trong lớp học lập trình này, trước tiên, bạn sẽ nâng cấp Auth để tìm hiểu các khái niệm cơ bản vì Auth API tương đối đơn giản. Việc nâng cấp Firestore có liên quan nhiều hơn một chút và bạn sẽ tìm hiểu cách thực hiện việc đó trong phần tiếp theo.

Cập nhật quá trình khởi chạy Auth

  1. Chuyển đến tệp src/firebase.ts
  2. Thêm nội dung nhập sau:

src/firebase.ts

import { initializeAuth, indexedDBLocalPersistence } from 'firebase/auth';
  1. Xóa import ‘firebase/compat/auth'.
  2. Thay thế export const firebaseAuth = app.auth(); bằng:

src/firebase.ts

export const firebaseAuth = initializeAuth(app, { persistence: [indexedDBLocalPersistence] });
  1. Xoá export type User = firebase.User; ở cuối tệp. User sẽ được xuất trực tiếp trong src/auth.ts mà bạn sẽ thay đổi tiếp theo.

Cập nhật mã uỷ quyền

  1. Chuyển đến tệp src/auth.ts
  2. Thêm các nội dung nhập sau vào đầu tệp:

src/auth.ts

import { 
    signInAnonymously, 
    signOut,
    onAuthStateChanged,
    User
} from 'firebase/auth';
  1. Xoá User khỏi import { firebaseAuth, User } from './firebase'; vì bạn đã nhập User từ ‘firebase/auth'.
  2. Cập nhật các hàm để sử dụng API theo mô-đun.

Như bạn đã thấy trước đó khi chúng tôi cập nhật câu lệnh nhập, các gói trong phiên bản 9 được sắp xếp theo các hàm mà bạn có thể nhập, khác với các API phiên bản 8 dựa trên mẫu dịch vụ và không gian tên được liên kết bằng dấu chấm. Chính cấu trúc mã mới này cho phép loại bỏ mã không dùng đến, vì nó cho phép các công cụ bản dựng phân tích mã nào được dùng và mã nào không được dùng.

Trong phiên bản 9, các dịch vụ được truyền dưới dạng đối số đầu tiên cho các hàm. Dịch vụ là các đối tượng mà bạn nhận được khi khởi chạy một dịch vụ Firebase, ví dụ: đối tượng được trả về từ getAuth() hoặc initializeAuth(). Chúng giữ trạng thái của một dịch vụ Firebase cụ thể và hàm này sử dụng trạng thái đó để thực hiện các tác vụ. Hãy áp dụng mẫu này để triển khai các hàm sau:

src/auth.ts

export function firebaseSignInAnonymously() { 
    return signInAnonymously(firebaseAuth); 
} 

export function firebaseSignOut() { 
    return signOut(firebaseAuth); 
} 

export function onUserChange(callback: (user: User | null) => void) { 
    return onAuthStateChanged(firebaseAuth, callback); 
} 

export { User } from 'firebase/auth';

Xác minh ứng dụng hoạt động

  1. Chạy npm run build để tạo lại ứng dụng.
  2. Mở một thẻ trình duyệt đến http://localhost:8080 hoặc làm mới thẻ hiện có
  3. Chơi với ứng dụng. Mọi thứ vẫn hoạt động bình thường.

Kiểm tra kích thước gói

  1. Mở Công cụ của Chrome cho nhà phát triển.
  2. Chuyển sang thẻ Mạng.
  3. Làm mới trang để ghi lại các yêu cầu mạng.
  4. Tìm main.js và kiểm tra kích thước của tệp này. Bạn đã giảm kích thước gói xuống 100 KB (36 KB khi nén bằng gzip), tức là giảm khoảng 22% chỉ bằng cách thay đổi một vài dòng mã! Trang web này cũng tải nhanh hơn 0,75 giây khi kết nối 3G chậm.

2e4eafaf66cd829b.png

6. Nâng cấp Ứng dụng Firebase và Firestore để sử dụng API theo mô-đun

Cập nhật quá trình khởi chạy Firebase

  1. Chuyển đến tệp src/firebase.ts.
  2. Thay thế import firebase from ‘firebase/compat/app'; bằng:

src/firebase.ts

import { initializeApp } from 'firebase/app';
  1. Thay thế const app = firebase.initializeApp({...}); bằng:

src/firebase.ts

const app = initializeApp({
    apiKey: "AIzaSyBnRKitQGBX0u8k4COtDTILYxCJuMf7xzE", 
    authDomain: "exchange-rates-adcf6.firebaseapp.com", 
    databaseURL: "https://exchange-rates-adcf6.firebaseio.com", 
    projectId: "exchange-rates-adcf6", 
    storageBucket: "exchange-rates-adcf6.firebasestorage.app", 
    messagingSenderId: "875614679042", 
    appId: "1:875614679042:web:5813c3e70a33e91ba0371b"
});

Cập nhật quá trình khởi chạy Firestore

  1. Trong cùng một tệp src/firebase.ts,, hãy thay thế import 'firebase/compat/firestore'; bằng

src/firebase.ts

import { getFirestore } from 'firebase/firestore';
  1. Thay thế export const firestore = app.firestore(); bằng:

src/firebase.ts

export const firestore = getFirestore();
  1. Xoá tất cả các dòng sau "export const firestore = ..."

Cập nhật các lệnh nhập

  1. Mở tệp src/services.ts.
  2. Xoá FirestoreFieldPath, FirestoreFieldValueQuerySnapshot khỏi dữ liệu nhập. Lệnh nhập từ './firebase' giờ đây sẽ có dạng như sau:

src/services.ts

import { firestore } from './firebase';
  1. Nhập các hàm và kiểu mà bạn sẽ sử dụng ở đầu tệp:
    **src/services.ts**
import { 
    collection, 
    getDocs, 
    doc, 
    setDoc, 
    arrayUnion, 
    arrayRemove, 
    onSnapshot, 
    query, 
    where, 
    documentId, 
    QuerySnapshot
} from 'firebase/firestore';
  1. Tạo một tham chiếu đến bộ sưu tập chứa tất cả các mã chứng khoán:

src/services.ts

const tickersCollRef = collection(firestore, 'current');
  1. Sử dụng getDocs() để tìm nạp tất cả tài liệu trong bộ sưu tập:

src/services.ts

const tickers = await getDocs(tickersCollRef);

Hãy xem search() để biết đoạn mã hoàn chỉnh.

Cập nhật addToWatchList()

Sử dụng doc() để tạo một tài liệu tham chiếu đến danh sách xem của người dùng, sau đó thêm một mã chứng khoán vào danh sách đó bằng cách sử dụng setDoc() với arrayUnion():

src/services.ts

export function addToWatchList(ticker: string, user: User) {
      const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
      return setDoc(watchlistRef, {
       tickers: arrayUnion(ticker)
   }, { merge: true });
}

Cập nhật hàm deleteFromWatchList()

Tương tự, hãy xoá một mã chứng khoán khỏi danh sách xem của người dùng bằng cách sử dụng setDoc() với arrayRemove():

src/services.ts

export function deleteFromWatchList(ticker: string, user: User) {
   const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
   return setDoc(watchlistRef, {
       tickers: arrayRemove(ticker)
   }, { merge: true });
}

Cập nhật subscribeToTickerChanges()

  1. Trước tiên, hãy dùng doc() để tạo một tài liệu tham chiếu đến danh sách xem của người dùng, sau đó theo dõi các thay đổi trong danh sách xem bằng cách dùng onSnapshot():

src/services.ts

const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
const unsubscribe = onSnapshot(watchlistRef, snapshot => {
   /* subscribe to ticker price changes */
});
  1. Sau khi bạn thêm các mã chứng khoán vào danh sách theo dõi, hãy dùng query() để tạo một truy vấn nhằm tìm nạp giá của các mã chứng khoán đó và dùng onSnapshot() để theo dõi các thay đổi về giá của chúng:

src/services.ts

const priceQuery = query(
    collection(firestore, 'current'),
    where(documentId(), 'in', tickers)
);
unsubscribePrevTickerChanges = onSnapshot(priceQuery, snapshot => {
               if (firstload) {
                   performance && performance.measure("initial-data-load");
                   firstload = false;
                   logPerformance();
               }
               const stocks = formatSDKStocks(snapshot);
               callback(stocks);
  });

Hãy xem subscribeToTickerChanges() để biết cách triển khai hoàn chỉnh.

Cập nhật subscribeToAllTickerChanges()

Trước tiên, bạn sẽ dùng collection() để tạo một tham chiếu đến bộ sưu tập chứa giá của tất cả các mã chứng khoán, sau đó dùng onSnapshot() để theo dõi các thay đổi về giá:

src/services.ts

export function subscribeToAllTickerChanges(callback: TickerChangesCallBack) {
   const tickersCollRef = collection(firestore, 'current');
   return onSnapshot(tickersCollRef, snapshot => {
       if (firstload) {
           performance && performance.measure("initial-data-load");
           firstload = false;
           logPerformance();
       }
       const stocks = formatSDKStocks(snapshot);
       callback(stocks);
   });
}

Xác minh ứng dụng hoạt động

  1. Chạy npm run build để tạo lại ứng dụng.
  2. Mở một thẻ trình duyệt đến http://localhost:8080 hoặc làm mới thẻ hiện có
  3. Chơi với ứng dụng. Mọi thứ vẫn hoạt động bình thường.

Kiểm tra kích thước gói

  1. Mở Công cụ của Chrome cho nhà phát triển.
  2. Chuyển sang thẻ Mạng.
  3. Làm mới trang để ghi lại các yêu cầu mạng.
  4. Tìm main.js và kiểm tra kích thước của tệp này. Hãy so sánh kích thước này với kích thước gói ban đầu một lần nữa – chúng ta đã giảm kích thước gói xuống hơn 200 KB (63,8 KB khi nén gzip) hoặc nhỏ hơn 50%, tức là thời gian tải nhanh hơn 1,3 giây!

7660cdc574ee8571.png

7. Sử dụng Firestore Lite để tăng tốc quá trình kết xuất trang ban đầu

Firestore Lite là gì?

Firestore SDK cung cấp tính năng lưu vào bộ nhớ đệm phức tạp, truyền phát trực tiếp theo thời gian thực, bộ nhớ liên tục, đồng bộ hoá ngoại tuyến nhiều thẻ, thử lại, tính đồng thời lạc quan và nhiều tính năng khác. Do đó, SDK này có kích thước khá lớn. Nhưng có thể bạn chỉ muốn lấy dữ liệu một lần mà không cần dùng bất kỳ tính năng nâng cao nào. Trong những trường hợp đó, Firestore đã tạo ra một giải pháp đơn giản và gọn nhẹ, đó là một gói hoàn toàn mới có tên Firestore Lite.

Một trường hợp sử dụng tuyệt vời cho Firestore Lite là tối ưu hoá hiệu suất của quá trình kết xuất trang ban đầu, trong đó bạn chỉ cần biết người dùng có đăng nhập hay không, sau đó đọc một số dữ liệu từ Firestore để hiển thị.

Trong bước này, bạn sẽ tìm hiểu cách sử dụng Firestore lite để giảm kích thước gói nhằm tăng tốc quá trình kết xuất trang ban đầu, sau đó tải SDK Firestore chính một cách linh động để đăng ký nhận thông tin cập nhật theo thời gian thực.

Bạn sẽ tái cấu trúc mã để:

  1. Di chuyển các dịch vụ theo thời gian thực sang một tệp riêng biệt để có thể tải động các dịch vụ này bằng tính năng nhập động.
  2. Tạo các hàm mới để dùng Firestore Lite truy xuất danh sách theo dõi và giá cổ phiếu.
  3. Sử dụng các hàm Firestore Lite mới để truy xuất dữ liệu nhằm hiển thị trang ban đầu, sau đó tải động các dịch vụ theo thời gian thực để theo dõi nội dung cập nhật theo thời gian thực.

Di chuyển các dịch vụ theo thời gian thực sang một tệp mới

  1. Tạo một tệp mới có tên src/services.realtime.ts.
  2. Di chuyển các hàm subscribeToTickerChanges()subscribeToAllTickerChanges() từ src/services.ts vào tệp mới.
  3. Thêm các nội dung nhập cần thiết vào đầu tệp mới.

Bạn vẫn cần thực hiện một số thay đổi tại đây:

  1. Trước tiên, hãy tạo một phiên bản Firestore từ SDK Firestore chính ở đầu tệp sẽ được dùng trong các hàm. Bạn không thể nhập phiên bản Firestore từ firebase.ts tại đây vì bạn sẽ thay đổi phiên bản này thành phiên bản Firestore Lite trong vài bước. Phiên bản này sẽ chỉ được dùng cho quá trình kết xuất trang ban đầu.
  2. Thứ hai, loại bỏ biến firstload và khối if được bảo vệ bởi biến đó. Chức năng của các hàm này sẽ được chuyển sang các hàm mới mà bạn sẽ tạo trong bước tiếp theo.

src/services.realtime.ts

import { User } from './auth'
import { TickerChange } from './models';
import { collection, doc, onSnapshot, query, where, documentId, getFirestore } from 'firebase/firestore';
import { formatSDKStocks } from './services';

const firestore = getFirestore();
type TickerChangesCallBack = (changes: TickerChange[]) => void

export function subscribeToTickerChanges(user: User, callback: TickerChangesCallBack) {

   let unsubscribePrevTickerChanges: () => void;

   // Subscribe to watchlist changes. We will get an update whenever a ticker is added/deleted to the watchlist
   const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
   const unsubscribe = onSnapshot(watchlistRef, snapshot => {
       const doc = snapshot.data();
       const tickers = doc ? doc.tickers : [];

       if (unsubscribePrevTickerChanges) {
           unsubscribePrevTickerChanges();
       }

       if (tickers.length === 0) {
           callback([]);
       } else {
           // Query to get current price for tickers in the watchlist
           const priceQuery = query(
               collection(firestore, 'current'),
               where(documentId(), 'in', tickers)
           );

           // Subscribe to price changes for tickers in the watchlist
           unsubscribePrevTickerChanges = onSnapshot(priceQuery, snapshot => {
               const stocks = formatSDKStocks(snapshot);
               callback(stocks);
           });
       }
   });
   return () => {
       if (unsubscribePrevTickerChanges) {
           unsubscribePrevTickerChanges();
       }
       unsubscribe();
   };
}

export function subscribeToAllTickerChanges(callback: TickerChangesCallBack) {
   const tickersCollRef = collection(firestore, 'current');
   return onSnapshot(tickersCollRef, snapshot => {
       const stocks = formatSDKStocks(snapshot);
       callback(stocks);
   });
}

Sử dụng Firestore lite để tìm nạp dữ liệu

  1. Mở src/services.ts.
  2. Thay đổi đường dẫn nhập từ ‘firebase/firestore' thành ‘firebase/firestore/lite',, thêm getDoc và xoá onSnapshot khỏi danh sách nhập:

src/services.ts

import { 
    collection, 
    getDocs, 
    doc, 
    setDoc, 
    arrayUnion, 
    arrayRemove,
//  onSnapshot, // firestore lite doesn't support realtime updates
    query, 
    where, 
    documentId, 
    QuerySnapshot, 
    getDoc // add this import
} from 'firebase/firestore/lite';
  1. Thêm các hàm để tìm nạp dữ liệu cần thiết cho quá trình kết xuất trang ban đầu bằng Firestore Lite:

src/services.ts

export async function getTickerChanges(tickers: string[]): Promise<TickerChange[]> {

   if (tickers.length === 0) {
       return [];
   }

   const priceQuery = query(
       collection(firestore, 'current'),
       where(documentId(), 'in', tickers)
   );
   const snapshot = await getDocs(priceQuery);
   performance && performance.measure("initial-data-load");
   logPerformance();
   return formatSDKStocks(snapshot);
}

export async function getTickers(user: User): Promise<string[]> {
   const watchlistRef = doc(firestore, `watchlist/${user.uid}`);
   const data =  (await getDoc(watchlistRef)).data();

   return data ? data.tickers : [];
}

export async function getAllTickerChanges(): Promise<TickerChange[]> {
   const tickersCollRef = collection(firestore, 'current');
   const snapshot = await getDocs(tickersCollRef);
   performance && performance.measure("initial-data-load");
   logPerformance();
   return formatSDKStocks(snapshot);
}
  1. Mở src/firebase.ts rồi thay đổi đường dẫn nhập từ ‘firebase/firestore' thành ‘firebase/firestore/lite':

src/firebase.ts

import { getFirestore } from 'firebase/firestore/lite';

Kết hợp tất cả các yếu tố này

  1. Mở src/main.ts.
  2. Bạn sẽ cần các hàm mới tạo để tìm nạp dữ liệu cho quá trình kết xuất trang ban đầu và một số hàm trợ giúp để quản lý trạng thái ứng dụng. Bây giờ, hãy cập nhật các mục nhập:

src/main.ts

import { renderLoginPage, renderUserPage } from './renderer';
import { getAllTickerChanges, getTickerChanges, getTickers } from './services';
import { onUserChange } from './auth';
import { getState, setRealtimeServicesLoaded, setUser } from './state';
import './styles.scss';
  1. Tải src/services.realtime bằng cách sử dụng một câu lệnh nhập động ở đầu tệp. Biến loadRealtimeService là một lời hứa sẽ giải quyết bằng các dịch vụ theo thời gian thực sau khi mã được tải. Bạn sẽ sử dụng đối tượng này sau để đăng ký nhận thông tin cập nhật theo thời gian thực.

src/main.ts

const loadRealtimeService = import('./services.realtime');
loadRealtimeService.then(() => {
   setRealtimeServicesLoaded(true);
});
  1. Thay đổi lệnh gọi lại của onUserChange() thành hàm async để chúng ta có thể sử dụng await trong phần nội dung hàm:

src/main.ts

onUserChange(async user => {
 // callback body
});
  1. Giờ đây, hãy tìm nạp dữ liệu để hiển thị trang ban đầu bằng các hàm mới mà chúng ta đã tạo ở bước trước.

Trong lệnh gọi lại onUserChange(), hãy tìm điều kiện if khi người dùng đăng nhập, rồi sao chép và dán mã bên trong câu lệnh if:

src/main.ts

onUserChange(async user => {
      // LEAVE THE EXISTING CODE UNCHANGED HERE
      ...

      if (user) {
       // REPLACE THESE LINES

       // user page
       setUser(user);

       // show loading screen in 500ms
       const timeoutId = setTimeout(() => {
           renderUserPage(user, {
               loading: true,
               tableData: []
           });
       }, 500);

       // get data once if realtime services haven't been loaded
       if (!getState().realtimeServicesLoaded) {
           const tickers = await getTickers(user);
           const tickerData = await getTickerChanges(tickers);
           clearTimeout(timeoutId);
           renderUserPage(user, { tableData: tickerData });
       }

       // subscribe to realtime updates once realtime services are loaded
       loadRealtimeService.then(({ subscribeToTickerChanges }) => {
           unsubscribeTickerChanges = subscribeToTickerChanges(user, stockData => {
               clearTimeout(timeoutId);
               renderUserPage(user, { tableData: stockData })
           });
       });
   } else {
     // DON'T EDIT THIS PART, YET   
   }
}
  1. Trong khối else (nơi không có người dùng nào đăng nhập), hãy tìm nạp thông tin về giá cho tất cả các cổ phiếu bằng firestore lite, hiển thị trang, sau đó theo dõi các thay đổi về giá sau khi các dịch vụ theo thời gian thực được tải:

src/main.ts

if (user) {
   // DON'T EDIT THIS PART, WHICH WE JUST CHANGED ABOVE
   ...
} else {
   // REPLACE THESE LINES

   // login page
   setUser(null);

   // show loading screen in 500ms
   const timeoutId = setTimeout(() => {
       renderLoginPage('Landing page', {
           loading: true,
           tableData: []
       });
   }, 500);

   // get data once if realtime services haven't been loaded
   if (!getState().realtimeServicesLoaded) {
       const tickerData = await getAllTickerChanges();
       clearTimeout(timeoutId);
       renderLoginPage('Landing page', { tableData: tickerData });
   }

   // subscribe to realtime updates once realtime services are loaded
   loadRealtimeService.then(({ subscribeToAllTickerChanges }) => {
       unsubscribeAllTickerChanges = subscribeToAllTickerChanges(stockData => {
           clearTimeout(timeoutId);
           renderLoginPage('Landing page', { tableData: stockData })
       });
   });
}

Hãy xem src/main.ts để biết mã đã hoàn tất.

Xác minh ứng dụng hoạt động

  1. Chạy npm run build để tạo lại ứng dụng.
  2. Mở một thẻ trình duyệt đến http://localhost:8080 hoặc làm mới thẻ hiện có.

Kiểm tra kích thước gói

  1. Mở Công cụ cho nhà phát triển của Chrome.
  2. Chuyển sang thẻ Mạng.
  3. Làm mới trang để ghi lại các yêu cầu mạng
  4. Tìm main.js và kiểm tra kích thước của tệp này.
  5. Giờ đây, kích thước chỉ còn 115 KB (34,5 KB khi được nén bằng gzip). Kích thước này nhỏ hơn 75% so với kích thước gói ban đầu là 446 KB(138 KB khi nén bằng gzip)! Do đó, trang web này tải nhanh hơn 2 giây khi kết nối 3G – một hiệu suất tuyệt vời và cải thiện trải nghiệm người dùng!

9ea7398a8c8ef81b.png

8. Xin chúc mừng

Xin chúc mừng, bạn đã nâng cấp thành công ứng dụng, giúp ứng dụng nhỏ hơn và chạy nhanh hơn!

Bạn đã sử dụng các gói tương thích để nâng cấp ứng dụng từng phần và sử dụng Firestore Lite để tăng tốc quá trình kết xuất trang ban đầu, sau đó tải động Firestore chính để truyền trực tuyến các thay đổi về giá.

Bạn cũng đã giảm kích thước gói và cải thiện thời gian tải gói trong suốt quá trình thực hiện lớp học lập trình này:

main.js

kích thước tài nguyên (kb)

kích thước được nén bằng gzip (kb)

thời gian tải (giây) (trên mạng 3G chậm)

v8

446

138

4,92

v9 compat

429

124

4,65

Chỉ xác thực theo mô-đun phiên bản 9

348

102

4.2

v9 hoàn toàn theo mô-đun

244

74,6

3,66

v9 hoàn toàn theo mô-đun + Firestore lite

117

34,9

2,88

32a71bd5a774e035.png

Giờ đây, bạn đã biết các bước chính cần thiết để nâng cấp một ứng dụng web sử dụng Firebase JS SDK phiên bản 8 để sử dụng JS SDK theo mô-đun mới.

Tài liệu đọc thêm

Tài liệu tham khảo