Skip to content

الوحدات: الحزم

[السجل]

الإصدارالتغييرات
v14.13.0، v12.20.0إضافة دعم لأنماط "exports".
v14.6.0، v12.19.0إضافة حقل الحزمة "imports".
v13.7.0، v12.17.0إلغاء وضع تصنيف الصادرات الشرطية.
v13.7.0، v12.16.0إزالة خيار --experimental-conditional-exports. في الإصدار 12.16.0، لا تزال الصادرات الشرطية خلف --experimental-modules.
v13.6.0، v12.16.0إلغاء وضع تصنيف الإشارة الذاتية إلى حزمة باستخدام اسمها.
v12.7.0تقديم حقل "exports" في ملف package.json كبديل أكثر قوة للحقل الكلاسيكي "main".
v12.0.0إضافة دعم لوحدات ES باستخدام امتداد الملف .js عبر حقل "type" في ملف package.json.

مقدمة

الحزمة هي شجرة مجلدات يصفها ملف package.json. تتكون الحزمة من المجلد الذي يحتوي على ملف package.json وجميع المجلدات الفرعية حتى المجلد التالي الذي يحتوي على ملف package.json آخر، أو مجلد باسم node_modules.

توفر هذه الصفحة إرشادات لمؤلفي الحزم الذين يكتبون ملفات package.json بالإضافة إلى مرجع لحقول package.json التي يعرفها Node.js.

تحديد نظام الوحدة

مقدمة

سيتعامل Node.js مع ما يلي على أنه وحدات ES عند تمريرها إلى node كمدخل أولي، أو عند الإشارة إليها بواسطة عبارات import أو تعبيرات import() :

  • الملفات ذات الامتداد .mjs.
  • الملفات ذات الامتداد .js عندما يحتوي ملف package.json الأصل الأقرب على حقل مستوى أعلى "type" بقيمة "module".
  • السلاسل الممررة كوسيطة إلى --eval، أو المُمررة إلى node عبر STDIN، مع العلم --input-type=module.
  • التعليمات البرمجية التي تحتوي على بناء جملة يتم تحليله بنجاح فقط كوحدات ES، مثل عبارات import أو export أو import.meta، بدون أي علامة صريحة لكيفية تفسيرها. العلامات الصريحة هي امتدادات .mjs أو .cjs، أو حقول "type" في package.json ذات قيم "module" أو "commonjs"، أو علم --input-type. يتم دعم تعبيرات import() الديناميكية في وحدات CommonJS أو ES ولن تجبر ملفًا على التعامل معه كوحدة ES. انظر كشف بناء الجملة.

سيتعامل Node.js مع ما يلي على أنه CommonJS عند تمريره إلى node كمدخل أولي، أو عند الإشارة إليه بواسطة عبارات import أو تعبيرات import() :

  • الملفات ذات الامتداد .cjs.
  • الملفات ذات الامتداد .js عندما يحتوي ملف package.json الأصل الأقرب على حقل مستوى أعلى "type" بقيمة "commonjs".
  • السلاسل الممررة كوسيطة إلى --eval أو --print، أو المُمررة إلى node عبر STDIN، مع العلم --input-type=commonjs.
  • الملفات ذات الامتداد .js بدون ملف package.json أصلي أو حيث يفتقر ملف package.json الأصل الأقرب إلى حقل type، وحيث يمكن تقييم التعليمات البرمجية بنجاح كـ CommonJS. بمعنى آخر، يحاول Node.js تشغيل هذه الملفات "الغامضة" كـ CommonJS أولاً، وسوف يعيد محاولة تقييمها كوحدات ES إذا فشل التقييم كـ CommonJS لأن المحلل وجد بناء جملة وحدة ES.

يُحدث كتابة بناء جملة وحدة ES في الملفات "الغامضة" تكلفة أداء، لذلك يُشجع المؤلفون على أن يكونوا صريحين قدر الإمكان. على وجه الخصوص، يجب على مؤلفي الحزم دائمًا تضمين حقل "type" في ملفات package.json الخاصة بهم، حتى في الحزم التي تكون جميع مصادرها CommonJS. إن التحديد الصريح لنوع الحزمة سيُحافظ على الحزمة في المستقبل في حالة تغير نوع Node.js الافتراضي، كما سيجعل الأمور أسهل لأدوات البناء وأدوات التحميل لتحديد كيفية تفسير الملفات الموجودة في الحزمة.

كشف بناء الجملة

[السجل]

الإصدارالتغييرات
v22.7.0تم تمكين كشف بناء الجملة افتراضيًا.
v21.1.0، v20.10.0تمت الإضافة في: v21.1.0، v20.10.0

[مستقر: 1 - تجريبي]

مستقر: 1 ثبات: 1.2 - إصدار مرشح

ستقوم Node.js بفحص التعليمات البرمجية المصدر لإدخال غامض لتحديد ما إذا كان يحتوي على بناء جملة وحدة ES ؛ إذا تم اكتشاف مثل هذا البناء، فسيتم التعامل مع الإدخال كوحدة ES.

يُعرّف الإدخال الغامض بأنه:

  • الملفات ذات الامتداد .js أو بدون امتداد ؛ وإما عدم وجود ملف package.json للتحكم أو ملف يفتقر إلى حقل type.
  • إدخال سلسلة (--eval أو STDIN) عندما لا يتم تحديد --input-type.

