Sử dụng trình gói mô-đun với Firebase

Trình đóng gói mô-đun JavaScript có thể làm nhiều việc, nhưng một trong những tính năng hữu ích nhất của chúng là khả năng thêm và sử dụng các thư viện bên ngoài trong cơ sở mã của bạn. Trình đóng gói mô-đun đọc các đường dẫn nhập trong mã của bạn và kết hợp (đóng gói) mã dành riêng cho ứng dụng với mã thư viện đã nhập.

Từ phiên bản 9 trở lên, API mô-đun JavaScript của Firebase được tối ưu hoá để hoạt động với các tính năng tối ưu hoá của trình đóng gói mô-đun nhằm giảm lượng mã Firebase có trong bản dựng cuối cùng.

import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged, getRedirectResult } from 'firebase/auth';

const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => { /* check status */ });

/**
 * getRedirectResult is unused and should not be included in the code base.
 * In addition, there are many other functions within firebase/auth that are
 * not imported and therefore should not be included as well.
 */

Quá trình loại bỏ mã không dùng đến khỏi thư viện được gọi là loại bỏ mã không dùng đến. Việc xoá mã này theo cách thủ công sẽ tốn rất nhiều thời gian và dễ xảy ra lỗi, nhưng trình đóng gói mô-đun có thể tự động hoá quá trình xoá này.

Có nhiều trình đóng gói mô-đun chất lượng cao trong hệ sinh thái JavaScript. Hướng dẫn này tập trung vào việc sử dụng Firebase với webpack, Rollupesbuild.

Bắt đầu

Hướng dẫn này yêu cầu bạn phải cài đặt npm trong môi trường phát triển. npm được dùng để cài đặt và quản lý các phần phụ thuộc (thư viện). Để cài đặt npm, hãy cài đặt Node.js, trong đó có npm tự động.

Hầu hết nhà phát triển đều thiết lập đúng cách sau khi cài đặt Node.js. Tuy nhiên, nhiều nhà phát triển gặp phải các vấn đề thường gặp khi thiết lập môi trường. Nếu bạn gặp phải lỗi, hãy đảm bảo môi trường của bạn có npm CLI và bạn đã thiết lập các quyền thích hợp để bạn không phải cài đặt gói dưới dạng quản trị viên bằng lệnh sudo.

package.json và cài đặt Firebase

Sau khi cài đặt npm, bạn cần tạo tệp package.json ở gốc dự án cục bộ. Tạo tệp này bằng lệnh npm sau:

npm init

Lệnh này sẽ đưa bạn qua một trình hướng dẫn để cung cấp thông tin cần thiết. Sau khi tạo, tệp này sẽ có dạng tương tự như sau:

{
  "name": "your-package-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {

  }
}

Tệp này chịu trách nhiệm về nhiều việc khác nhau. Đây là một tệp quan trọng để bạn làm quen nếu muốn tìm hiểu thêm về việc đóng gói mô-đun và tạo mã JavaScript nói chung. Phần quan trọng của hướng dẫn này là đối tượng "dependencies". Đối tượng này sẽ giữ một cặp khoá-giá trị của thư viện mà bạn đã cài đặt và phiên bản mà thư viện đang sử dụng.

Việc thêm phần phụ thuộc được thực hiện thông qua lệnh npm install hoặc npm i.

npm i firebase

Khi bạn chạy npm i firebase, quá trình cài đặt sẽ cập nhật package.json để liệt kê Firebase dưới dạng phần phụ thuộc:

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

Khoá là tên của thư viện và giá trị là phiên bản cần sử dụng. Giá trị phiên bản có tính linh hoạt và có thể chấp nhận một phạm vi giá trị. Đây được gọi là phiên bản ngữ nghĩa hoặc semver. Để tìm hiểu thêm về semver, hãy xem hướng dẫn của npm về phiên bản ngữ nghĩa.

Thư mục nguồn so với thư mục bản dựng

