الـ Modules في Node.js — Node.js و Express
الوحدات (Modules) في Node.js
كل ملف في Node وحدة لها نطاقها الخاص: المتغيرات لا تتسرب لغيرها إلا ما تصدّره صراحة. يوجد نظامان — ستقابل الاثنين.
1. CommonJS (الأقدم، ما زال شائعاً)
// math.js
const add = (a, b) => a + b;
const PI = 3.14159;
module.exports = { add, PI };// app.js
const { add, PI } = require("./math"); // ./ = ملف محلي
console.log(add(2, 3), PI);- require متزامن، ويُخزَّن ناتجه: استدعاء الوحدة مرتين يعيد نفس الكائن.
- الامتداد .js اختياري في require.
2. ES Modules (المعيار الحديث)
// math.mjs
export const add = (a, b) => a + b;
export default function multiply(a, b) { return a * b; }// app.mjs
import multiply, { add } from "./math.mjs"; // الامتداد إلزامي
console.log(add(2, 3), multiply(2, 3));لتفعيله لكل ملفات .js: أضف "type": "module" إلى package.json. مزاياه: نفس صيغة المتصفح، وawait في المستوى الأعلى مسموح، وتحليل ثابت (أدوات البناء تحذف الكود غير المستخدم).
| | CommonJS | ES Modules |
|---|---|---|
| التصدير | module.exports | export |
| الاستيراد | require() | import |
| await في المستوى الأعلى | ❌ | ✅ |
| __dirname | موجود | import.meta.dirname (Node 20.11+) |
للمشاريع الجديدة: ES Modules. ولا تخلط الاثنين في نفس الملف.
الوحدات المدمجة
const path = require("node:path");
const os = require("node:os");
console.log(path.join("uploads", "images", "a.png")); // يستخدم فاصل النظام الصحيح
console.log(path.extname("report.pdf")); // .pdf
console.log(os.cpus().length, "نواة");البادئة node: توضح أنها وحدة مدمجة لا حزمة من npm. أشهرها: fs و path و http و crypto و events و os و url.
كيف يجد Node الوحدة؟
- ./ أو ../: ملف نسبي لمكان الملف الحالي.
- اسم بلا مسار (express): حزمة في node_modules (الدرس القادم).
- node:...: وحدة مدمجة.
تمرين
أنشئ utils/format.js يصدّر formatPrice(n) (مثلاً "1,500 د.ع") و slugify(text)، واستورده في app.js مرة بـ CommonJS ومرة بنسخة ES Modules (.mjs).
// مثال واحد يحاكي ملفين ليعمل مباشرة.
// في مشروع حقيقي: كل قسم في ملفه، مع module.exports و require.
// ===== math.js =====
const mathModule = (() => {
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const divide = (a, b) => {
if (b === 0) throw new RangeError("لا يمكن القسمة على صفر");
return a / b;
};
const secretHelper = () => "خاص بالوحدة — غير مصدَّر";
return { add, subtract, divide }; // module.exports = { add, subtract, divide };
})();
// ===== app.js =====
// const { add, subtract, divide } = require('./math');
const { add, subtract, divide } = mathModule;
console.log("2 + 3 =", add(2, 3));
console.log("10 - 4 =", subtract(10, 4));
try {
divide(5, 0);
} catch (err) {
console.log("خطأ:", err.message);
}
console.log("secretHelper مُصدَّرة؟", "secretHelper" in mathModule);
// ===== الوحدات المدمجة =====
const path = require("node:path");
const os = require("node:os");
console.log(path.join("uploads", "2026", "avatar.png"));
console.log("الامتداد:", path.extname("report.final.pdf"));
console.log("نظام التشغيل:", os.platform());اختبر فهمك