يُعرّف بناء جملة وحدة ES على أنه بناء جملة من شأنه أن يطرح استثناءً عند تقييمه كـ CommonJS. وهذا يشمل ما يلي:

  • عبارات import (ولكن ليس تعبيرات import()، وهي صالحة في CommonJS).
  • عبارات export.
  • مراجع import.meta.
  • await في أعلى مستوى من الوحدة.
  • إعادة الإعلان اللغوي لمتغيرات مُغلّف CommonJS (require, module, exports, __dirname, __filename).

محمّلات الوحدات

تحتوي Node.js على نظامين لحل مُحدد ومحميل الوحدات.

يوجد برنامج تحميل وحدة CommonJS:

  • إنه متزامن تمامًا.
  • وهو مسؤول عن التعامل مع مكالمات require().
  • وهو قابل للتصحيح باستخدام مُعدِّلات.
  • وهو يدعم المجلدات كوحدات.
  • عند حل مُحدد، إذا لم يتم العثور على تطابق دقيق، فسيحاول إضافة امتدادات (.js، .json، وأخيرًا .node) ثم يحاول حل المجلدات كوحدات.
  • يعامل .json كملفات نصية JSON.
  • يتم تفسير ملفات .node على أنها وحدات إضافية مُجمّعة مُحمّلة باستخدام process.dlopen().
  • يعامل جميع الملفات التي تفتقر إلى امتدادات .json أو .node كملفات نصية JavaScript.
  • لا يمكن استخدامه إلا لتحميل وحدات ECMAScript من وحدات CommonJS إذا كان رسم بياني الوحدة متزامنًا (لا يحتوي على أي await على مستوى أعلى). عند استخدامه لتحميل ملف نصي JavaScript ليس وحدة ECMAScript، سيتم تحميل الملف كوحدة CommonJS.

يوجد برنامج تحميل وحدة ECMAScript:

  • إنه غير متزامن، إلا إذا كان يُستخدم لتحميل وحدات لـ require().
  • وهو مسؤول عن التعامل مع عبارات import وتعبيرات import().
  • إنه ليس قابلًا للتصحيح باستخدام مُعدِّلات، ويمكن تخصيصه باستخدام خطافات المُحمِّل.
  • إنه لا يدعم المجلدات كوحدات، يجب تحديد مؤشرات الدليل (مثل './startup/index.js') بالكامل.
  • لا يقوم بالبحث عن الامتدادات. يجب توفير امتداد الملف عندما يكون المُحدد هو عنوان URL لملف نسبي أو مطلق.
  • يمكنه تحميل وحدات JSON، ولكن يلزم سمة نوع الاستيراد.
  • يقبل فقط امتدادات .js و.mjs و.cjs لملفات نص JavaScript.
  • يمكن استخدامه لتحميل وحدات CommonJS JavaScript. يتم تمرير هذه الوحدات عبر cjs-module-lexer لمحاولة تحديد الصادرات المسماة، والتي تكون متاحة إذا أمكن تحديدها من خلال التحليل الثابت. يتم تحويل عناوين URL للوحدات المُستوردة من CommonJS إلى مسارات مطلقة، ثم يتم تحميلها عبر برنامج تحميل وحدة CommonJS.

package.json و امتدادات الملفات

ضمن حزمة، يُحدد حقل package.json "type" كيف يجب أن يُفسر Node.js ملفات .js. إذا لم يحتوي ملف package.json على حقل "type"، فسيتم التعامل مع ملفات .js على أنها CommonJS.

قيمة "type" في package.json وهي "module" تخبر Node.js بتفسير ملفات .js ضمن تلك الحزمة على أنها تستخدم بناء جملة وحدة ES.

لا ينطبق حقل "type" فقط على نقاط الدخول الأولية (node my-app.js)، بل أيضًا على الملفات التي تشير إليها عبارات import و import().

js
// my-app.js، يُعامل كنموذج ES نظرًا لوجود ملف package.json
// في نفس المجلد مع "type": "module".

import './startup/init.js'
// تم تحميله كنموذج ES نظرًا لأن ./startup لا يحتوي على ملف package.json،
// وبالتالي يرث قيمة "type" من مستوى أعلى.

import 'commonjs-package'
// تم تحميله كـ CommonJS نظرًا لأن ./node_modules/commonjs-package/package.json
// يفتقر إلى حقل "type" أو يحتوي على "type": "commonjs".

import './node_modules/commonjs-package/index.js'
// تم تحميله كـ CommonJS نظرًا لأن ./node_modules/commonjs-package/package.json
// يفتقر إلى حقل "type" أو يحتوي على "type": "commonjs".

يتم دائمًا تحميل الملفات التي تنتهي بـ .mjs كـ وحدات ES بغض النظر عن أقرب ملف package.json الرئيسي.

يتم دائمًا تحميل الملفات التي تنتهي بـ .cjs كـ CommonJS بغض النظر عن أقرب ملف package.json الرئيسي.

js
import './legacy-file.cjs'
// تم تحميله كـ CommonJS نظرًا لأن .cjs يتم تحميله دائمًا كـ CommonJS.

import 'commonjs-package/src/index.mjs'
// تم تحميله كنموذج ES نظرًا لأن .mjs يتم تحميله دائمًا كنموذج ES.

يمكن استخدام امتدادات .mjs و .cjs لخلط الأنواع ضمن نفس الحزمة:

  • ضمن حزمة "type": "module"، يمكن توجيه Node.js لتفسير ملف معين كـ CommonJS عن طريق تسميته بامتداد .cjs (نظرًا لأن ملفات .js و .mjs كلاهما يُعاملان كنموذجات ES ضمن حزمة "module").
  • ضمن حزمة "type": "commonjs"، يمكن توجيه Node.js لتفسير ملف معين كـ وحدة ES عن طريق تسميته بامتداد .mjs (نظرًا لأن ملفات .js و .cjs كلاهما يُعاملان كـ CommonJS ضمن حزمة "commonjs").