Mã bạn viết được trình đóng gói mô-đun đọc và xử lý, sau đó xuất ra dưới dạng một tệp mới hoặc một tập hợp tệp. Bạn cần tách riêng 2 loại tệp này. Mã mà trình đóng gói mô-đun đọc và xử lý được gọi là mã "nguồn". Các tệp mà chúng xuất ra được gọi là mã đã tạo hoặc mã "dist" (phân phối).

Một thiết lập phổ biến trong cơ sở mã là lưu trữ mã nguồn trong một thư mục có tên là src và mã đã tạo trong một thư mục có tên là dist.

- src
 |_ index.js
 |_ animations.js
 |_ datalist.js


- dist
 |_ bundle.js

Trong cấu trúc tệp ví dụ ở trên, hãy cân nhắc việc index.js nhập cả animations.jsdatalist.js. Khi trình đóng gói mô-đun xử lý mã nguồn , trình này sẽ tạo ra tệp bundle.js trong thư mục dist. bundle.js là sự kết hợp của các tệp trong thư mục src và mọi thư viện mà quá trình nhập cũng như vậy.

Nếu bạn đang sử dụng các hệ thống kiểm soát nguồn như Git, thì bạn thường bỏ qua thư mục dist khi lưu trữ mã này trong kho lưu trữ chính.

Điểm truy cập

Tất cả trình đóng gói mô-đun đều có khái niệm về điểm truy cập. Bạn có thể coi ứng dụng của mình là một cây tệp. Một tệp nhập mã từ một tệp khác, v.v. Điều này có nghĩa là một tệp sẽ là gốc của cây. Tệp này được gọi là điểm truy cập.

Hãy xem lại ví dụ về cấu trúc tệp trước đó.

- src
 |_ index.js
 |_ animations.js
 |_ datalist.js


- dist
 |_ bundle.js
// src/index.js
import { animate } from './animations';
import { createList } from './datalist';

// This is not real code, but for example purposes only
const theList = createList('users/123/tasks');
theList.addEventListener('loaded', event => {
  animate(theList);
});

Tệp src/index.js được coi là điểm truy cập vì tệp này bắt đầu quá trình nhập tất cả mã cần thiết cho ứng dụng. Trình đóng gói mô-đun sử dụng tệp điểm truy cập này để bắt đầu quá trình đóng gói.

Sử dụng Firebase với webpack

Bạn không cần phải thiết lập cấu hình cụ thể nào cho các ứng dụng Firebase và webpack. Phần này trình bày cấu hình webpack chung.

Bước đầu tiên là cài đặt webpack từ npm dưới dạng phần phụ thuộc phát triển.

npm i webpack webpack-cli -D

Tạo một tệp ở gốc dự án cục bộ có tên là webpack.config.js rồi thêm mã sau.

const path = require('path');

module.exports = {
  // The entry point file described above
  entry: './src/index.js',
  // The location of the build folder described above
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // Optional and for development only. This provides the ability to
  // map the built code back to the original source format when debugging.
  devtool: 'eval-source-map',
};

Sau đó, hãy đảm bảo bạn đã cài đặt Firebase dưới dạng phần phụ thuộc.

npm i firebase

Sau đó, hãy khởi động Firebase trong cơ sở mã của bạn. Mã sau đây nhập và khởi động Firebase trong một tệp điểm truy cập, đồng thời sử dụng Firestore Lite để tải tài liệu "city".

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

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

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

Bước tiếp theo là thêm một tập lệnh npm để chạy bản dựng webpack. Mở tệp package.json rồi thêm cặp khoá-giá trị sau vào đối tượng "scripts".

  "scripts": {
    "build": "webpack --mode=development"
  },

Để chạy webpack và tạo thư mục bản dựng, hãy chạy lệnh sau.

npm run build

Cuối cùng, hãy kiểm tra thư mục bản dựng dist. Thư mục này phải chứa một tệp có tên là bundle.js chứa mã ứng dụng và phần phụ thuộc đã đóng gói.

Để biết thêm thông tin về cách tối ưu hoá bản dựng webpack cho bản phát hành công khai, hãy xem tài liệu chính thức của họ về chế độ cài đặt cấu hình "mode".

