ES Modules: Nâng tầm code Node.js của bạn, gọn gàng như Gen Z!
Nodejs

ES Modules: Nâng tầm code Node.js của bạn, gọn gàng như Gen Z!

Author

Admin System

@root

Ngày xuất bản

18 Mar, 2026

Lượt xem

46 Lượt

"ES Modules"

Chào các 'dev' tương lai, hay đúng hơn là các 'code influencer' của thế hệ Z! Hôm nay, Anh Creyt sẽ cùng các bạn 'mổ xẻ' một khái niệm nghe có vẻ hàn lâm nhưng lại cực kỳ 'chill' và cần thiết cho mọi dự án hiện đại: ES Modules trong Node.js.

1. ES Modules là gì mà 'hot' vậy? Để làm gì?

Ngày xửa ngày xưa, khi JavaScript còn 'ngây thơ', mỗi file code là một thế giới riêng, và mọi thứ bạn khai báo (biến, hàm) đều có thể 'va chạm' với nhau nếu không cẩn thận. Giống như một căn phòng trọ sinh viên, mỗi đứa vứt đồ đạc lung tung, y rằng sẽ có ngày giẫm phải đồ của đứa khác và cãi nhau ỏm tỏi vậy.

Rồi đến lúc code to dần, cần chia nhỏ ra nhiều file để dễ quản lý. Lúc này, 'bài toán' làm sao để các file có thể 'giao tiếp' với nhau, chia sẻ các 'công thức' (hàm) hay 'nguyên liệu' (biến) mà không gây 'đụng độ' toàn cục, trở thành một cơn đau đầu kinh niên. Các hệ thống module ra đời để giải quyết vấn đề này, như CommonJS trong Node.js ngày trước, hay AMD, UMD trên trình duyệt.

Nhưng rồi, 'thời đại mới' đến, và ES Modules (ECMAScript Modules) chính là 'người hùng' được sinh ra để thống nhất mọi thứ. Hãy tưởng tượng ES Modules như việc bạn xây dựng một căn hộ chung cư cao cấp. Mỗi căn hộ là một module, có cửa ra vào (export) để cung cấp dịch vụ (hàm, biến) cho các căn hộ khác, và có thể 'nhập khẩu' (import) dịch vụ từ các căn hộ lân cận. Mỗi căn hộ hoạt động độc lập, có không gian riêng, nhưng vẫn có thể kết nối với nhau một cách có trật tự.

Để làm gì ư? Đơn giản là để:

  • Tổ chức code gọn gàng: Chia dự án thành các phần nhỏ, dễ quản lý, dễ đọc, dễ bảo trì.
  • Tránh xung đột: Mỗi module có phạm vi riêng, không làm bẩn môi trường toàn cục.
  • Tái sử dụng code: Viết một lần, dùng nhiều nơi, tiết kiệm thời gian và công sức.
  • Tối ưu hiệu suất (Tree-shaking): Các công cụ đóng gói (bundler) có thể loại bỏ những phần code không dùng đến, giúp ứng dụng nhẹ hơn, load nhanh hơn. Giống như bạn chỉ mang những món đồ cần thiết khi đi du lịch vậy.

2. Code Ví Dụ Minh Họa: 'Mở cửa' và 'Mời vào' module