علم --input-type

مُضاف في: v12.0.0

يتم التعامل مع السلاسل المُمرَّرة كوسيط إلى --eval (أو -e)، أو المُمرَّرة إلى node عبر STDIN، على أنها وحدات ES عندما يتم ضبط علم --input-type=module.

bash
node --input-type=module --eval "import { sep } from 'node:path'; console.log(sep);"

echo "import { sep } from 'node:path'; console.log(sep);" | node --input-type=module

للحصول على اكتمال الصورة، يوجد أيضًا --input-type=commonjs، لتشغيل إدخال السلسلة صراحةً كـ CommonJS. هذا هو السلوك الافتراضي إذا لم يتم تحديد --input-type.

تحديد مدير الحزم

[مستقر: 1 - تجريبي]

مستقر: 1 ثبات: 1 - تجريبي

في حين يُتوقع أن تكون جميع مشاريع Node.js قابلة للتثبيت بواسطة جميع مديري الحزم بمجرد نشرها، غالبًا ما يُطلب من فرق التطوير الخاصة بها استخدام مدير حزم محدد واحد. لتسهيل هذه العملية، يتم شحن Node.js مع أداة تُسمى Corepack تهدف إلى جعل جميع مديري الحزم متاحين بشكل شفاف في بيئتك - بشرط تثبيت Node.js لديك.

بشكل افتراضي، لن يفرض Corepack أي مدير حزم محدد، وسوف يستخدم الإصدارات العامة "الأفضل المعروفة" المرتبطة بكل إصدار من Node.js، ولكن يمكنك تحسين هذه التجربة عن طريق تعيين حقل "packageManager" في ملف package.json الخاص بمشروعك.

نقاط دخول الحزمة

في ملف package.json الخاص بالحزمة، يمكن لحقلين تحديد نقاط الدخول للحزمة: "main" و "exports". ينطبق كلا الحقلين على كل من نقاط دخول وحدة ES ونقاط دخول وحدة CommonJS.

يُدعم الحقل "main" في جميع إصدارات Node.js، لكن قدراته محدودة: فهو يُحدد فقط نقطة الدخول الرئيسية للحزمة.

يُوفر "exports" بديلاً حديثًا لـ "main" يسمح بتعريف نقاط دخول متعددة، ودعم دقة الإدخال الشرطي بين البيئات، ومنع أي نقاط دخول أخرى بخلاف تلك المُعرَّفة في "exports". يسمح هذا التغليف لمؤلفي الوحدات بتحديد الواجهة العامة لحزمتهم بوضوح.

بالنسبة للحزم الجديدة التي تستهدف إصدارات Node.js المدعومة حاليًا، يُوصى باستخدام حقل "exports". بالنسبة للحزم التي تدعم Node.js 10 وما دون، يُطلب حقل "main". إذا تم تعريف كل من "exports" و "main"، فإن حقل "exports" يأخذ الأسبقية على "main" في إصدارات Node.js المدعومة.

يمكن استخدام الصادرات الشرطية ضمن "exports" لتحديد نقاط دخول حزمة مختلفة لكل بيئة، بما في ذلك ما إذا كانت الحزمة مُشار إليها عبر require أو عبر import. لمزيد من المعلومات حول دعم كل من CommonJS ووحدات ES في حزمة واحدة، يُرجى الرجوع إلى قسم الحزم المزدوجة CommonJS/ES.

ستمنع الحزم الحالية التي تُدخِل حقل "exports" مُستهلكي الحزمة من استخدام أي نقاط دخول لم يتم تعريفها، بما في ذلك package.json (مثل: require('your-package/package.json')). من المرجح أن يكون هذا تغييرًا جوهريًا.

لجعل إدخال "exports" غير جوهري، تأكد من تصدير كل نقطة دخول مُدعمه سابقًا. من الأفضل تحديد نقاط الدخول صراحةً حتى تكون واجهة برمجة التطبيقات العامة للحزمة محددة جيدًا. على سبيل المثال، يمكن لمشروع قام سابقًا بتصدير main، lib، feature، و package.json استخدام package.exports التالي:

json
{
  "name": "my-package",
  "exports": {
    ".": "./lib/index.js",
    "./lib": "./lib/index.js",
    "./lib/index": "./lib/index.js",
    "./lib/index.js": "./lib/index.js",
    "./feature": "./feature/index.js",
    "./feature/index": "./feature/index.js",
    "./feature/index.js": "./feature/index.js",
    "./package.json": "./package.json"
  }
}

بدلاً من ذلك، يمكن للمشروع اختيار تصدير مجلدات كاملة مع مسارات فرعية ممتدة وبدونها باستخدام أنماط التصدير:

json
{
  "name": "my-package",
  "exports": {
    ".": "./lib/index.js",
    "./lib": "./lib/index.js",
    "./lib/*": "./lib/*.js",
    "./lib/*.js": "./lib/*.js",
    "./feature": "./feature/index.js",
    "./feature/*": "./feature/*.js",
    "./feature/*.js": "./feature/*.js",
    "./package.json": "./package.json"
  }
}

مع توفير التوافق مع الإصدارات الثانوية للحزم أعلاه، يمكن بعد ذلك تغيير رئيسي مستقبلي للحزمة تقييد الصادرات بشكل صحيح إلى صادرات الميزات المحددة المُعرَّضة فقط:

