Modules: ESM และ CommonJS
สองระบบ Module
หัวข้อที่มีชื่อว่า “สองระบบ Module”Node.js รองรับสองระบบ module ที่ไม่สามารถผสมกันได้อย่างอิสระ:
| ฟีเจอร์ | ESM | CommonJS |
|---|---|---|
| Syntax | import / export | require() / module.exports |
| นามสกุลไฟล์ | .mjs หรือ .js พร้อม "type":"module" | .cjs หรือ .js ไม่มี "type":"module" |
| การโหลด | Static วิเคราะห์เมื่อ parse | Dynamic รันเมื่อ runtime |
Top-level await | รองรับ | ไม่รองรับ |
| Default ใน Node 20+ | ใช่ (opt-in) | Legacy default |
CommonJS (CJS)
หัวข้อที่มีชื่อว่า “CommonJS (CJS)”CommonJS คือระบบ module ดั้งเดิมของ Node.js ยังคงใช้กันอย่างแพร่หลายใน packages และ tooling เก่า
// math.js (CommonJS)function add(a, b) { return a + b; }function multiply(a, b) { return a * b; }
module.exports = { add, multiply }; // named exports ผ่าน object// หรือ: module.exports = add; // single default export
// main.js (CommonJS)const { add, multiply } = require('./math');console.log(add(2, 3)); // 5console.log(multiply(4, 5)); // 20require() เป็น synchronous และโหลดไฟล์ทันทีเมื่อบรรทัดนั้นถูก execute ซึ่งหมายความว่าสามารถ require() ภายใน if block หรือฟังก์ชันได้
ECMAScript Modules (ESM)
หัวข้อที่มีชื่อว่า “ECMAScript Modules (ESM)”ESM คือมาตรฐาน JavaScript module อย่างเป็นทางการ ตอนนี้เป็นระบบที่แนะนำสำหรับ Node.js projects ใหม่
// math.mjs (ESM — named exports)export function add(a, b) { return a + b; }export function multiply(a, b) { return a * b; }
// utils.mjs (ESM — default export)export default function formatNumber(n) { return n.toFixed(2);}
// main.mjs (ESM — named import)import { add, multiply } from './math.mjs';import formatNumber from './utils.mjs';
console.log(add(2, 3)); // 5console.log(formatNumber(3.14159)); // '3.14'import statements เป็น static — ต้องปรากฏที่ด้านบนของไฟล์และถูก resolve ก่อนโค้ดใดๆ รัน ทำให้ bundlers สามารถทำ tree-shaking (การกำจัด dead-code) ได้
การเปิดใช้งาน ESM ใน Node.js
หัวข้อที่มีชื่อว่า “การเปิดใช้งาน ESM ใน Node.js”สองวิธีในการบอก Node.js ว่าไฟล์ใช้ ESM:
"type": "module"ในpackage.json— ไฟล์.jsทั้งหมดใน package นั้นถือเป็น ESM ใช้.cjsสำหรับไฟล์ใดๆ ที่ต้องคงเป็น CommonJS- นามสกุล
.mjs— ถือเป็น ESM เสมอไม่ว่าpackage.jsonจะเป็นอะไร
{ "name": "my-app", "type": "module"}Named vs Default Exports
หัวข้อที่มีชื่อว่า “Named vs Default Exports”// Named: export หลาย bindings import ด้วยชื่อที่แน่นอน (หรือเปลี่ยนชื่อ)export const PI = 3.14159;export function area(r) { return PI * r * r; }
import { PI, area } from './circle.mjs';import { area as circleArea } from './circle.mjs'; // เปลี่ยนชื่อ
// Default: main export หนึ่งตัวต่อไฟล์ import ด้วยชื่อใดก็ได้export default class Logger { /* ... */ }
import Logger from './logger.mjs';import MyLogger from './logger.mjs'; // เหมือนกัน แค่ชื่อ local ต่างกันDemo ESM ที่รันได้
หัวข้อที่มีชื่อว่า “Demo ESM ที่รันได้”snippet นี้รันบน Node.js runtime (module resolution ต้องการ Node) แสดงการทำงานของ ES module ที่มี named exports end-to-end โดยใช้ inline dynamic import()
// ESM inline ผ่าน data: URL — ต้องการ Node runtimeconst src = ` export function add(a, b) { return a + b; } export const VERSION = '1.0.0';`;const mod = await import('data:text/javascript,' + encodeURIComponent(src));console.log('add(3, 4):', mod.add(3, 4));console.log('VERSION:', mod.VERSION);Needs the Node.js runtime — open in StackBlitz to run.