Node.js: وحدتا path و url

آخر تحديث: 2026-08-26

1. القصة: كارثة في عملية النشر بسبب فاصل

أُجريت اختبارات على أداة CLI التي طورها بوب على نظام macOS وكانت النتائج مثالية — حيث استُخدمت / في ربط المسارات، كما سارت عمليات قراءة التكوين وكتابة السجلات دون أي مشاكل. ومع ذلك، بعد نشرها على خادم Linux، أبلغ البرنامج على الفور عن حدوث خطأ: ENOENT: no such file or directory. وعند التحقيق في الأمر، تبين أن بوب قد قام بترميز / بشكل ثابت كفاصل للمسارات في الكود، في حين أن بعض منطق معالجة المسارات في نظام Windows يستخدم \، مما أدى إلى حدوث خلط في تحليل المسارات. وقد منح هذا الحادث بوب فهمًا عميقًا للغرض من وحدة path — ألا يتم أبدًا ربط المسارات يدويًّا.

(1) ستتعلم



2. الطرق الأساسية في وحدة «path»

الوحدة النمطية path هي وحدة نمطية مدمجة في Node.js توفر أدوات لتسلسل مسارات الملفات وتحليلها وتنسيقها، مع معالجة الاختلافات في فواصل المسارات عبر أنظمة التشغيل تلقائيًّا.

(1) ربط المسارات — تسلسل المسارات

path.join() يدمج عدة مقاطع مسار في مسار واحد موحد، وذلك تلقائيًا باستخدام الفاصل المستخدم حاليًا في النظام.

▶ مثال: التسلسل الأساسي للمسارات باستخدام path.join

JAVASCRIPT
const path = require('path');

const fullPath = path.join('/app', 'src', 'utils', 'helper.js');
console.log(fullPath);
// macOS/Linux: /app/src/utils/helper.js
// Windows:     \app\src\utils\helper.js
▶ جرّب الكود

▶ مثال: path.join — التوحيد التلقائي

JAVASCRIPT
const path = require('path');

console.log(path.join('/app', '../config', 'settings.json'));
// /config/settings.json

console.log(path.join('src', '.', 'index.js'));
// src/index.js
▶ جرّب الكود

(2) path.resolve — تحويل المسار إلى مسار مطلق

path.resolve() قم بربط المسارات من اليمين إلى اليسار حتى يتم الحصول على مسار مطلق. إذا لم يتم الحصول على مسار مطلق، فاستخدم دليل العمل الحالي كأساس.

▶ مثال: الاستخدام الأساسي لـ path.resolve

JAVASCRIPT
const path = require('path');

console.log(path.resolve('src', 'index.js'));
// /current/working/dir/src/index.js

console.log(path.resolve('/app', 'src', 'index.js'));
// /app/src/index.js

console.log(path.resolve('/app', '/tmp', 'file.txt'));
// /tmp/file.txt(Use the absolute path on the far right as the reference.)
▶ جرّب الكود

(3) path.parse و path.format — تحليل المسار وإعادة بنائه

يقسم path.parse() المسار إلى خمسة أجزاء: root وdir وbase وext وname؛ بينما يعيد path.format() تجميع الكائن ليشكل سلسلة نصية للمسار.

▶ مثال: تحليل المسار باستخدام path.parse

JAVASCRIPT
const path = require('path');

const parsed = path.parse('/app/src/utils/helper.js');
console.log(parsed);
▶ جرّب الكود
TEXT 📖 للعرض فقط
{
  root: '/',
  dir: '/app/src/utils',
  base: 'helper.js',
  ext: '.js',
  name: 'helper'
}
100%
graph LR
    A["/app/src/utils/helper.js"] --> B["root: /"]
    A --> C["dir: /app/src/utils"]
    A --> D["base: helper.js"]
    D --> E["name: helper"]
    D --> F["ext: .js"]
    style A fill:#4CAF50,color:#fff
    style B fill:#FF9800,color:#fff
    style C fill:#2196F3,color:#fff
    style D fill:#9C27B0,color:#fff
    style E fill:#E91E63,color:#fff
    style F fill:#FF5722,color:#fff

▶ مثال: path.format — إعادة كتابة المسارات

JAVASCRIPT
const path = require('path');

const filePath = path.format({
  dir: '/app/src/utils',
  base: 'helper.js'
});
console.log(filePath);
// /app/src/utils/helper.js
▶ جرّب الكود

(4) path.extname / path.basename / path.dirname

تستخرج هذه الطرق الثلاث امتداد الملف واسم الملف وجزء الدليل من المسار، على التوالي.

