Họ đang đo gì
Bạn có hiểu công cụ build của mình không, hay chỉ copy cấu hình cho tới khi hết lỗi.
Trả lời ngắn~30 giây
ESM có cấu trúc tĩnh: import được phân tích trước khi bất kỳ dòng nào chạy, nên bundler biết chắc thứ gì được dùng và loại bỏ được phần thừa (tree shaking). CommonJS thì require() là một lời gọi hàm bình thường, chạy lúc runtime, đặt trong if cũng được — nên không phân tích tĩnh triệt để được. Đau đớn khi trộn đến từ chỗ ESM nạp bất đồng bộ còn require thì đồng bộ, nên CJS không require thẳng một module ESM được.
Giải thích sâu
Hệ quả thực tế hay gặp nhất là lỗi ERR_REQUIRE_ESM: một thư viện chuyển sang ESM thuần, code của bạn còn CJS, và không có cách nào require nó đồng bộ vì ESM có thể có top-level await. Cách thoát là await import() động, hoặc chuyển cả dự án sang ESM. Node 22 trở đi đã nới bằng require(esm) cho các module không có top-level await, nhưng vẫn cần biết ranh giới đó ở đâu.
Khác biệt thứ hai ít được nhắc: ESM xuất ra BINDING sống, CJS xuất ra giá trị đã sao chép. Nếu module A gán lại biến đã export, bên import ESM sẽ thấy giá trị mới, còn bên require giữ nguyên giá trị cũ. Chi tiết này hiếm khi gặp nhưng khi gặp thì rất khó gỡ, vì nó trông như bug logic chứ không như bug module.
Về tree shaking, điều đáng nói là nó không miễn phí: nó chỉ hoạt động khi module không có side effect, và bundler cần bạn khai "sideEffects": false trong package.json để tự tin loại bỏ. Một thư viện import file CSS ở cấp module coi như có side effect, và cả cây phụ thuộc đó ở lại trong bundle. Đây là lý do rất phổ biến khiến “đã dùng ESM mà bundle vẫn to”.
Câu hỏi tiếp theo họ sẽ hỏi
?import() động có phá tree shaking không?
Không, nó tạo ra một chunk riêng — đó là code splitting, và thường là điều bạn muốn. Cái phá tree shaking là import() với đường dẫn dựng từ biến, vì bundler phải gộp mọi khả năng vào chunk.
?"type": "module" trong package.json làm gì?
Nó quyết định file .js được đọc là ESM hay CJS. Muốn trộn thì dùng đuôi tường minh: .mjs luôn là ESM, .cjs luôn là CJS, bất kể cấu hình.
Trả lời thế này là mất điểm
- Nói “ESM chỉ là cú pháp mới của require”. Cơ chế nạp khác nhau về bản chất, và đó là toàn bộ vấn đề tương thích.