json
{
  "name": "my-package",
  "exports": {
    ".": "./lib/index.js",
    "./feature/*.js": "./feature/*.js",
    "./feature/internal/*": null
  }
}

نقطة الدخول الرئيسية للتصدير

عند كتابة حزمة جديدة، يُوصى باستخدام حقل "exports":

json
{
  "exports": "./index.js"
}

عندما يتم تعريف حقل "exports"، يتم تغليف جميع المسارات الفرعية للحزمة، ولا تصبح متاحة للمستوردين بعد الآن. على سبيل المثال، يُلقي require('pkg/subpath.js') خطأ ERR_PACKAGE_PATH_NOT_EXPORTED.

يوفر هذا التغليف للصادرات ضمانات أكثر موثوقية حول واجهات الحزمة للأدوات وعند التعامل مع ترقيات semver لحزمة. ليس هذا تغليفًا قويًا، لأن require('/path/to/node_modules/pkg/subpath.js') سيقوم بتحميل subpath.js بشكل مباشر.

تدعم جميع إصدارات Node.js المدعومة حاليًا وأدوات إنشاء حديثة حقل "exports". بالنسبة للمشاريع التي تستخدم إصدارًا أقدم من Node.js أو أداة إنشاء ذات صلة، يمكن تحقيق التوافق من خلال تضمين حقل "main" جنبًا إلى جنب مع "exports" الذي يشير إلى نفس الوحدة النمطية:

json
{
  "main": "./index.js",
  "exports": "./index.js"
}

صادرات المسارات الفرعية

تمت الإضافة في: v12.7.0

عند استخدام حقل "exports"، يمكن تعريف مسارات فرعية مخصصة جنبًا إلى جنب مع نقطة الدخول الرئيسية من خلال التعامل مع نقطة الدخول الرئيسية على أنها المسار الفرعي ".":

json
{
  "exports": {
    ".": "./index.js",
    "./submodule.js": "./src/submodule.js"
  }
}

الآن، لا يمكن للمستهلك إلا استيراد المسار الفرعي المُعرّف في "exports":

js
import submodule from 'es-module-package/submodule.js'
// Loads ./node_modules/es-module-package/src/submodule.js

بينما ستُحدث المسارات الفرعية الأخرى خطأ:

js
import submodule from 'es-module-package/private-module.js'
// Throws ERR_PACKAGE_PATH_NOT_EXPORTED

الامتدادات في المسارات الفرعية

يجب على مُعدّي الحزم توفير مسارات فرعية مُمتدة (import 'pkg/subpath.js') أو بدون امتداد (import 'pkg/subpath') في صادراتها. هذا يضمن وجود مسار فرعي واحد فقط لكل وحدة نمطية مُصدرة، بحيث يستورد جميع التابعين نفس المُحدد المُتناسق، مما يحافظ على عقد الحزمة واضحًا للمستهلكين ويُبسّط إكمال المسارات الفرعية للحزمة.

تقليديًا، كانت الحزم تميل إلى استخدام النمط بدون امتداد، والذي يتمتع بمزايا القراءة وإخفاء المسار الحقيقي للملف داخل الحزمة.

مع توفير خرائط الاستيراد الآن معيارًا لحل الحزم في المتصفحات وبيئات تشغيل JavaScript الأخرى، يمكن أن يؤدي استخدام النمط بدون امتداد إلى تعريفات خريطة استيراد منتفخة. يمكن أن تتجنب الامتدادات الصريحة هذه المشكلة من خلال تمكين خريطة الاستيراد من استخدام تعيين مجلدات الحزم لتعيين العديد من المسارات الفرعية عند الإمكان بدلاً من إدخال خريطة منفصل لكل تصدير لمسار فرعي للحزمة. ويعكس هذا أيضًا متطلب استخدام مسار المُحدد الكامل في مُحددات الاستيراد النسبية والمطلقة.

تصدير السكر

مضاف في: v12.11.0

إذا كان تصدير "." هو التصدير الوحيد، فإن حقل "exports" يوفر سكرًا لهذه الحالة باعتباره القيمة المباشرة لحقل "exports".

json
{
  "exports": {
    ".": "./index.js"
  }
}

يمكن كتابتها:

json
{
  "exports": "./index.js"
}

استيراد المسار الفرعي

مضاف في: v14.6.0، v12.19.0

بالإضافة إلى حقل "exports"، يوجد حقل حزمة "imports" لإنشاء تعيينات خاصة لا تنطبق إلا على محددات الاستيراد من داخل الحزمة نفسها.

يجب أن تبدأ الإدخالات في حقل "imports" دائمًا بـ # للتأكد من تمييزها عن محددات الحزمة الخارجية.

على سبيل المثال، يمكن استخدام حقل الاستيراد للحصول على فوائد التصدير الشرطي للوحدات الداخلية:

json
// package.json
{
  "imports": {
    "#dep": {
      "node": "dep-node-native",
      "default": "./dep-polyfill.js"
    }
  },
  "dependencies": {
    "dep-node-native": "^1.0.0"
  }
}

حيث لا يحصل import '#dep' على دقة الحزمة الخارجية dep-node-native (بما في ذلك صادراتها بدورها)، وبدلاً من ذلك يحصل على الملف المحلي ./dep-polyfill.js بالنسبة للحزمة في بيئات أخرى.

على عكس حقل "exports"، يسمح حقل "imports" بالتعيين إلى حزم خارجية.