▶ مثال: استخراج أجزاء المسار

JAVASCRIPT
const path = require('path');

const filePath = '/app/src/utils/helper.js';

console.log(path.extname(filePath));   // .js
console.log(path.basename(filePath));  // helper.js
console.log(path.basename(filePath, '.js')); // helper
console.log(path.dirname(filePath));   // /app/src/utils
▶ جرّب الكود

3. ثوابت المسار عبر الأنظمة الأساسية

تختلف فواصل المسارات وفواصل متغيرات البيئة باختلاف أنظمة التشغيل؛ وتوفر الوحدة النمطية path ثوابت لمراعاة هذه الاختلافات.

(1) path.sep — فاصل المسار

المنصة فاصل المسار
macOS / Linux /
ويندوز \

(2) path.delimiter — فاصل متغيرات البيئة

المنصة فاصل المسار
macOS / Linux :
ويندوز ;

▶ مثال: استخدام path.sep وpath.delimiter

JAVASCRIPT
const path = require('path');

console.log('Delimiter:', JSON.stringify(path.sep));
// macOS/Linux: "/"
// Windows:     "\\"

const envPaths = process.env.PATH.split(path.delimiter);
console.log('PATH Number of entries:', envPaths.length);
▶ جرّب الكود

4. الوحدة النمطية url ومنشئ عناوين URL

(1) url.parse (مهملة) مقابل new URL()

url.parse() هو إصدار قديم من واجهة برمجة التطبيقات (API) وقد تم تصنيفه على أنه قديم. نوصي باستخدام مُنشئ new URL()، الذي يتوافق مع معيار WHATWG.

ميزة url.parse() new URL()
المعيار Node.js القديم معيار WHATWG
الحالة مهمل موصى به
معالجة الأخطاء إرجاع القيمة null دون إظهار أي رسالة إثارة استثناء TypeError
searchParams لا شيء URLSearchParams المدمجة
الأداء أبطأ أسرع

▶ مثال: الاستخدام القديم لـ url.parse (غير موصى به)

JAVASCRIPT
const url = require('url');

const parsed = url.parse('https://example.com/api/users?name=Bob&page=1');
console.log(parsed.hostname);
console.log(parsed.query);
▶ جرّب الكود
TEXT 📖 للعرض فقط
example.com
name=Bob&page=1

▶ مثال: الاستخدام الموصى به لـ new URL()

JAVASCRIPT
const myUrl = new URL('https://example.com/api/users?name=Bob&page=1');

console.log(myUrl.hostname);
console.log(myUrl.pathname);
console.log(myUrl.searchParams.get('name'));
console.log(myUrl.searchParams.get('page'));
▶ جرّب الكود
TEXT 📖 للعرض فقط
example.com
/api/users
Bob
1

(2) url.searchParams —— التعامل مع معلمات الاستعلام

تعد الخاصية searchParams للكائن URL مثيلًا لـ URLSearchParams، والتي توفر طرقًا ملائمة لإضافة المعلمات وحذفها وتحديثها والاستعلام عنها.

▶ مثال: عمليات CRUD لـ searchParams

JAVASCRIPT
const myUrl = new URL('https://example.com/search');
myUrl.searchParams.set('q', 'nodejs');
myUrl.searchParams.set('lang', 'zh');
myUrl.searchParams.append('tag', 'バックエンド');
myUrl.searchParams.append('tag', 'tutorial');
myUrl.searchParams.remove('lang');

console.log(myUrl.toString());
// https://example.com/search?q=nodejs&tag=バックエンド&tag=tutorial

console.log(myUrl.searchParams.getAll('tag'));
// [ 'バックエンド', 'tutorial' ]
▶ جرّب الكود

(3) url.fileURLToPath — يحول عنوان URL للملف إلى مسار محلي

في وحدة ESM، تُرجع الدالة import.meta.url عنوان URL بتنسيق file://، والذي يجب تحويله إلى مسار في نظام الملفات باستخدام الدالة url.fileURLToPath().

▶ مثال: تحويل fileURLToPath

JAVASCRIPT
const { fileURLToPath } = require('url');

const fileUrl = 'file:///app/src/index.js';
const filePath = fileURLToPath(fileUrl);
console.log(filePath);
// macOS/Linux: /app/src/index.js
// Windows:     \app\src\index.js
▶ جرّب الكود

5. __dirname / __filename مقابل import.meta.url

