Node.js

الوحدات ونظام الملفات في Node.js — دليل شامل 2026

📅 2026-11-03⏱ 8 دقائق قراءة
في المقال السابق، كتبت أول برنامج Node.js. الآن سنتعمق في **الوحدات (Modules)** و **نظام الملفات (File System)** — وهما أساس أي تطبيق Node.js حقيقي. في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم الوحدات ونظام الملفات، مع تمارين وحلول. ## ما هي الوحدة (Module)؟ **الوحدة** هي **ملف JavaScript** يمكن استيراده في ملفات أخرى. **الفكرة:** بدلاً من كتابة كل الكود في ملف واحد كبير، نقسمه إلى وحدات صغيرة: - **`math.js`** — دوال رياضية. - **`user.js`** — دوال المستخدم. - **`database.js`** — دوال قاعدة البيانات. **الفائدة:** - تنظيم الكود. - إعادة الاستخدام. - سهولة الصيانة. ## نظاما الوحدات في Node.js <table> <thead> <tr> <th>المعيار</th> <th>CommonJS</th> <th>ES Modules</th> </tr> </thead> <tbody> <tr> <td><strong>الصيغة</strong></td> <td><code>require</code> / <code>module.exports</code></td> <td><code>import</code> / <code>export</code></td> </tr> <tr> <td><strong>الامتداد</strong></td> <td><code>.js</code></td> <td><code>.mjs</code> أو <code>"type": "module"</code></td> </tr> <tr> <td><strong>الحداثة</strong></td> <td>قديم (افتراضي)</td> <td>حديث (ES6)</td> </tr> <tr> <td><strong>الاستخدام</strong></td> <td>شائع في Node.js</td> <td>المعيار الحديث</td> </tr> </tbody> </table> ## CommonJS — الطريقة التقليدية ### 1. تصدير دالة واحدة **`greet.js`:** ```javascript function greet(name) { return `مرحباً ${name}!`; } module.exports = greet; ``` **`index.js`:** ```javascript const greet = require("./greet"); console.log(greet("أحمد")); // مرحباً أحمد! ``` ### 2. تصدير عدة دوال (كائن) **`math.js`:** ```javascript function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } module.exports = { add, subtract }; ``` **`index.js`:** ```javascript const math = require("./math"); console.log(math.add(5, 3)); // 8 console.log(math.subtract(5, 3)); // 2 ``` **أو باستخدام Destructuring:** ```javascript const { add, subtract } = require("./math"); console.log(add(5, 3)); // 8 console.log(subtract(5, 3)); // 2 ``` ### 3. تصدير مباشر **`user.js`:** ```javascript exports.name = "أحمد"; exports.age = 25; exports.email = "ahmed@example.com"; ``` **أو:** ```javascript module.exports = { name: "أحمد", age: 25, email: "ahmed@example.com", }; ``` ## ES Modules — الطريقة الحديثة ### 1. الإعداد **في `package.json`:** ```json { "type": "module" } ``` **أو** استخدم امتداد `.mjs`: ``` math.mjs index.mjs ``` ### 2. تصدير مُسمّى (Named Export) **`math.js`:** ```javascript export function add(a, b) { return a + b; } export function subtract(a, b) { return a - b; } ``` **`index.js`:** ```javascript import { add, subtract } from "./math.js"; console.log(add(5, 3)); // 8 console.log(subtract(5, 3)); // 2 ``` ### 3. تصدير افتراضي (Default Export) **`greet.js`:** ```javascript export default function greet(name) { return `مرحباً ${name}!`; } ``` **`index.js`:** ```javascript import greet from "./greet.js"; console.log(greet("أحمد")); // مرحباً أحمد! ``` ### 4. خلط التصديرين **`utils.js`:** ```javascript export default function main() { return "الدالة الرئيسية"; } export function helper() { return "دالة مساعدة"; } ``` **`index.js`:** ```javascript import main, { helper } from "./utils.js"; ``` ## جدول مقارنة سريعة <table> <thead> <tr> <th>العملية</th> <th>CommonJS</th> <th>ES Modules</th> </tr> </thead> <tbody> <tr> <td><strong>التصدير</strong></td> <td><code>module.exports = ...</code></td> <td><code>export ...</code></td> </tr> <tr> <td><strong>الاستيراد</strong></td> <td><code>require("...")</code></td> <td><code>import ... from "..."</code></td> </tr> <tr> <td><strong>الامتداد</strong></td> <td><code>.js</code></td> <td><code>.mjs</code> أو <code>"type": "module"</code></td> </tr> </tbody> </table> ## نظام الملفات (fs) **`fs`** هي وحدة مدمجة للتعامل مع الملفات والمجلدات. ### 1. استيراد `fs` **CommonJS:** ```javascript const fs = require("fs"); ``` **ES Modules:** ```javascript import fs from "fs"; ``` **مع Promise (موصى به):** ```javascript const fs = require("fs/promises"); // أو import fs from "fs/promises"; ``` ### 2. قراءة ملف (متزامن) ```javascript const fs = require("fs"); const content = fs.readFileSync("file.txt", "utf-8"); console.log(content); ``` **⚠️ تحذير:** `readFileSync` **يحجب** التنفيذ حتى ينتهي. ### 3. قراءة ملف (غير متزامن — موصى به) **مع Callback:** ```javascript const fs = require("fs"); fs.readFile("file.txt", "utf-8", (err, data) => { if (err) { console.error("خطأ:", err.message); return; } console.log(data); }); ``` **مع Promise:** ```javascript const fs = require("fs/promises"); async function readFile() { try { const content = await fs.readFile("file.txt", "utf-8"); console.log(content); } catch (error) { console.error("خطأ:", error.message); } } readFile(); ``` ### 4. كتابة ملف ```javascript const fs = require("fs/promises"); async function writeFile() { try { await fs.writeFile("output.txt", "مرحباً من Node.js!"); console.log("تم الكتابة!"); } catch (error) { console.error("خطأ:", error.message); } } writeFile(); ``` ### 5. إضافة إلى ملف (Append) ```javascript const fs = require("fs/promises"); await fs.appendFile("log.txt", "سطر جديد\n"); ``` ### 6. حذف ملف ```javascript const fs = require("fs/promises"); await fs.unlink("old-file.txt"); ``` ### 7. التحقق من وجود ملف ```javascript const fs = require("fs/promises"); async function fileExists(path) { try { await fs.access(path); return true; } catch { return false; } } console.log(await fileExists("file.txt")); ``` ## العمل مع المجلدات ### 1. إنشاء مجلد ```javascript const fs = require("fs/promises"); // إنشاء مجلد await fs.mkdir("new-folder"); // إنشاء مجلدات متداخلة await fs.mkdir("a/b/c", { recursive: true }); ``` ### 2. قراءة محتوى مجلد ```javascript const fs = require("fs/promises"); const files = await fs.readdir("./"); console.log(files); // ["file1.js", "file2.txt", ...] ``` ### 3. حذف مجلد ```javascript const fs = require("fs/promises"); // حذف مجلد فارغ await fs.rmdir("empty-folder"); // حذف مجلد ومحتواه await fs.rm("folder", { recursive: true, force: true }); ``` ## مثال عملي: دفتر ملاحظات **`notes.js`:** ```javascript const fs = require("fs/promises"); const path = require("path"); const NOTES_FILE = "notes.json"; // قراءة الملاحظات async function getNotes() { try { const data = await fs.readFile(NOTES_FILE, "utf-8"); return JSON.parse(data); } catch { return []; } } // إضافة ملاحظة async function addNote(text) { const notes = await getNotes(); const newNote = { id: Date.now(), text, createdAt: new Date().toISOString(), }; notes.push(newNote); await fs.writeFile(NOTES_FILE, JSON.stringify(notes, null, 2)); return newNote; } // حذف ملاحظة async function deleteNote(id) { const notes = await getNotes(); const filtered = notes.filter((n) => n.id !== id); await fs.writeFile(NOTES_FILE, JSON.stringify(filtered, null, 2)); } // عرض الملاحظات async function listNotes() { const notes = await getNotes(); if (notes.length === 0) { console.log("لا توجد ملاحظات"); return; } notes.forEach((note) => { console.log(`[${note.id}] ${note.text}`); }); } module.exports = { getNotes, addNote, deleteNote, listNotes }; ``` **`index.js`:** ```javascript const notes = require("./notes"); async function main() { await notes.addNote("تعلم Node.js"); await notes.addNote("بناء مشروع"); await notes.listNotes(); } main(); ``` ## تمارين عملية ### تمرين 1: وحدة رياضية أنشئ وحدة `math.js` تحتوي على 4 دوال رياضية. **الحل:** ```javascript // math.js function add(a, b) { return a + b; } function subtract(a, b) { return a - b; } function multiply(a, b) { return a * b; } function divide(a, b) { if (b === 0) throw new Error("لا يمكن القسمة على صفر"); return a / b; } module.exports = { add, subtract, multiply, divide }; ``` ### تمرين 2: قراءة ملف اقرأ ملف نصي واطبع محتواه. **الحل:** ```javascript const fs = require("fs/promises"); async function readAndPrint(file) { try { const content = await fs.readFile(file, "utf-8"); console.log(content); } catch (error) { console.error("خطأ:", error.message); } } readAndPrint("file.txt"); ``` ### تمرين 3: كتابة ملف اكتب ملفاً يحتوي على قائمة أسماء. **الحل:** ```javascript const fs = require("fs/promises"); async function writeNames() { const names = ["أحمد", "محمد", "علي"]; await fs.writeFile("names.txt", names.join("\n")); console.log("تم!"); } writeNames(); ``` ### تمرين 4: سجل الأخطاء أنشئ وحدة تسجل الأخطاء في ملف. **الحل:** ```javascript const fs = require("fs/promises"); async function logError(message) { const timestamp = new Date().toISOString(); const line = `[${timestamp}] ${message}\n`; await fs.appendFile("errors.log", line); } module.exports = { logError }; ``` ### تمرين 5: عد الأسطر اقرأ ملفاً واحسب عدد أسطره. **الحل:** ```javascript const fs = require("fs/promises"); async function countLines(file) { const content = await fs.readFile(file, "utf-8"); return content.split("\n").length; } countLines("file.txt").then(console.log); ``` ### تمرين 6: نسخ ملف انسخ ملفاً إلى مكان آخر. **الحل:** ```javascript const fs = require("fs/promises"); async function copyFile(src, dest) { const content = await fs.readFile(src); await fs.writeFile(dest, content); console.log("تم النسخ!"); } copyFile("source.txt", "backup.txt"); ``` ### تمرين 7: عرض محتوى مجلد اعرض كل ملفات مجلد معين. **الحل:** ```javascript const fs = require("fs/promises"); async function listFiles(dir) { const files = await fs.readdir(dir); files.forEach((file) => console.log(file)); } listFiles("./"); ``` ### تمرين 8: دفتر ملاحظات كامل أنشئ تطبيق دفتر ملاحظات كامل (إضافة، حذف، عرض). **الحل:** (راجع المثال العملي أعلاه) ## حل المشاكل الشائعة ### 🔴 المشكلة 1: `ENOENT: no such file or directory` **السبب:** الملف غير موجود. **الحل:** تحقق من المسار، أو أنشئ الملف: ```javascript try { await fs.readFile("file.txt", "utf-8"); } catch (error) { if (error.code === "ENOENT") { console.log("الملف غير موجود"); } } ``` ### 🔴 المشكلة 2: `Cannot find module 'xxx'` **السبب:** الوحدة غير موجودة. **الحل:** تحقق من: - المسار (`./` للوحدة المحلية). - الاسم. - الامتداد. ### 🔴 المشكلة 3: `require is not defined` **السبب:** استخدمت `"type": "module"` في `package.json`، لكنك تستخدم `require`. **الحل:** ```javascript // بدلاً من require: import fs from "fs"; ``` ### 🔴 المشكلة 4: `import` لا يعمل **السبب:** لم تُضف `"type": "module"`. **الحل:** ```json { "type": "module" } ``` ### 🔴 المشكلة 5: `Cannot use import statement outside a module` **السبب:** نفس المشكلة السابقة. **الحل:** أضف `"type": "module"` في `package.json`. ## جدول دوال `fs` <table> <thead> <tr> <th>الدالة</th> <th>الوظيفة</th> </tr> </thead> <tbody> <tr> <td><code>fs.readFile()</code></td> <td>قراءة ملف</td> </tr> <tr> <td><code>fs.writeFile()</code></td> <td>كتابة ملف</td> </tr> <tr> <td><code>fs.appendFile()</code></td> <td>إضافة لملف</td> </tr> <tr> <td><code>fs.unlink()</code></td> <td>حذف ملف</td> </tr> <tr> <td><code>fs.mkdir()</code></td> <td>إنشاء مجلد</td> </tr> <tr> <td><code>fs.readdir()</code></td> <td>قراءة محتوى مجلد</td> </tr> <tr> <td><code>fs.rm()</code></td> <td>حذف مجلد</td> </tr> <tr> <td><code>fs.access()</code></td> <td>التحقق من الوجود</td> </tr> </tbody> </table> ## قائمة تحقق نهائية <table> <thead> <tr> <th>المهمة</th> <th>الحالة</th> </tr> </thead> <tbody> <tr> <td>فهم الوحدات (Modules)</td> <td>⬜</td> </tr> <tr> <td>استخدام <code>require</code> و <code>module.exports</code></td> <td>⬜</td> </tr> <tr> <td>استخدام <code>import</code> و <code>export</code></td> <td>⬜</td> </tr> <tr> <td>قراءة وكتابة الملفات</td> <td>⬜</td> </tr> <tr> <td>العمل مع المجلدات</td> <td>⬜</td> </tr> <tr> <td>بناء دفتر ملاحظات</td> <td>⬜</td> </tr> <tr> <td>حل التمارين الثمانية</td> <td>⬜</td> </tr> </tbody> </table> ## ماذا بعد هذا المقال؟ الآن بعد أن أتقنت الوحدات ونظام الملفات، أنت جاهز للمقال التالي: 1. **npm وإدارة الحزم** — تثبيت المكتبات. 2. **بناء HTTP Server** — أول سيرفر. 3. **Express.js** — إطار العمل. ## الخلاصة في هذا المقال، تعلمت: - ✅ ما هي الوحدات (Modules). - ✅ CommonJS (`require` / `module.exports`). - ✅ ES Modules (`import` / `export`). - ✅ نظام الملفات (`fs`). - ✅ قراءة وكتابة وحذف الملفات. - ✅ العمل مع المجلدات. - ✅ بناء دفتر ملاحظات كامل. - ✅ حل 8 تمارين عملية. **تذكر:** الوحدات ونظام الملفات هما أساس أي تطبيق Node.js حقيقي.