Để Node.js hiểu rằng bạn muốn dùng ES Modules, có hai cách chính:

  1. Dùng "type": "module" trong package.json: Đây là cách phổ biến và khuyến khích cho các dự án mới.
    {
      "name": "my-esm-app",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "type": "module", // <-- Thêm dòng này
      "scripts": {
        "start": "node index.js"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    
  2. Dùng đuôi file .mjs: Node.js sẽ tự động coi các file .mjs là ES Modules, bất kể package.json có gì.

Bây giờ, hãy tạo một module đơn giản:

utils.js (hoặc utils.mjs)

// utils.js

// Export named: Giống như bạn có nhiều món đồ để bán, mỗi món có tên riêng
export const add = (a, b) => a + b;

export const multiply = (a, b) => a * b;

export const greeting = (name) => `Hello, ${name}! Welcome to the ES Modules club.`;

// Export default: Chỉ có một món đồ 'best-seller' của cửa hàng
const secretMessage = "This is a secret message from utils.";
export default secretMessage;

Và cách bạn 'nhập khẩu' chúng vào file chính:

index.js (hoặc index.mjs)

// index.js

// Import named: Mua đúng món đồ mình cần theo tên
import { add, multiply, greeting } from './utils.js'; // Lưu ý: phải có đuôi .js (hoặc .mjs)

// Import default: Mua món 'best-seller' của cửa hàng, bạn có thể đặt tên tùy ý
import mySecret from './utils.js';

console.log('Using named exports:');
console.log('2 + 3 =', add(2, 3)); // Output: 2 + 3 = 5
console.log('4 * 5 =', multiply(4, 5)); // Output: 4 * 5 = 20
console.log(greeting('Creyt')); // Output: Hello, Creyt! Welcome to the ES Modules club.

console.log('\nUsing default export:');
console.log('Secret:', mySecret); // Output: Secret: This is a secret message from utils.

// Bạn cũng có thể import tất cả các named exports vào một object:
import * as Utils from './utils.js';
console.log('\nImporting all named exports as an object:');
console.log('10 + 20 =', Utils.add(10, 20)); // Output: 10 + 20 = 30

Để chạy, bạn chỉ cần mở terminal trong thư mục dự án và gõ:

node index.js

(Hoặc node index.mjs nếu bạn dùng .mjs)

Illustration

3. Mẹo (Best Practices) để 'chơi' ES Modules đỉnh cao

  • Luôn dùng đuôi file: Trong Node.js, khi import một module cục bộ, bạn phải thêm đuôi .js, .mjs, .json... Đây là một điểm khác biệt so với khi bạn import trên trình duyệt hoặc với các bundler như Webpack (nơi bạn thường bỏ qua đuôi file). Quên cái này là 'toang' ngay!
  • Thống nhất cách dùng: Nếu đã dùng "type": "module" thì cứ thế mà triển khai. Hạn chế tối đa việc trộn lẫn CommonJS (require/module.exports) và ES Modules (import/export) trong cùng một dự án lớn, trừ khi bạn là 'phù thủy' và biết mình đang làm gì. Việc này có thể dẫn đến những lỗi khó lường và 'debug' mệt nghỉ.
  • Đường dẫn tương đối: Luôn dùng đường dẫn tương đối (ví dụ: ./utils.js, ../components/button.js) cho các module cục bộ của bạn. Điều này giúp code của bạn dễ di chuyển và hoạt động tốt hơn trong các môi trường khác nhau.
  • Hiểu rõ import là async: Không giống như require của CommonJS (thường là synchronous), import về cơ bản là asynchronous. Tuy nhiên, Node.js đã tối ưu để chúng hoạt động 'như thể' synchronous trong hầu hết các trường hợp. Dù vậy, việc hiểu bản chất này sẽ giúp bạn khi làm việc với các hệ thống phức tạp hơn.
  • Tree-shaking là 'chân ái': Khi bạn chỉ import những thứ bạn cần (ví dụ: import { add } from './utils.js'; thay vì import * as Utils from './utils.js';), các bundler sẽ có thể loại bỏ phần code không dùng đến, làm ứng dụng của bạn nhẹ hơn đáng kể. Đây là một 'siêu năng lực' mà CommonJS không có được.

4. Góc nhìn học thuật sâu của Harvard: Why ES Modules?

Từ góc độ 'học thuật' (nhưng vẫn dễ hiểu nha), sự ra đời của ES Modules không chỉ là một 'cải tiến' mà là một 'cuộc cách mạng' trong việc chuẩn hóa hệ sinh thái JavaScript. Trước đây, mỗi môi trường (browser, Node.js) lại có một cách quản lý module riêng, tạo ra sự phân mảnh và đau đầu cho các nhà phát triển.

ES Modules được thiết kế để trở thành tiêu chuẩn chung của ECMAScript, nghĩa là nó hoạt động được cả trên trình duyệt lẫn Node.js (và các môi trường JavaScript khác). Điều này mang lại:

  • Tính tương thích cao: Code module của bạn có thể chạy 'ngon lành' ở mọi nơi.
  • Phân tích tĩnh (Static Analysis): Cấu trúc import/export của ES Modules cho phép các công cụ (như bundler) hiểu được mối quan hệ giữa các module ngay cả trước khi code được thực thi. Điều này là nền tảng cho các tính năng mạnh mẽ như tree-shaking và kiểm tra lỗi sớm.
  • Thiết kế bất đồng bộ: Mặc dù hiện tại Node.js đã tối ưu để import hoạt động hiệu quả, nhưng về bản chất, thiết kế của ES Modules hỗ trợ tốt cho việc tải module bất đồng bộ, rất quan trọng đối với hiệu suất trên web.
  • Loại bỏ vấn đề 'global scope pollution': Các module tạo ra các phạm vi (scope) riêng biệt, đảm bảo biến và hàm không 'làm bẩn' phạm vi toàn cục, giảm thiểu lỗi và tăng tính ổn định của ứng dụng.

5. Ví dụ thực tế: Ai đang dùng ES Modules?

'Hội' ES Modules giờ đây đông đảo vô cùng, từ các framework 'lẫy lừng' đến những công cụ 'xịn sò':

  • React, Vue, Angular: Các framework frontend này sử dụng ES Modules làm nền tảng cho việc tổ chức component và quản lý dependency. Mỗi component là một module, 'export' component chính và 'import' các component con hoặc utility khác.
  • Next.js, Nuxt.js, SvelteKit: Các framework meta này xây dựng trên React/Vue/Svelte và Node.js, tận dụng triệt để ES Modules để tối ưu hóa quá trình build và server-side rendering.
  • Webpack, Rollup, Vite: Các công cụ đóng gói (bundler) này là 'fan cuồng' của ES Modules. Chúng dùng cấu trúc import/export để phân tích cây dependency, thực hiện tree-shaking, code splitting và nhiều tối ưu hóa khác, giúp ứng dụng web của bạn 'nhanh như điện'.
  • Các thư viện Node.js hiện đại: Rất nhiều thư viện đã chuyển sang hoặc hỗ trợ cả ES Modules song song với CommonJS, ví dụ như lodash-es, date-fns.

6. Thử nghiệm và Nên dùng cho case nào?

Khi nào nên dùng ES Modules?

  • Dự án mới: Bất kỳ dự án JavaScript/Node.js nào bạn bắt đầu từ bây giờ đều nên dùng ES Modules. Đây là tương lai, là tiêu chuẩn.
  • Phát triển Frontend: Luôn luôn dùng ES Modules. Trình duyệt đã hỗ trợ native ES Modules từ lâu, và các bundler frontend cũng hoạt động tốt nhất với chúng.
  • Thư viện/package: Nếu bạn đang phát triển một thư viện để chia sẻ, việc hỗ trợ ES Modules là cực kỳ quan trọng để người dùng có thể tận dụng tree-shaking và tích hợp dễ dàng vào các dự án hiện đại.

Khi nào nên cân nhắc (hoặc tạm thời chưa dùng)?

  • Dự án cũ dùng CommonJS: Nếu bạn đang làm việc với một dự án Node.js 'lão làng' chỉ toàn CommonJS, việc chuyển đổi toàn bộ sang ES Modules có thể tốn thời gian và công sức. Hãy cân nhắc lợi ích so với chi phí. Đôi khi, bạn có thể 'dùng chung' (interop) bằng cách import CommonJS module vào ES Module, nhưng không phải lúc nào cũng mượt mà.
  • Môi trường hạn chế: Một số công cụ hoặc môi trường rất cũ có thể chưa hỗ trợ ES Modules đầy đủ. Nhưng trường hợp này ngày càng hiếm.

Thử nghiệm:

Bạn có thể thử nghiệm bằng cách tạo một dự án nhỏ với "type": "module" trong package.json và sau đó cố gắng require một module CommonJS từ một file ES Module. Node.js hỗ trợ điều này, nhưng bạn sẽ không thể import một ES Module từ một file CommonJS một cách trực tiếp. Đây là một điểm cần lưu ý khi làm việc với các dự án hybrid.

// esm-file.js (type: module)
import { someFunction } from './cjs-module.cjs'; // Có thể import CJS vào ESM
console.log(someFunction());

// cjs-module.cjs (mặc định là CommonJS)
module.exports = { someFunction: () => 'Hello from CJS!' };
// cjs-file.js (không có type: module)
// const { someFunction } = require('./esm-module.js'); // Sẽ lỗi! Không thể require ESM vào CJS trực tiếp
// Để import ESM vào CJS, bạn cần dùng dynamic import()
async function run() {
  const { greeting } = await import('./esm-module.js');
  console.log(greeting('Dynamic Import User'));
}
run();

// esm-module.js (type: module)
export const greeting = (name) => `Hello, ${name} from ESM!`;

Đó, các bạn thấy không? ES Modules không chỉ là một cú 'upgrade' về cú pháp, mà nó còn là cả một triết lý mới trong việc tổ chức và xây dựng ứng dụng JavaScript. Hãy 'ôm' lấy nó, vì nó sẽ giúp code của bạn 'sạch sẽ' hơn, 'thông minh' hơn và 'chuẩn' hơn trong thế giới lập trình hiện đại. 'Keep coding, keep learning!'.

Thuộc Series: Nodejs

Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!