هذا هو الفرق الرئيسي بين نظامي الوحدات النمطية CJS و ESM فيما يتعلق بالحصول على مسار الملف الحالي.

السمة __dirname / __filename import.meta.url
نظام الوحدات CJS (require) ESM (import)
نوع القيمة المُرجعة سلسلة المسار المطلق سلسلة عنوان URL من نوع file://
التوفر متغير عام، يُستخدم مباشرةً يتطلب وجود دالة fileURLToPath
مسار الدليل __dirname (استرجاع مباشر) يتطلب استخدام dirname(fileURLToPath())
مسار الملف __filename (الوصول المباشر) يتطلب التحويل باستخدام fileURLToPath()

▶ مثال: استخدام __dirname في CJS

JAVASCRIPT
const path = require('path');

console.log('__dirname:', __dirname);
console.log('__filename:', __filename);

const configPath = path.join(__dirname, 'config', 'settings.json');
console.log(configPath);
▶ جرّب الكود

▶ مثال: استخدام import.meta.url في ESM

JAVASCRIPT
import { fileURLToPath } from 'url';
import path from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

console.log('__dirname:', __dirname);
console.log('__filename:', __filename);
▶ جرّب الكود

6. جدول مرجعي سريع لطرق المسار الشائعة

الطريقة المعلمات القيمة المرجعة الغرض
path.join() ...paths string ربط أجزاء المسار وتوحيدها تلقائيًا
path.resolve() ...paths string تحويل المسار إلى مسار مطلق
path.parse() pathString object تقسيم المسار إلى الأجزاء المكونة له
path.format() pathObject string إعادة بناء كائن المسار كسلسلة نصية
path.extname() pathString string الحصول على امتداد الملف
path.basename() pathString[, ext] string الحصول على اسم الملف (يمكن حذف الامتداد)
path.dirname() pathString string الانتقال إلى جدول المحتويات
path.isAbsolute() pathString boolean التحقق مما إذا كان المسار مسارًا مطلقًا
path.normalize() pathString string المسار المعياري (معالجة ..، .)
path.relative() from, to string الحصول على المسار النسبي من «from» إلى «to»


7. أفضل الممارسات في التعامل مع المسارات عبر الأنظمة الأساسية المختلفة

(1) المبادئ الأساسية

القاعدة الوصف مثال خاطئ مثال صحيح
استخدام path.join المعالجة التلقائية للفواصل 'src' + '/' + 'index.js' path.join('src', 'index.js')
استخدام path.sep ثابت فاصل الاقتباس str.split('/') str.split(path.sep)
استخدام path.resolve الحصول على المسار المطلق process.cwd() + '/' + file path.resolve(file)
استخدام fileURLToPath تحويل عنوان URL للملف import.meta.url.slice(7) fileURLToPath(import.meta.url)
تجنب استخدام __dirname في ESM غير متوفر استخدم __dirname مباشرةً استخدم import.meta.url بدلاً من ذلك

▶ مثال:(2) أنماط الأخطاء الشائعة

JAVASCRIPT
const path = require('path');

// ❌ Hard-coded delimiters
const bad1 = '/app/data/' + 'config.json';

// ✅ Usage path.join
const good1 = path.join('/app', 'data', 'config.json');

// ❌ Manually Merge Working Directories
const bad2 = process.cwd() + '/output/result.log';

// ✅ Usage path.resolve
const good2 = path.resolve('output', 'result.log');

// ❌ String Replacement Delimiter
const bad3 = somePath.replace(/\\/g, '/');

// ✅ Usage path.normalize
const good3 = path.normalize(somePath);
▶ جرّب الكود

8. مثال شامل: أداة مسار الملفات عبر الأنظمة الأساسية

يحاكي المثال التالي المنطق الأساسي لأداة واجهة سطر الأوامر (CLI) المعدلة التي طورها بوب: قراءة مسار التكوين، وإنشاء دليل البيانات، وتحليل عنوان URL، واستخراج المعلمات.

JAVASCRIPT
const path = require('path');
const { fileURLToPath } = require('url');

class PathTool {
  constructor(baseDir) {
    this.baseDir = baseDir || process.cwd();
  }

  resolveConfigPath(configRelativePath) {
    return path.resolve(this.baseDir, configRelativePath);
  }

  buildDataPath(...segments) {
    return path.join(this.baseDir, 'data', ...segments);
  }

  parseUrl(urlString) {
    const myUrl = new URL(urlString);
    return {
      protocol: myUrl.protocol,
      hostname: myUrl.hostname,
      pathname: myUrl.pathname,
      params: Object.fromEntries(myUrl.searchParams.entries())
    };
  }