قواعد الحل لحقل الاستيراد هي مشابهة لحقل التصدير.

أنماط المسار الفرعي

[History]

الإصدارالتغييرات
v16.10.0، v14.19.0دعم ملحقات الأنماط في حقل "imports".
v16.9.0، v14.19.0دعم ملحقات الأنماط.
v14.13.0، v12.20.0مضاف في: v14.13.0، v12.20.0

بالنسبة للحزم التي تحتوي على عدد صغير من الصادرات أو الواردات، نوصي بقائمة صريحة لكل إدخال مسار فرعي للتصدير. ولكن بالنسبة للحزم التي تحتوي على أعداد كبيرة من المسارات الفرعية، قد يتسبب هذا في تضخم package.json ومشاكل الصيانة.

لهذه حالات الاستخدام، يمكن استخدام أنماط تصدير المسار الفرعي بدلاً من ذلك:

json
// ./node_modules/es-module-package/package.json
{
  "exports": {
    "./features/*.js": "./src/features/*.js"
  },
  "imports": {
    "#internal/*.js": "./src/internal/*.js"
  }
}

* تعرض الخرائط المسارات الفرعية المتداخلة لأنها عبارة عن بناء جملة استبدال سلسلة فقط.

سيتم استبدال جميع مثيلات * على الجانب الأيمن بهذه القيمة، بما في ذلك إذا كانت تحتوي على أي فاصلات /.

js
import featureX from 'es-module-package/features/x.js'
// Loads ./node_modules/es-module-package/src/features/x.js

import featureY from 'es-module-package/features/y/y.js'
// Loads ./node_modules/es-module-package/src/features/y/y.js

import internalZ from '#internal/z.js'
// Loads ./node_modules/es-module-package/src/internal/z.js

هذا هو التطابق الثابت المباشر والاستبدال بدون أي معالجة خاصة لملحقات الملفات. يؤدي تضمين "*.js" على جانبي الخريطة إلى تقييد صادرات الحزمة المعروضة على ملفات JS فقط.

يتم الحفاظ على خاصية كون الصادرات قابلة للعد بشكل ثابت مع أنماط التصدير نظرًا لأنه يمكن تحديد الصادرات الفردية لحزمة ما عن طريق التعامل مع نمط الهدف الجانبي الأيمن كـ ** glob مقابل قائمة الملفات داخل الحزمة. نظرًا لأن مسارات node_modules ممنوعة في أهداف التصدير، فإن هذا التوسع يعتمد فقط على ملفات الحزمة نفسها.

لاستبعاد المجلدات الفرعية الخاصة من الأنماط، يمكن استخدام أهداف null:

json
// ./node_modules/es-module-package/package.json
{
  "exports": {
    "./features/*.js": "./src/features/*.js",
    "./features/private-internal/*": null
  }
}
js
import featureInternal from 'es-module-package/features/private-internal/m.js'
// Throws: ERR_PACKAGE_PATH_NOT_EXPORTED

import featureX from 'es-module-package/features/x.js'
// Loads ./node_modules/es-module-package/src/features/x.js

التصدير الشرطي

[السجل]

الإصدارالتغييرات
v13.7.0، v12.16.0إلغاء وضع التصدير الشرطي.
v13.2.0، v12.16.0تمت الإضافة في: v13.2.0، v12.16.0

يوفر التصدير الشرطي طريقة للربط بمسارات مختلفة بناءً على ظروف معينة. وهو مدعوم لكل من استيرادات CommonJS و ES module.

على سبيل المثال، يمكن كتابة حزمة تريد توفير تصدير مختلف لـ ES module لـ require() و import كالتالي:

json
// package.json
{
  "exports": {
    "import": "./index-module.js",
    "require": "./index-require.cjs"
  },
  "type": "module"
}

تُنفذ Node.js الشروط التالية، المدرجة بالترتيب من الأكثر تحديدًا إلى الأقل تحديدًا حيث يجب تعريف الشروط:

  • "node-addons" - مشابه لـ "node" ويتوافق مع أي بيئة Node.js. يمكن استخدام هذا الشرط لتوفير نقطة دخول تستخدم إضافات C++ الأصلية على عكس نقطة دخول أكثر عالمية ولا تعتمد على الإضافات الأصلية. يمكن تعطيل هذا الشرط عبر علم --no-addons.
  • "node" - يتوافق مع أي بيئة Node.js. يمكن أن يكون ملف CommonJS أو ES module. في معظم الحالات، ليس من الضروري تحديد منصة Node.js صراحةً.
  • "import" - يتوافق عندما يتم تحميل الحزمة عبر import أو import()، أو عبر أي عملية استيراد أو حل على مستوى أعلى بواسطة مُحمّل وحدة ECMAScript. ينطبق بغض النظر عن تنسيق وحدة الملف الهدف. متبادل الاستبعاد دائمًا مع "require".
  • "require" - يتوافق عندما يتم تحميل الحزمة عبر require() . يجب أن يكون الملف المُشار إليه قابلاً للتحميل باستخدام require() على الرغم من أن الشرط يتوافق بغض النظر عن تنسيق وحدة الملف الهدف. تتضمن التنسيقات المتوقعة CommonJS و JSON والإضافات الأصلية ووحدات ES. متبادل الاستبعاد دائمًا مع "import".
  • "module-sync" - يتوافق بغض النظر عن تحميل الحزمة عبر import أو import() أو require(). من المتوقع أن يكون التنسيق هو وحدات ES التي لا تحتوي على انتظار على مستوى أعلى في رسم بياني الوحدة الخاصة بها - وإذا كانت تحتوي عليه، فسيتم طرح ERR_REQUIRE_ASYNC_MODULE عندما يتم استخدام require() للوحدة.
  • "default" - بديل عام يتوافق دائمًا. يمكن أن يكون ملف CommonJS أو ES module. يجب أن يأتي هذا الشرط دائمًا في النهاية.

