Tiếng Việt

Khám phá sự khác biệt giữa CommonJS và ES Modules, hai hệ thống module chính trong JavaScript, với các ví dụ thực tế và thông tin chi tiết cho phát triển web hiện đại.

Hệ Thống Module: CommonJS và ES Modules - Hướng Dẫn Toàn Diện

Trong thế giới phát triển JavaScript không ngừng biến đổi, tính module là nền tảng để xây dựng các ứng dụng có khả năng mở rộng và dễ bảo trì. Hai hệ thống module đã từng thống trị toàn cảnh: CommonJS và ES Modules (ESM). Việc hiểu rõ sự khác biệt, ưu điểm và nhược điểm của chúng là rất quan trọng đối với bất kỳ nhà phát triển JavaScript nào, dù đang làm việc trên front-end với các framework như React, Vue, hoặc Angular, hay trên back-end với Node.js.

Hệ Thống Module là gì?

Một hệ thống module cung cấp cách thức tổ chức mã nguồn thành các đơn vị có thể tái sử dụng được gọi là module. Mỗi module đóng gói một phần chức năng cụ thể và chỉ hiển thị những phần mà các module khác cần sử dụng. Cách tiếp cận này thúc đẩy khả năng tái sử dụng mã nguồn, giảm độ phức tạp và cải thiện khả năng bảo trì. Hãy tưởng tượng các module như những khối xây dựng; mỗi khối có một mục đích cụ thể, và bạn có thể kết hợp chúng để tạo ra các cấu trúc lớn hơn, phức tạp hơn.

Lợi ích của việc sử dụng Hệ Thống Module:

CommonJS: Tiêu Chuẩn của Node.js

CommonJS nổi lên như một hệ thống module tiêu chuẩn cho Node.js, môi trường chạy JavaScript phổ biến cho phát triển phía máy chủ. Nó được thiết kế để giải quyết việc thiếu một hệ thống module tích hợp sẵn trong JavaScript khi Node.js lần đầu được tạo ra. Node.js đã áp dụng CommonJS làm cách thức tổ chức mã nguồn của mình. Lựa chọn này đã có tác động sâu sắc đến cách các ứng dụng JavaScript được xây dựng ở phía máy chủ.

Các Tính Năng Chính của CommonJS:

Cú Pháp CommonJS:

Đây là một ví dụ về cách sử dụng CommonJS:

Module (math.js):

// math.js
function add(a, b) {
 return a + b;
}

function subtract(a, b) {
 return a - b;
}

module.exports = {
 add: add,
 subtract: subtract
};

Cách sử dụng (app.js):

// app.js
const math = require('./math');

console.log(math.add(5, 3)); // Kết quả: 8
console.log(math.subtract(10, 4)); // Kết quả: 6

Ưu điểm của CommonJS:

Nhược điểm của CommonJS:

ES Modules (ESM): Hệ Thống Module JavaScript Tiêu Chuẩn Hóa

ES Modules (ESM) là hệ thống module tiêu chuẩn chính thức cho JavaScript, được giới thiệu cùng với ECMAScript 2015 (ES6). Chúng nhằm mục đích cung cấp một cách nhất quán và hiệu quả để tổ chức mã nguồn trong cả Node.js và trình duyệt. ESM mang lại sự hỗ trợ module native cho chính ngôn ngữ JavaScript, loại bỏ sự cần thiết của các thư viện bên ngoài hoặc các công cụ xây dựng để xử lý tính module.

Các Tính Năng Chính của ES Modules:

Cú Pháp ES Modules:

Đây là một ví dụ về cách sử dụng ES Modules:

Module (math.js):

// math.js
export function add(a, b) {
 return a + b;
}

export function subtract(a, b) {
 return a - b;
}

// Hoặc, cách khác:
// function add(a, b) {
//  return a + b;
// }
// function subtract(a, b) {
//  return a - b;
// }
// export { add, subtract };

Cách sử dụng (app.js):

// app.js
import { add, subtract } from './math.js';

console.log(add(5, 3)); // Kết quả: 8
console.log(subtract(10, 4)); // Kết quả: 6

Named Exports và Default Exports:

ES Modules hỗ trợ cả export theo tên (named export) và export mặc định (default export). Named exports cho phép bạn xuất nhiều giá trị từ một module với các tên cụ thể. Default exports cho phép bạn xuất một giá trị duy nhất làm giá trị xuất mặc định của một module.

Ví dụ về Named Export (utils.js):

// utils.js
export function formatCurrency(amount, currencyCode) {
 // Định dạng số tiền theo mã tiền tệ
 // Ví dụ: formatCurrency(1234.56, 'USD') có thể trả về '$1,234.56'
 // Việc triển khai phụ thuộc vào định dạng mong muốn và các thư viện có sẵn
 return new Intl.NumberFormat('en-US', { style: 'currency', currency: currencyCode }).format(amount);
}

export function formatDate(date, locale) {
 // Định dạng ngày theo ngôn ngữ địa phương
 // Ví dụ: formatDate(new Date(), 'fr-CA') có thể trả về '2024-01-01'
 return new Intl.DateTimeFormat(locale).format(date);
}
// app.js
import { formatCurrency, formatDate } from './utils.js';

const price = formatCurrency(19.99, 'EUR'); // Châu Âu
const today = formatDate(new Date(), 'ja-JP'); // Nhật Bản