  extractFileInfo(filePath) {
    const parsed = path.parse(filePath);
    return {
      directory: parsed.dir,
      fileName: parsed.name,
      extension: parsed.ext,
      fullPath: filePath
    };
  }

  toFilePath(urlOrPath) {
    if (urlOrPath.startsWith('file://')) {
      return fileURLToPath(urlOrPath);
    }
    return path.resolve(urlOrPath);
  }
}

const tool = new PathTool('/app/project');

// 1. Parsing the Configuration Path
const configPath = tool.resolveConfigPath('config/app.json');
console.log('Configuration Path:', configPath);
// /app/project/config/app.json

// 2. Data Merge Catalog
const dataPath = tool.buildDataPath('users', 'profiles.json');
console.log('Data Path:', dataPath);
// /app/project/data/users/profiles.json

// 3. Analysis URL and extract the parameters
const parsed = tool.parseUrl('https://api.example.com/v1/users?role=admin&active=true');
console.log('URL Analysis:', parsed);
// { protocol: 'https:', hostname: 'api.example.com',
//   pathname: '/v1/users', params: { role: 'admin', active: 'true' } }

// 4. Extract File Information
const info = tool.extractFileInfo('/app/project/data/users/profiles.json');
console.log('File Information:', info);
// { directory: '/app/project/data/users',
//   fileName: 'profiles', extension: '.json', fullPath: '...' }

// 5. file URL File Path
const localPath = tool.toFilePath('file:///app/project/config/app.json');
console.log('Local Path:', localPath);
// /app/project/config/app.json


❓ أسئلة شائعة

س ما الفرق بين path.join وpath.resolve؟
ج تقوم path.join ببساطة بربط أجزاء المسار وتوحيدها؛ وهي لا تضمن أن تكون النتيجة مسارًا مطلقًا. أما path.resolve فيحل المسار من اليمين إلى اليسار حتى يتم إنتاج مسار مطلق؛ وإذا لم يتم العثور على مسار مطلق، فإنه يستخدم process.cwd() كأساس.
س هل يمكن استخدام __dirname في ESM؟
ج لا. لا توجد المتغيرات العالمية __dirname و__filename في وحدات ESM؛ عليك استخدام path.dirname(fileURLToPath(import.meta.url)) للحصول على القيم المكافئة.
س هل تم إهمال url.parse؟
ج نعم، تم تصنيف url.parse على أنه مهمل. نوصي باستخدام مُنشئ new URL() الوارد في معيار WHATWG، والذي يوفر معالجة أفضل للأخطاء ودعمًا مدمجًا لـ searchParams.
س كيف يمكنني ضمان توافق المسارات بين Windows و macOS/Linux؟
ج استخدم دائمًا path.join أو path.resolve لربط المسارات، واستخدم path.sep لتحديد الفاصل، واستخدم path.delimiter للتعامل مع متغيرات البيئة، وتجنب أي سلاسل فاصلة مكتوبة بشكل ثابت في الكود.
س ما الذي ترجعه الدالة import.meta.url؟
ج ترجع سلسلة عنوان URL لبروتوكول file:// الخاص بالوحدة الحالية (على سبيل المثال، file:///app/src/index.js)، والتي يجب تحويلها إلى مسار في نظام الملفات باستخدام fileURLToPath().
س هل يتصرف path.isAbsolute بنفس الطريقة عبر الأنظمة الأساسية المختلفة؟
ج لا، لا يتصرف كذلك. في أنظمة POSIX، يُعد /usr/local مسارًا مطلقًا، بينما في نظام Windows، يُعد C:\Users مسارًا مطلقًا، في حين أن /usr/local ليس كذلك. ويحدد path.isAbsolute النتيجة بناءً على النظام الأساسي الحالي.

📖 ملخص


📝 تمارين

  1. أكمل جميع أمثلة الأكواد الواردة في هذا الدرس وتأكد من أن كل منها يعمل بشكل صحيح.
  2. Modify the comprehensive example and add your own extensions
  3. راجع الوثائق الرسمية، وحدد واجهة برمجة تطبيقات (API) واحدة أو اثنتين لم يتم تناولهما في هذا الدرس، واكتب كود اختبار لهما.
  4. التأمل: كيف ستطبق ما تعلمته في هذا الدرس على مشروع في الواقع العملي؟
  5. حاول أن تجمع بين ما تعلمته في هذا الدرس والمواد التي درستها في الدروس السابقة لإنشاء مشروع صغير.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%