داخل كائن "exports"، يكون ترتيب المفاتيح ذا أهمية. أثناء مطابقة الشرط، تكون الإدخالات السابقة ذات أولوية أعلى وتأخذ الأسبقية على الإدخالات اللاحقة. القاعدة العامة هي أن الشروط يجب أن تكون من الأكثر تحديدًا إلى الأقل تحديدًا في ترتيب الكائن.

قد يؤدي استخدام شرطي "import" و "require" إلى بعض المخاطر، والتي سيتم شرحها بمزيد من التفصيل في قسم الحزم المزدوجة CommonJS/ES module.

يمكن استخدام الشرط "node-addons" لتوفير نقطة دخول تستخدم إضافات C++ الأصلية. ومع ذلك، يمكن تعطيل هذا الشرط عبر علم --no-addons. عند استخدام "node-addons"، يُوصى بمعاملة "default" كتحسين يوفر نقطة دخول أكثر عالمية، مثل استخدام WebAssembly بدلاً من إضافة أصلية.

يمكن أيضًا توسيع التصدير الشرطي لمسارات فرعية للتصدير، على سبيل المثال:

json
{
  "exports": {
    ".": "./index.js",
    "./feature.js": {
      "node": "./feature-node.js",
      "default": "./feature.js"
    }
  }
}

يُعرّف حزمة حيث يمكن أن يوفر require('pkg/feature.js') و import 'pkg/feature.js' تنفيذات مختلفة بين Node.js وبيئات JS الأخرى.

عند استخدام فروع البيئة، قم دائمًا بتضمين شرط "default" كلما أمكن ذلك. يضمن توفير شرط "default" أن تتمكن أي بيئات JS غير معروفة من استخدام هذا التنفيذ العالمي، مما يساعد على تجنب اضطرار بيئات JS هذه إلى التظاهر بأنها بيئات موجودة لدعم الحزم ذات التصدير الشرطي. لهذا السبب، يُفضّل عادةً استخدام فروع الشرط "node" و "default" على استخدام فروع الشرط "node" و "browser".

الشروط المتداخلة

بالإضافة إلى التعيينات المباشرة، يدعم Node.js أيضًا كائنات الشروط المتداخلة.

على سبيل المثال، لتعريف حزمة تحتوي فقط على نقاط دخول ثنائية الوضع للاستخدام في Node.js ولكن ليس في المتصفح:

json
{
  "exports": {
    "node": {
      "import": "./feature-node.mjs",
      "require": "./feature-node.cjs"
    },
    "default": "./feature.mjs"
  }
}

تستمر مطابقة الشروط بالترتيب كما هو الحال مع الشروط المسطحة. إذا لم يكن الشرط المتداخل يحتوي على أي تعيين، فسوف يستمر في التحقق من الشروط المتبقية للشرط الرئيسي. بهذه الطريقة، تتصرف الشروط المتداخلة بشكل مشابه لتعليمات JavaScript if المتداخلة.

حل شروط المستخدم

تمت الإضافة في: v14.9.0، v12.19.0

عند تشغيل Node.js، يمكن إضافة شروط المستخدم المخصصة باستخدام علم --conditions:

bash
node --conditions=development index.js

الذي سيحل بعد ذلك شرط "development" في استيرادات الحزم وتصديرها، مع حل الشروط الموجودة "node"، "node-addons"، "default"، "import"، و "require" حسب الاقتضاء.

يمكن تعيين أي عدد من الشروط المخصصة باستخدام أعلام متكررة.

يجب أن تحتوي الشروط النموذجية فقط على أحرف أبجدية رقمية، باستخدام ":" أو "-" أو "=" كفاصلات إذا لزم الأمر. قد يؤدي أي شيء آخر إلى مشاكل في التوافق خارج node.

في node، هناك قيود قليلة جدًا على الشروط، ولكنها تتضمن على وجه التحديد ما يلي:

تعريفات شروط المجتمع

يتم تجاهل سلاسل الشروط بخلاف شروط "import"، "require"، "node"، "module-sync"، "node-addons" و "default" المطبقة في Node.js core بشكل افتراضي.

قد تقوم منصات أخرى بتنفيذ شروط أخرى، ويمكن تمكين شروط المستخدم في Node.js عبر علم --conditions / -C.

نظرًا لأن شروط الحزم المخصصة تتطلب تعريفات واضحة لضمان الاستخدام الصحيح، يتم توفير قائمة بالشروط المعروفة الشائعة للحزم وتعريفاتها الصارمة أدناه للمساعدة في تنسيق النظام البيئي.

  • "types" - يمكن استخدامها بواسطة أنظمة الكتابة لحل ملف الكتابة للتصدير المعطى. يجب تضمين هذا الشرط دائمًا أولاً.
  • "browser" - أي بيئة متصفح ويب.
  • "development" - يمكن استخدامها لتعريف نقطة دخول بيئة التطوير فقط، على سبيل المثال لتوفير سياق تصحيح أخطاء إضافي مثل رسائل خطأ أفضل عند التشغيل في وضع التطوير. يجب أن يكون دائمًا متبادلًا مع "production".
  • "production" - يمكن استخدامها لتعريف نقطة دخول بيئة الإنتاج. يجب أن يكون دائمًا متبادلًا مع "development".

