وحدات Node.js الأساسية
تأتي Node.js مع مجموعة غنية من الوحدات المدمجة (تسمى أيضًا الوحدات الأساسية) التي توفر وظائف أساسية لبناء التطبيقات. هذه الوحدات جزء من مكتبة Node.js القياسية ولا تتطلب التثبيت—إنها متاحة جاهزة للاستخدام. في هذا الدرس، سنستكشف أهم الوحدات الأساسية ونتعلم كيفية استخدامها بفعالية.
ما هي الوحدات الأساسية؟
الوحدات الأساسية هي مكتبات C/C++ و JavaScript مُجمعة مسبقًا تأتي مع Node.js. توفر واجهات برمجة تطبيقات منخفضة المستوى للمهام الشائعة مثل عمليات نظام الملفات والشبكات والتشفير والمزيد.
الخصائص الرئيسية:
- مدمجة في Node.js (لا حاجة للتثبيت)
- محسّنة للأداء
- يتم صيانتها بواسطة فريق Node.js
- مستقرة وموثقة جيدًا
- يتم تحميلها باستخدام
require() أو import
تحميل الوحدات الأساسية
// CommonJS (Node.js التقليدية)
const fs = require('fs');
const path = require('path');
const http = require('http');
// وحدات ES (JavaScript الحديثة)
import fs from 'fs';
import path from 'path';
import http from 'http';
// استيراد دوال محددة
import { readFile, writeFile } from 'fs';
import { join, resolve } from 'path';
1. وحدة نظام الملفات (fs)
توفر وحدة fs واجهات برمجة تطبيقات للتفاعل مع نظام الملفات—قراءة وكتابة وتحديث وحذف الملفات والدلائل.
قراءة الملفات
const fs = require('fs');
// غير متزامن (غير محظور) - موصى به
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('خطأ في قراءة الملف:', err);
return;
}
console.log('محتوى الملف:', data);
});
// متزامن (محظور) - استخدمه بحذر
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log('محتوى الملف:', data);
} catch (err) {
console.error('خطأ في قراءة الملف:', err);
}
// قائم على الوعود (النهج الحديث)
const fsPromises = require('fs').promises;
async function readFileAsync() {
try {
const data = await fsPromises.readFile('example.txt', 'utf8');
console.log('محتوى الملف:', data);
} catch (err) {
console.error('خطأ في قراءة الملف:', err);
}
}
أفضل ممارسة: استخدم دائمًا الطرق غير المتزامنة (readFile) أو واجهات برمجة التطبيقات القائمة على الوعود في الإنتاج لتجنب حظر حلقة الأحداث. استخدم الطرق المتزامنة (readFileSync) فقط أثناء التهيئة أو في أدوات CLI.
كتابة الملفات
const fs = require('fs');
// كتابة سلسلة إلى ملف (استبدال المحتوى الموجود)
fs.writeFile('output.txt', 'مرحبًا Node.js!', 'utf8', (err) => {
if (err) {
console.error('خطأ في كتابة الملف:', err);
return;
}
console.log('تمت كتابة الملف بنجاح');
});
// الإلحاق بالملف
fs.appendFile('log.txt', 'إدخال سجل جديد\n', (err) => {
if (err) throw err;
console.log('تمت إضافة إدخال السجل');
});
// كتابة بيانات JSON
const data = { name: 'John', age: 30 };
fs.writeFile('data.json', JSON.stringify(data, null, 2), 'utf8', (err) => {
if (err) throw err;
console.log('تم حفظ ملف JSON');
});
العمل مع الدلائل
const fs = require('fs');
// إنشاء دليل
fs.mkdir('uploads', { recursive: true }, (err) => {
if (err) throw err;
console.log('تم إنشاء الدليل');
});
// قراءة محتويات الدليل
fs.readdir('./', (err, files) => {
if (err) throw err;
console.log('الملفات في الدليل:', files);
});
// التحقق من وجود ملف/دليل
fs.access('example.txt', fs.constants.F_OK, (err) => {
if (err) {
console.log('الملف غير موجود');
} else {
console.log('الملف موجود');
}
});
// الحصول على معلومات الملف/الدليل
fs.stat('example.txt', (err, stats) => {
if (err) throw err;
console.log('هل هو ملف:', stats.isFile());
console.log('هل هو دليل:', stats.isDirectory());
console.log('الحجم:', stats.size, 'بايت');
console.log('تم التعديل:', stats.mtime);
});
2. وحدة المسار (path)
توفر وحدة path أدوات للعمل مع مسارات الملفات والدلائل بطريقة متعددة المنصات.
const path = require('path');
// دمج شرائح المسار
const fullPath = path.join('/users', 'john', 'documents', 'file.txt');
console.log(fullPath); // /users/john/documents/file.txt
// حل المسار المطلق
const absolutePath = path.resolve('files', 'data.txt');
console.log(absolutePath); // /current/working/directory/files/data.txt
// الحصول على امتداد الملف
const ext = path.extname('document.pdf');
console.log(ext); // .pdf
// الحصول على اسم الملف
const fileName = path.basename('/path/to/file.txt');
console.log(fileName); // file.txt
// الحصول على اسم الملف بدون الامتداد
const name = path.basename('/path/to/file.txt', '.txt');
console.log(name); // file
// الحصول على اسم الدليل
const dirName = path.dirname('/path/to/file.txt');
console.log(dirName); // /path/to
// تحليل المسار إلى كائن
const parsed = path.parse('/home/user/file.txt');
console.log(parsed);
// {
// root: '/',
// dir: '/home/user',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }
// بناء المسار من كائن
const formatted = path.format({
dir: '/home/user',
base: 'file.txt'
});
console.log(formatted); // /home/user/file.txt
المسارات متعددة المنصات: استخدم دائمًا path.join() أو path.resolve() بدلاً من دمج المسارات يدويًا باستخدام / أو \. يضمن ذلك أن الكود الخاص بك يعمل بشكل صحيح على Windows و macOS و Linux.
3. وحدة نظام التشغيل (os)
توفر وحدة os طرقًا وخصائص مرتبطة بنظام التشغيل.
const os = require('os');
// الحصول على المنصة
console.log('المنصة:', os.platform()); // darwin, win32, linux
// الحصول على البنية
console.log('البنية:', os.arch()); // x64, arm64
// الحصول على معلومات CPU
console.log('المعالجات:', os.cpus().length, 'نواة');
console.log('طراز CPU:', os.cpus()[0].model);
// الحصول على معلومات الذاكرة
console.log('الذاكرة الإجمالية:', os.totalmem() / 1024 / 1024 / 1024, 'GB');
console.log('الذاكرة الحرة:', os.freemem() / 1024 / 1024 / 1024, 'GB');
// الحصول على وقت تشغيل النظام
console.log('وقت التشغيل:', os.uptime() / 60 / 60, 'ساعة');
// الحصول على الدليل الرئيسي
console.log('الدليل الرئيسي:', os.homedir());
// الحصول على الدليل المؤقت
console.log('الدليل المؤقت:', os.tmpdir());
// الحصول على اسم المضيف
console.log('اسم المضيف:', os.hostname());
// الحصول على واجهات الشبكة
console.log('واجهات الشبكة:', os.networkInterfaces());
4. وحدة HTTP (http)
تسمح لك وحدة http بإنشاء خوادم HTTP وإجراء طلبات HTTP.
إنشاء خادم HTTP
const http = require('http');
// إنشاء الخادم
const server = http.createServer((req, res) => {
// تعيين رؤوس الاستجابة
res.writeHead(200, { 'Content-Type': 'text/plain' });
// التعامل مع مسارات مختلفة
if (req.url === '/') {
res.end('مرحبًا بك في خادم Node.js HTTP');
} else if (req.url === '/api') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'نقطة نهاية API' }));
} else {
res.writeHead(404);
res.end('404 غير موجود');
}
});
// بدء الخادم
const PORT = 3000;
server.listen(PORT, () => {
console.log(`الخادم يعمل على http://localhost:${PORT}/`);
});
إجراء طلبات HTTP
const http = require('http');
// طلب GET
http.get('http://api.example.com/users', (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('الاستجابة:', JSON.parse(data));
});
}).on('error', (err) => {
console.error('خطأ:', err);
});
// طلب POST
const postData = JSON.stringify({ name: 'John', age: 30 });
const options = {
hostname: 'api.example.com',
port: 80,
path: '/users',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};
const req = http.request(options, (res) => {
console.log('الحالة:', res.statusCode);
res.on('data', (chunk) => {
console.log('الاستجابة:', chunk.toString());
});
});
req.on('error', (err) => {
console.error('خطأ:', err);
});
req.write(postData);
req.end();
5. وحدة الأحداث (events)
توفر وحدة events فئة EventEmitter للعمل مع الأحداث.
const EventEmitter = require('events');
// إنشاء مُصدر أحداث
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
// تسجيل مستمع للأحداث
myEmitter.on('event', (arg) => {
console.log('حدث وقع:', arg);
});
// تسجيل مستمع لمرة واحدة
myEmitter.once('singleEvent', () => {
console.log('سيعمل هذا مرة واحدة فقط');
});
// إطلاق الأحداث
myEmitter.emit('event', 'مرحبًا');
myEmitter.emit('event', 'عالم');
myEmitter.emit('singleEvent'); // يعمل
myEmitter.emit('singleEvent'); // لا يعمل
// مثال واقعي: تسجيل المستخدم
class UserManager extends EventEmitter {
register(user) {
console.log(`تسجيل المستخدم: ${user.name}`);
this.emit('userRegistered', user);
}
}
const userManager = new UserManager();
userManager.on('userRegistered', (user) => {
console.log('إرسال بريد إلكتروني ترحيبي إلى:', user.email);
});
userManager.on('userRegistered', (user) => {
console.log('إنشاء ملف تعريف المستخدم لـ:', user.name);
});
userManager.register({ name: 'John', email: 'john@example.com' });
6. وحدة Buffer (buffer)
تُستخدم Buffers للتعامل مع البيانات الثنائية. إنها مفيدة بشكل خاص عند العمل مع التدفقات والملفات وعمليات الشبكة.
// إنشاء buffers
const buf1 = Buffer.from('Hello');
const buf2 = Buffer.from([72, 101, 108, 108, 111]); // أكواد ASCII
const buf3 = Buffer.alloc(10); // 10 بايت مملوءة بأصفار
const buf4 = Buffer.allocUnsafe(10); // أسرع ولكن يحتوي على بيانات قديمة
console.log(buf1); // <Buffer 48 65 6c 6c 6f>
console.log(buf1.toString()); // Hello
console.log(buf1.toString('hex')); // 48656c6c6f
console.log(buf1.toString('base64')); // SGVsbG8=
// الكتابة إلى buffer
buf3.write('Node.js');
console.log(buf3.toString()); // Node.js
// عمليات Buffer
const buf5 = Buffer.concat([buf1, Buffer.from(' World')]);
console.log(buf5.toString()); // Hello World
// مقارنة buffers
const buf6 = Buffer.from('ABC');
const buf7 = Buffer.from('DEF');
console.log(buf6.compare(buf7)); // -1 (buf6 يأتي قبل buf7)
// التحقق من المساواة
console.log(buf6.equals(buf7)); // false
7. وحدة التدفق (stream)
تسمح لك التدفقات بمعالجة البيانات قطعة قطعة دون تحميل كل شيء في الذاكرة مرة واحدة. مثالية للتعامل مع الملفات الكبيرة أو البيانات في الوقت الفعلي.
const fs = require('fs');
// تدفق قابل للقراءة
const readStream = fs.createReadStream('large-file.txt', 'utf8');
readStream.on('data', (chunk) => {
console.log('تم استلام قطعة:', chunk.length, 'بايت');
});
readStream.on('end', () => {
console.log('انتهت قراءة الملف');
});
readStream.on('error', (err) => {
console.error('خطأ:', err);
});
// تدفق قابل للكتابة
const writeStream = fs.createWriteStream('output.txt');
writeStream.write('السطر الأول\n');
writeStream.write('السطر الثاني\n');
writeStream.end('السطر الأخير\n');
// توجيه التدفقات (نسخ ملف فعال)
const source = fs.createReadStream('source.txt');
const destination = fs.createWriteStream('destination.txt');
source.pipe(destination);
// تدفق التحويل (معالجة البيانات أثناء التدفق)
const { Transform } = require('stream');
const upperCaseTransform = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
fs.createReadStream('input.txt')
.pipe(upperCaseTransform)
.pipe(fs.createWriteStream('output-upper.txt'));
8. وحدة URL (url)
توفر وحدة url أدوات لتحليل URL وتنسيقها.
const url = require('url');
// تحليل URL
const myUrl = new URL('https://example.com:8080/path?name=John&age=30#section');
console.log(myUrl.protocol); // https:
console.log(myUrl.hostname); // example.com
console.log(myUrl.port); // 8080
console.log(myUrl.pathname); // /path
console.log(myUrl.search); // ?name=John&age=30
console.log(myUrl.hash); // #section
// الحصول على معاملات الاستعلام
console.log(myUrl.searchParams.get('name')); // John
console.log(myUrl.searchParams.get('age')); // 30
// إضافة معاملات الاستعلام
myUrl.searchParams.append('city', 'New York');
console.log(myUrl.toString());
// واجهة برمجة التطبيقات القديمة (لا تزال مفيدة)
const urlString = 'https://example.com/path?name=John';
const parsedUrl = url.parse(urlString, true);
console.log(parsedUrl.query); // { name: 'John' }
9. وحدة التشفير (crypto)
توفر وحدة crypto وظائف التشفير بما في ذلك التجزئة والتشفير وتوليد الأرقام العشوائية.
const crypto = require('crypto');
// إنشاء hash (SHA256)
const hash = crypto.createHash('sha256');
hash.update('password123');
console.log('Hash:', hash.digest('hex'));
// إنشاء HMAC
const hmac = crypto.createHmac('sha256', 'secret-key');
hmac.update('بيانات مهمة');
console.log('HMAC:', hmac.digest('hex'));
// إنشاء بايتات عشوائية
crypto.randomBytes(16, (err, buffer) => {
if (err) throw err;
console.log('رمز عشوائي:', buffer.toString('hex'));
});
// تجزئة كلمة المرور باستخدام scrypt
const password = 'myPassword123';
const salt = crypto.randomBytes(16).toString('hex');
crypto.scrypt(password, salt, 64, (err, derivedKey) => {
if (err) throw err;
console.log('كلمة مرور مجزأة:', derivedKey.toString('hex'));
});
// التشفير وفك التشفير
const algorithm = 'aes-256-cbc';
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
function encrypt(text) {
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
function decrypt(encrypted) {
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const message = 'رسالة سرية';
const encrypted = encrypt(message);
const decrypted = decrypt(encrypted);
console.log('الأصلي:', message);
console.log('مشفر:', encrypted);
console.log('فك التشفير:', decrypted);
تمرين عملي: مدير ملفات CLI
أنشئ مدير ملفات لسطر الأوامر باستخدام الوحدات الأساسية:
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
async function fileManager() {
const command = process.argv[2];
const arg1 = process.argv[3];
const arg2 = process.argv[4];
try {
switch (command) {
case 'list':
const files = await fs.readdir(arg1 || './');
console.log('الملفات:', files.join(', '));
break;
case 'read':
const content = await fs.readFile(arg1, 'utf8');
console.log('المحتوى:', content);
break;
case 'write':
await fs.writeFile(arg1, arg2);
console.log('تمت كتابة الملف بنجاح');
break;
case 'info':
const stats = await fs.stat(arg1);
console.log('الحجم:', stats.size, 'بايت');
console.log('تم التعديل:', stats.mtime);
console.log('هل هو ملف:', stats.isFile());
break;
case 'system':
console.log('المنصة:', os.platform());
console.log('نوى CPU:', os.cpus().length);
console.log('الذاكرة الحرة:', os.freemem() / 1024 / 1024, 'MB');
break;
default:
console.log('أمر غير معروف');
}
} catch (err) {
console.error('خطأ:', err.message);
}
}
fileManager();
// الاستخدام:
// node file-manager.js list ./
// node file-manager.js read file.txt
// node file-manager.js write test.txt "مرحبًا"
// node file-manager.js info file.txt
// node file-manager.js system
الملخص
في هذا الدرس، تعلمت عن وحدات Node.js الأساسية:
- fs: عمليات نظام الملفات (قراءة، كتابة، دلائل)
- path: معالجة المسارات متعددة المنصات
- os: معلومات نظام التشغيل والأدوات
- http: إنشاء الخوادم وإجراء طلبات HTTP
- events: البرمجة الموجهة بالأحداث مع EventEmitter
- buffer: العمل مع البيانات الثنائية
- stream: معالجة البيانات بكفاءة قطعة قطعة
- url: تحليل URL ومعالجتها
- crypto: العمليات التشفيرية والأمان
تشكل هذه الوحدات الأساسية أساس معظم تطبيقات Node.js. في الدرس التالي، سنغوص بعمق في أنماط البرمجة غير المتزامنة في Node.js!