console.log(price); // Kết quả: €19.99
console.log(today); // Kết quả: (thay đổi tùy theo ngày)

Ví dụ về Default Export (api.js):

// api.js
const api = {
 fetchData: async (url) => {
 const response = await fetch(url);
 return response.json();
 }
};

export default api;
// app.js
import api from './api.js';

api.fetchData('https://example.com/data')
 .then(data => console.log(data));

Ưu điểm của ES Modules:

Nhược điểm của ES Modules:

So Sánh Chi Tiết CommonJS và ES Modules

Đây là bảng tóm tắt những khác biệt chính giữa CommonJS và ES Modules:

Tính năng CommonJS ES Modules
Cú pháp Import require() import
Cú pháp Export module.exports export
Tải Đồng bộ Bất đồng bộ (trong trình duyệt), Đồng bộ/Bất đồng bộ trong Node.js
Phân tích tĩnh Không
Hỗ trợ native trên trình duyệt Không
Trường hợp sử dụng chính Node.js (trước đây) Trình duyệt và Node.js (hiện đại)

Ví Dụ Thực Tế và Các Trường Hợp Sử Dụng

Ví dụ 1: Tạo một Module Tiện Ích Tái Sử Dụng (Quốc tế hóa)

Giả sử bạn đang xây dựng một ứng dụng web cần hỗ trợ nhiều ngôn ngữ. Bạn có thể tạo một module tiện ích có thể tái sử dụng để xử lý việc quốc tế hóa (i18n).

ES Modules (i18n.js):

// i18n.js
const translations = {
 'en': {
 'greeting': 'Hello, world!'
 },
 'fr': {
 'greeting': 'Bonjour, le monde !'
 },
 'es': {
 'greeting': '¡Hola, mundo!'
 }
};

export function getTranslation(key, language) {
 return translations[language][key] || key;
}
// app.js
import { getTranslation } from './i18n.js';

const language = 'fr'; // Ví dụ: Người dùng đã chọn tiếng Pháp
const greeting = getTranslation('greeting', language);
console.log(greeting); // Kết quả: Bonjour, le monde !

Ví dụ 2: Xây Dựng một API Client Dạng Module (REST API)

Khi tương tác với một REST API, bạn có thể tạo một API client dạng module để đóng gói logic API.

ES Modules (apiClient.js):

// apiClient.js
const API_BASE_URL = 'https://api.example.com';

async function get(endpoint) {
 const response = await fetch(`${API_BASE_URL}${endpoint}`);
 if (!response.ok) {
 throw new Error(`Lỗi HTTP! trạng thái: ${response.status}`);
 }
 return response.json();
}

async function post(endpoint, data) {
 const response = await fetch(`${API_BASE_URL}${endpoint}`, {
 method: 'POST',
 headers: {
 'Content-Type': 'application/json'
 },
 body: JSON.stringify(data)
 });
 if (!response.ok) {
 throw new Error(`Lỗi HTTP! trạng thái: ${response.status}`);
 }
 return response.json();
}

export { get, post };
// app.js
import { get, post } from './apiClient.js';

get('/users')
 .then(users => console.log(users))
 .catch(error => console.error('Lỗi khi lấy danh sách người dùng:', error));

post('/users', { name: 'John Doe', email: 'john.doe@example.com' })
 .then(newUser => console.log('Người dùng mới đã được tạo:', newUser))
 .catch(error => console.error('Lỗi khi tạo người dùng:', error));

Chuyển đổi từ CommonJS sang ES Modules

Việc chuyển đổi từ CommonJS sang ES Modules có thể là một quá trình phức tạp, đặc biệt là trong các codebase lớn. Dưới đây là một số chiến lược cần cân nhắc:

Node.js và ES Modules:

Node.js đã phát triển để hỗ trợ đầy đủ ES Modules. Bạn có thể sử dụng ES Modules trong Node.js bằng cách:

Lựa Chọn Hệ Thống Module Phù Hợp

Sự lựa chọn giữa CommonJS và ES Modules phụ thuộc vào nhu cầu cụ thể của bạn và môi trường bạn đang phát triển:

Kết Luận

Hiểu được sự khác biệt giữa CommonJS và ES Modules là điều cần thiết đối với bất kỳ nhà phát triển JavaScript nào. Mặc dù CommonJS trong lịch sử là tiêu chuẩn cho Node.js, ES Modules đang nhanh chóng trở thành lựa chọn ưu tiên cho cả trình duyệt và Node.js do tính chất tiêu chuẩn hóa, lợi ích về hiệu suất và hỗ trợ phân tích tĩnh. Bằng cách xem xét cẩn thận nhu cầu của dự án và môi trường bạn đang phát triển, bạn có thể chọn hệ thống module phù hợp nhất với yêu cầu của mình và xây dựng các ứng dụng JavaScript có khả năng mở rộng, dễ bảo trì và hiệu quả.

Khi hệ sinh thái JavaScript tiếp tục phát triển, việc cập nhật thông tin về các xu hướng và phương pháp hay nhất của hệ thống module là rất quan trọng để thành công. Hãy tiếp tục thử nghiệm với cả CommonJS và ES Modules, và khám phá các công cụ và kỹ thuật khác nhau có sẵn để giúp bạn xây dựng mã JavaScript có tính module và dễ bảo trì.