بالنسبة لأوقات التشغيل الأخرى، يتم الاحتفاظ بتعريفات مفتاح الشرط الخاصة بالمنصة بواسطة WinterCG في مواصفات اقتراح Runtime Keys.

يمكن إضافة تعريفات شروط جديدة إلى هذه القائمة من خلال إنشاء طلب سحب إلى وثائق Node.js لهذا القسم. متطلبات إدراج تعريف شرط جديد هنا هي:

  • يجب أن يكون التعريف واضحًا وغير مبهم لجميع المُنفذين.
  • يجب تبرير حالة الاستخدام لسبب حاجة الشرط بشكل واضح.
  • يجب أن يكون هناك استخدام تنفيذ موجود كافٍ.
  • يجب ألا يتعارض اسم الشرط مع تعريف شرط آخر أو شرط قيد الاستخدام الواسع.
  • يجب أن يوفر إدراج تعريف الشرط ميزة تنسيق للنظام البيئي لن يكون ممكنًا بخلاف ذلك. على سبيل المثال، لن تكون هذه هي الحالة بالضرورة بالنسبة لشروط محددة للشركة أو التطبيق.
  • يجب أن يكون الشرط بحيث يتوقع مستخدم Node.js وجوده في وثائق Node.js الأساسية. الشرط "types" هو مثال جيد: إنه لا ينتمي حقًا إلى اقتراح Runtime Keys ولكنه مناسب هنا في وثائق Node.js.

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

الإشارة الذاتية إلى حزمة باستخدام اسمها

[السجل]

الإصدارالتغييرات
v13.6.0، v12.16.0إلغاء وضع الإشارة الذاتية إلى حزمة باستخدام اسمها.
v13.1.0، v12.16.0تمت الإضافة في: v13.1.0، v12.16.0

ضمن حزمة، يمكن الرجوع إلى القيم المُعرّفة في حقل package.json "exports" للحزمة عبر اسم الحزمة. على سبيل المثال، بافتراض أن package.json هو:

json
// package.json
{
  "name": "a-package",
  "exports": {
    ".": "./index.mjs",
    "./foo.js": "./foo.js"
  }
}

يمكن لأي وحدة ضمن تلك الحزمة الرجوع إلى تصدير في الحزمة نفسها:

js
// ./a-module.mjs
import { something } from 'a-package' // يستورد "something" من ./index.mjs.

تتوفر الإشارة الذاتية فقط إذا كان لدى package.json حقل "exports"، وسيسمح باستيراد ما يسمح به هذا الحقل "exports" (في package.json) فقط. لذا فإن الكود أدناه، بالنظر إلى الحزمة السابقة، سيولد خطأ وقت التشغيل:

js
// ./another-module.mjs

// يستورد "another" من ./m.mjs. يفشل لأن
// حقل "exports" في "package.json"
// لا يوفر تصديراً باسم "./m.mjs".
import { another } from 'a-package/m.mjs'

تتوفر الإشارة الذاتية أيضًا عند استخدام require، سواء في وحدة ES أو في وحدة CommonJS. على سبيل المثال، سيعمل هذا الكود أيضًا:

js
// ./a-module.js
const { something } = require('a-package/foo.js') // يحمّل من ./foo.js.

أخيرًا، تعمل الإشارة الذاتية أيضًا مع الحزم ذات النطاق. على سبيل المثال، سيعمل هذا الكود أيضًا:

json
// package.json
{
  "name": "@my/package",
  "exports": "./index.js"
}
js
// ./index.js
module.exports = 42
js
// ./other.js
console.log(require('@my/package'))
bash
$ node other.js
42

حزم CommonJS/ES المزدوجة

راجع مستودع أمثلة الحزم للحصول على التفاصيل.

تعريفات حقل Node.js package.json

يصف هذا القسم الحقول التي يستخدمها وقت تشغيل Node.js. تستخدم أدوات أخرى (مثل npm) حقولًا إضافية يتجاهلها Node.js ولا يتم توثيقها هنا.

تُستخدم الحقول التالية في ملفات package.json في Node.js:

  • "name" - ذات صلة عند استخدام الاستيرادات المسماة ضمن حزمة. تُستخدم أيضًا من قبل مديري الحزم كاسم الحزمة.
  • "main" - الوحدة الافتراضية عند تحميل الحزمة، إذا لم يتم تحديد exports، وفي إصدارات Node.js السابقة على إدخال exports.
  • "packageManager" - مدير الحزم الموصى به عند المساهمة في الحزمة. يتم الاستفادة منه بواسطة Corepack shims.
  • "type" - نوع الحزمة الذي يحدد ما إذا كان سيتم تحميل ملفات .js كـ CommonJS أو وحدات ES.
  • "exports" - صادرات الحزمة والصادرات الشرطية. عند وجوده، يحد من الوحدات الفرعية التي يمكن تحميلها من داخل الحزمة.
  • "imports" - استيرادات الحزمة، لاستخدامها من قبل الوحدات داخل الحزمة نفسها.

"name"

[History]

الإصدارالتغييرات
v13.6.0، v12.16.0إزالة خيار --experimental-resolve-self.
v13.1.0، v12.16.0تمت الإضافة في: v13.1.0، v12.16.0
json
{
  "name": "package-name"
}

يحدد حقل "name" اسم حزمتك. يتطلب النشر في سجل npm اسمًا يلبي متطلبات معينة.