Sử dụng Firebase với Rollup

Bạn không cần phải thiết lập cấu hình cụ thể nào cho các ứng dụng Firebase và Rollup. Phần này trình bày cấu hình Rollup chung.

Bước đầu tiên là cài đặt Rollup và một trình bổ trợ dùng để ánh xạ các lượt nhập đến các phần phụ thuộc được cài đặt bằng npm.

npm i rollup @rollup/plugin-node-resolve -D

Tạo một tệp ở gốc dự án cục bộ có tên là rollup.config.js rồi thêm mã sau.

import { nodeResolve } from '@rollup/plugin-node-resolve';

export default {
  // the entry point file described above
  input: 'src/index.js',
  // the output for the build folder described above
  output: {
    file: 'dist/bundle.js',
    // Optional and for development only. This provides the ability to
    // map the built code back to the original source format when debugging.
    sourcemap: 'inline',
    // Configure Rollup to convert your module code to a scoped function
    // that "immediate invokes". See the Rollup documentation for more
    // information: https://rollupjs.org/guide/en/#outputformat
    format: 'iife'
  },
  // Add the plugin to map import paths to dependencies
  // installed with npm
  plugins: [nodeResolve()]
};

Sau đó, hãy khởi động Firebase trong cơ sở mã của bạn. Mã sau đây nhập và khởi động Firebase trong một tệp điểm truy cập, đồng thời sử dụng Firestore Lite để tải tài liệu "city".

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

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

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

Bước tiếp theo là thêm một tập lệnh npm để chạy bản dựng rollup. Mở tệp package.json rồi thêm cặp khoá-giá trị sau vào đối tượng "scripts".

  "scripts": {
    "build": "rollup -c rollup.config.js"
  },

Để chạy rollup và tạo thư mục bản dựng, hãy chạy lệnh sau.

npm run build

Cuối cùng, hãy kiểm tra thư mục bản dựng dist. Thư mục này phải chứa một tệp có tên là bundle.js chứa mã ứng dụng và phần phụ thuộc đã đóng gói.

Để biết thêm thông tin về cách tối ưu hoá bản dựng Rollup cho bản phát hành công khai, hãy xem tài liệu chính thức của họ về các trình bổ trợ cho bản dựng phát hành công khai.

Sử dụng Firebase với esbuild

Bạn không cần phải thiết lập cấu hình cụ thể nào cho các ứng dụng Firebase và esbuild. Phần này trình bày cấu hình esbuild chung.

Bước đầu tiên là cài đặt esbuild dưới dạng phần phụ thuộc phát triển.

npm i esbuild -D

Tạo một tệp ở gốc dự án cục bộ có tên là esbuild.config.js rồi thêm mã sau.

require('esbuild').build({
  // the entry point file described above
  entryPoints: ['src/index.js'],
  // the build folder location described above
  outfile: 'dist/bundle.js',
  bundle: true,
  // Replace with the browser versions you need to target
  target: ['chrome60', 'firefox60', 'safari11', 'edge20'],
  // Optional and for development only. This provides the ability to
  // map the built code back to the original source format when debugging.
  sourcemap: 'inline',
}).catch(() => process.exit(1))

Sau đó, hãy khởi động Firebase trong cơ sở mã của bạn. Mã sau đây nhập và khởi động Firebase trong một tệp điểm truy cập, đồng thời sử dụng Firestore Lite để tải tài liệu "city".

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

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

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

Bước tiếp theo là thêm một tập lệnh npm để chạy esbuild. Mở tệp package.json rồi thêm cặp khoá-giá trị sau vào đối tượng "scripts".

  "scripts": {
    "build": "node ./esbuild.config.js"
  },

Cuối cùng, hãy kiểm tra thư mục bản dựng dist. Thư mục này phải chứa một tệp có tên là bundle.js chứa mã ứng dụng và phần phụ thuộc đã đóng gói.

Để biết thêm thông tin về cách tối ưu hoá esbuild cho bản phát hành công khai, hãy xem tài liệu chính thức của họ về tính năng thu gọn và các tính năng tối ưu hoá khác.