يمكن استخدام حقل "name" بالإضافة إلى حقل "exports" لالرجوع إلى الذات لحزمة باستخدام اسمها.

"main"

تمت الإضافة في: v0.4.0

json
{
  "main": "./index.js"
}

يحدد حقل "main" نقطة الدخول للحزمة عند استيرادها بالاسم عبر بحث node_modules. قيمته هي مسار.

عندما تحتوي الحزمة على حقل "exports"، فسوف يحظى بالأولوية على حقل "main" عند استيراد الحزمة بالاسم.

كما أنه يحدد البرنامج النصي المستخدم عندما يتم تحميل دليل الحزمة عبر require().

js
// هذا يحل في ./path/to/directory/index.js.
require('./path/to/directory')

"packageManager"

تمت الإضافة في: v16.9.0، v14.19.0

[مستقر: 1 - تجريبي]

مستقر: 1 الثبات: 1 - تجريبي

json
{
  "packageManager": "<package manager name>@<version>"
}

يحدد حقل "packageManager" مدير الحزم المتوقع استخدامه عند العمل على المشروع الحالي. يمكن تعيينه إلى أي من مديري الحزم المدعومين، وسوف يضمن أن تستخدم فرقك نفس إصدارات مدير الحزم بالضبط دون الحاجة إلى تثبيت أي شيء آخر غير Node.js.

يُعد هذا الحقل تجريبيًا حاليًا ويجب اختياره؛ راجع صفحة Corepack للحصول على تفاصيل حول الإجراء.

"type"

[History]

الإصدارالتغييرات
v13.2.0, v12.17.0إلغاء وضع --experimental-modules.
v12.0.0تمت الإضافة في: v12.0.0

يُعرّف حقل "type" تنسيق الوحدة النمطية التي يستخدمها Node.js لجميع ملفات .js التي تحتوي على ملف package.json هذا كأقرب ملف أب.

يتم تحميل الملفات التي تنتهي بـ .js ك وحدات نمطية ES عندما يحتوي ملف package.json الأب الأقرب على حقل مستوى أعلى "type" بقيمة "module".

يُعرّف ملف package.json الأب الأقرب بأنه أول ملف package.json يتم العثور عليه عند البحث في المجلد الحالي، ومجلد الأب الخاص بذلك المجلد، وهكذا حتى يتم الوصول إلى مجلد node_modules أو جذر القرص.

json
// package.json
{
  "type": "module"
}
bash
# في نفس مجلد ملف package.json السابق {#in-same-folder-as-preceding-packagejson}
node my-app.js # يتم تشغيله ك وحدة نمطية ES

إذا كان ملف package.json الأب الأقرب يفتقر إلى حقل "type"، أو يحتوي على "type": "commonjs"، فسيتم التعامل مع ملفات .js كـ CommonJS. إذا تم الوصول إلى جذر القرص ولم يتم العثور على أي ملف package.json، فسيتم التعامل مع ملفات .js كـ CommonJS.

يتم التعامل مع عبارات import الخاصة بملفات .js ك وحدات نمطية ES إذا كان ملف package.json الأب الأقرب يحتوي على "type": "module".

js
// my-app.js، جزء من نفس المثال أعلاه
import './startup.js' // تم تحميله ك وحدة نمطية ES بسبب package.json

بغض النظر عن قيمة حقل "type"، يتم دائمًا التعامل مع ملفات .mjs ك وحدات نمطية ES، ويتم دائمًا التعامل مع ملفات .cjs كـ CommonJS.

"exports"

[History]

الإصدارالتغييرات
v14.13.0, v12.20.0إضافة دعم لأنماط "exports".
v13.7.0, v12.17.0إلغاء وضع تصدير مشروط.
v13.7.0, v12.16.0تطبيق ترتيب تصدير مشروط منطقي.
v13.7.0, v12.16.0إزالة خيار --experimental-conditional-exports. في الإصدار 12.16.0، لا يزال التصدير المشروط ضمن --experimental-modules.
v13.2.0, v12.16.0تطبيق التصدير المشروط.
v12.7.0تمت الإضافة في: v12.7.0
json
{
  "exports": "./index.js"
}

يسمح حقل "exports" بتعريف نقاط الدخول للحزمة عند استيرادها بالاسم الذي تم تحميله إما عبر بحث node_modules أو مرجع ذاتي إلى اسمها الخاص. وهو مدعوم في Node.js 12+ كبديل لـ "main" الذي يمكنه دعم تعريف تصدير المسار الفرعي والصادرات الشرطية مع تغليف الوحدات الداخلية غير المصدرة.

يمكن أيضًا استخدام الصادرات الشرطية ضمن "exports" لتحديد نقاط دخول حزمة مختلفة لكل بيئة، بما في ذلك ما إذا كانت الحزمة تتم الإشارة إليها عبر require أو عبر import.

يجب أن تكون جميع المسارات المُعرّفة في "exports" عناوين URL لملفات نسبية تبدأ بـ ./.

"imports"

مضاف في: v14.6.0، v12.19.0

json
// package.json
{
  "imports": {
    "#dep": {
      "node": "dep-node-native",
      "default": "./dep-polyfill.js"
    }
  },
  "dependencies": {
    "dep-node-native": "^1.0.0"
  }
}

يجب أن تكون المدخلات في حقل imports سلاسل نصية تبدأ بـ #.

يسمح استيراد الحزم بتعيين الخرائط إلى حزم خارجية.

يُعرّف هذا الحقل استيراد المسارات الفرعية للحزمة الحالية.