اذهب إلى المحتوى

إدارة الوحدات البرمجية في Node.js باستخدام npm وملف package.json


Hassan Hedr

الشهرة والاستخدام الواسع لبيئة نود Node.js في تطوير تطبيقات النظم أو الواجهات الخلفية للويب سببها الأساسي مزايا السرعة والأداء العالي للغة جافاسكربت عند التعامل مع الدخل والخرج I/O، واعتمدت عليها العديد من التطبيقات كبيرة الحجم ما زاد تعقيد وصعوبة إدارة اعتمادياتها dependencies، حيث يوفر نود نظام تقسيم الشيفرة والاعتماديات إلى وحدات modules لتنظيمها وحل تلك المشكلة، ومن أبسط أشكالها هي أي ملف جافاسكربت يحوي توابع وكائنات يمكن استخدامها من قبل البرامج أو الوحدات الأخرى، ويُدعى تجمع عدة وحدات معًا بالحزمة package، وتُدار مجموعة الحزم باستخدام برنامج مخصص لإدارة الحزم من أشهرها مدير حزم نود npm، والذي يأتي افتراضيًا مع نود ويستخدم لإدارة الحزم الخارجية في المشاريع المبنية ضمن نود، ويستخدم أيضًا لتثبيت العديد من أدوات سطر الأوامر ولتشغيل النصوص أو السكربتات البرمجية للمشاريع، فهو يدير تلك الحزم ويخزن معلوماتها ضمن ملف يسمى package.json داخل مجلد المشروع ويحوي على معلومات مثل:

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

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

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

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

إنشاء ملف الحزمة package.json

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

بدايةً، نُنشئ ملفًا نسميه package.json، سيحوي على البيانات الوصفية للمشروع وتفاصيل الاعتماديات التي سيعتمد عليها، وكما تشير لاحقة ذلك الملف فمحتوياته ستكون مكتوبة بصيغة JSON وهي الصيغة المعتمدة لتخزين البيانات ومشاركتها على شكل كائنات جافاسكربت objects، وتتألف من أزواج من المفاتيح والقيم key/value المقابلة لها.

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

استخدام الأمر init

أول خطوة هي إنشاء مجلد للمشروع الذي سنتدرب عليه من سطر الأوامر أو بأي طريقة أخرى ننشئ مجلدًا جديدًا بالاسم locator:

mkdir locator

وننتقل إليه:

cd locator

والآن ننفذ أمر تهيئة ملف package.json:

npm init

ملاحظة: إذا كنا ننوي استخدام مدير الإصدارات Git لإدارة إصدارات المشروع وحفظ ملفاته، ننشئ مستودع Git داخل مجلد المشروع أولًا قبل تنفيذ أمر التهيئة npm init، وسيعلم حينها الأمر أن عملية التهيئة لملف الحزمة تتم بداخل مجلد يحوي مستودع Git، وإذا كان عنوان المستودع البعيد متاحًا ضمنه سيتم إضافة قيم للحقول repository و bugs و homepage تلقائيًا إلى ملف package.json، أما في حال تهيئة المستودع بعد تنفيذ أمر التهيئة سنحتاج حينها لإضافة تلك الحقول وتعيين قيمها يدويًا.

بعد تنفيذ الأمر السابق سيظهر الخرج التالي:

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (locator)

أول سؤال سنُسأل عنه هو اسم المشروع name، فإن لم تُعط فستأخذ افتراضيًا اسم المجلد للمشروع، ونلاحظ دومًا اقتراح القيم الافتراضية بين القوسين ()، وبما أن القيمة الافتراضية هي ما نريدها يمكننا الضغط على زر الإدخال ENTER مباشرةً لقبولها.

السؤال التالي هو عن رقم إصدار المشروع version، حيث أنها ضرورية مع اسم المشروع في حال مشاركة الحزمة التي سنطورها في مستودع حزم npm، فتستخدم حزم نود عادة الترقيم الدلالي Semantic Versioning لإصداراتها، وفيها يدل الرقم الأول على الإصدار الأساسي MAJOR الذي يشير أنه أجريت تغييرات جذرية على الحزمة، والرقم الثاني يدل على الإصدار الثانوي MINOR الذي يشير لإضافة مزايا على الحزمة، والرقم الثالث والأخير يدل على إصدار الترقيع PATCH الذي يشير لتصحيح أخطاء ضمن الحزمة.

نضغط على زر الإدخال ENTER لقبول القيمة الافتراضية لأول إصدار من الحزمة وهو 1.0.0.

الحقل التالي هو حقل الوصف للمشروع description وهو شرح مختصر عن المشروع ووظيفته يفيد عند البحث عن تلك الحزمة من قبل المستخدمين إن نُشر على الإنترنت، والحزمة locator التي سنطورها وظيفتها جلب عنوان IP للمستخدم وإعادة اسم البلد الذي ينتمي له هذا العنوان، وهنا يمكننا كتابة وصف معبر عن وظيفة هذه الحزمة باللغة الإنكليزية شبيه بالتالي:

Finds the country of origin of the incoming request

السؤال التالي هو عن الملف الأساسي أو المدخل للمشروع entry point فعند تثبيت أي حزمة واستخدامها ضمن مشروع آخر واستيرادها فإن أول ما سيُحمّل هو الملف الذي سنحدده في هذا الحقل، وقيمة المسار للملف المحدد في الحقل main يجب أن تكون نسبةً لمجلد المشروع الجذري الذي أول ما يحوي فيه الملف package.json، ويمكننا قبول القيمة الافتراضية المقترحة والضغط على زر الإدخال ENTER باعتبار أن الملف index.js سيكون المدخل هنا.

ملاحظة: تستخدم معظم الحزم الملف index.js كمدخل لها، لهذا تعتبر هذه القيمة الافتراضية للحقل main كمدخل لوحدات npm، وحتى عند غياب ملف package.json من مجلد الوحدة ستحاول نود افتراضيًا تحميل الملف index.js من مجلد جذر الحزمة المُستخدمة.

السؤال التالي هو عن أمر تنفيذ اختبارات الحزمة test command، وقيمته يمكن أن تكون إما مسار لملف تنفيذي أو أمر لتشغيل اختبارات المشروع، وتستخدم معظم وحدات نود الشهيرة أطر اختبار مثل Mocha أو Jest أو Jasmine أو غيرها لكتابة اختبارات المشروع، ويمكننا ترك قيمة هذا الحقل فارغة بالضغط على زر الإدخال.

سنُسأل بعدها عن عنوان مستودع Git للمشروع، هنا نُدخل مسار المستودع للمشروع الحالي الذي قد يكون مُستضافًا على أحد الخدمات الشهيرة مثل GitHub، ويمكنك ترك قيمته فارغة أيضًا.

سيُطلب منا بعدها إدخال بعض الكلمات المفتاحية كقيمة للحقل keywords، والقيمة عبارة عن مصفوفة من السلاسل النصية تحوي مصطلحات وكلمات مفتاحية ستفيد المستخدمين عند البحث عن الحزمة عند نشرها عبر الإنترنت، لذا يفضل إدخال بعض الكلمات القصيرة التي تتعلق بعمل الحزمة لتزداد فرصة العثور عليها وظهورها ضمن عمليات البحث، وندخل الكلمات المفتاحية مفصولًا بينها بفاصلة، فمثلًا لمشروعنا يمكن إدخال بعض الكلمات كالتالي ip,geo,country، ينتج عن ذلك مصفوفة تحوي ثلاث عناصر كقيمة للحقل keywords داخل الملف package.json.

الحقل التالي هو اسم صاحب المشروع أو الكاتب والمطور له author، حيث يفيد إدخال تلك المعلومة المستخدمين الراغبين بالتواصل معه لأي سبب، مثل اكتشاف ثغرة أو مشكلة في عمل الحزمة، وتكون قيمة هذا الحقل سلسة نصية بالصيغة التالية: "الاسم <عنوان البريد الإلكتروني> (موقع الويب)" مثلًا:

"Hassan <hassan@example.com> (https://mywebsite.com)"

وإدخال عنوان البريد الإلكتروني وموقع الويب اختياريان ويمكن الاكتفاء بإدخال الاسم فقط.

القيمة الأخيرة هي لحقل رخصة الاستخدام license، حيث يحدد ذلك الصلاحيات القانونية والحدود المسموح بها استخدام هذه الحزمة أو المشروع، وبما أن أغلب حزم نود مفتوحة المصدر لذا القيمة الافتراضية المقترحة هي رخصة ISC، لذا يجب قبل تعيين تلك القيمة مراجعة الرخص المتاحة واختيار المناسبة منها للمشروع، ويمكنك الاطلاع على معلومات أكثر على رخص المشاريع المفتوحة المصدر وفي حال كانت الحزمة مطورة للاستخدام الخاص وليست للمشاركة يمكن إدخال القيمة UNLICENSED لتحديد الحزمة كغير مرخصة للاستخدام العام أبدًا، ولمشروعنا الحالي يمكن استخدام القيمة الافتراضية بالضغط على زر الإدخال وإنهاء تهيئة وإنشاء الملف.

سيعرض بعد ذلك الأمر init محتوى ملف package.json الذي سيُنشئه لنراجعه ونتأكد من جميع القيم وسيظهر خرج كالتالي:

About to write to /home/hassan/locator/package.json:

{
  "name": "locator",
  "version": "1.0.0",
  "description": "Finds the country of origin of the incoming request",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "ip",
    "geo",
    "country"
  ],
  "author": "Hassan <hassan@your_domain> (https://your_domain)",
  "license": "ISC"
}


Is this OK? (yes)</hassan@your_domain>

في حال كانت كل البيانات صحيحة نضغط زر الإدخال للإنهاء وإنشاء ملف package.json وبعدها يمكننا تثبيت الوحدات البرمجية الخارجية ليعتمد عليها مشروعنا وتضاف تفاصيلها في ذلك الملف.

تثبيت الوحدات البرمجية

عند تطوير المشاريع البرمجية عادة ما نفوض المهام التي لا تتعلق بصلب عمل المشروع إلى مكتبات برمجية خارجية متخصصة في ذلك، ما يتيح للمطور التركيز على عمل المشروع الحالي فقط وتطوير التطبيق بسرعة وكفاءة أكبر عبر استخدام الأدوات والشيفرات البرمجية التي طورها الآخرون على مبدأ لا تخترع العجلة من جديد، فمثلًا إذا احتاج مشروعنا locator لإرسال طلب خارجي إلى الواجهة البرمجية API لخدمة تقدم البيانات الجغرافية اللازمة لنا وهنا يمكننا استخدام مكتبة خاصة بإرسال طلبات HTTP مباشرةً بدلًا من كتابة ذلك بأنفسنا، حيث وظيفة المشروع هي تقديم تلك البيانات الجغرافية إلى مستخدم الحزمة فقط، وأما تفاصيل إرسال طلبات HTTP لا تتعلق بوظيفة الحزمة لذا يمكن تفويضها لمكتبة خارجية جاهزة مختصة بذلك، يمكننا مثلًا استخدام مكتبة axios والتي تساعد في إرسال طلبات HTTP بشكل عملي وسهل، ولتثبيتها ننفذ الأمر التالي:

npm install axios --save

الجزء الأول من هذا الأمر npm install هو أمر تثبيت الحزم، ويمكن اختصارًا تنفيذه كالتالي npm i، حيث نمرر له أسماء الحزم التي نرغب بتثبيتها مفصولة بفراغات بينها وفي حالتنا نريد فقط تثبيت حزمة مكتبة axios، بعدها واختياريًا يمكن تمرير الخيار ‎--save لحفظ المكتبات المُثبتة كاعتماديات للمشروع ضمن ملف package.json وهو السلوك الافتراضي حتى دون ذكر ذلك الخيار، وبعد تثبيت المكتبة سنلاحظ ظهور خرج مشابه للتالي:

...
+ axios@0.27.2
added 5 packages from 8 contributors and audited 5 packages in 0.764s
found 0 vulnerabilities

والآن باستخدام أي محرر نصوص نعاين محتوى الملف package.json لنلاحظ التغييرات، سنستخدم مثلًا محرر nano كالتالي:

nano package.json

نلاحظ ظهور خاصية جديدة بالاسم dependencies أو الاعتماديات، والتي تحوي على اعتماديات المشروع الحالي:

{
  "name": "locator",
  "version": "1.0.0",
  "description": "Finds the country of origin of the incoming request",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "ip",
    "geo",
    "country"
  ],
  "author": "Hassan hassan@your_domain (https://your_domain)",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.27.2"
  }
}

وإضافة الوحدة البرمجية التي ثبتناها مع رقم إصدارها يحدد للمطورين الآخرين العاملين على نفس المشروع الاعتماديات الخارجية التي يتطلبها تشغيله.

ملاحظة: قد انتبهت إلى وجود الرمز ^ قبل رقم الإصدار لاعتمادية axios، وبما أن الترقيم الدلالي يحوي ثلاثة أرقام وهي الأساسي الجذري MAJOR والثانوي البسيط MINOR والترقيع PATCH فيشير ذلك الرمز إلى تثبيت الإصدار الأساسي للاعتمادية ولا مانع من تغير الإصدار الثانوي البسيط أو إصدار الترقيع أي يمكن تنزيل الإصدار 0.28.0 أو 0.28.1 مثلًا واستخدامه ضمن المشروع، ويمكن استخدام الرمز ~ أيضًا لتثبيت الإصدار الأساسي والثانوي وسماحية تغير إصدار الترقيع فقط أي يُقبَل إصدار 0.27.3 أو 0.27.4 مثلًا.

ويمكننا إغلاق الملف package.json الآن بعد الانتهاء من الاطلاع عليه، وفي حال استخدام محرر nano يمكن الخروج بالضغط على CTRL + X ثم ENTER.

اعتماديات لازمة أثناء تطوير المشروع

اعتماديات التطوير development dependencies هي الاعتماديات التي ستُستخدم فقط خلال مرحلة تطوير المشروع وليس خلال مراحل بناء المشروع ونشره ولا يعتمد عليها خلال مرحلة الإنتاج production وتشبه تلك الدعامات والسلالم والسقالات التي توضع أثناء بناء عمارة ثم تُزال عند الانتهاء، فمثلًا يستخدم المطورون عادة مكتبات لفحص الشيفرات البرمجية وكشف الأخطاء المحتملة وتوحيد تنسيق كتابة الشيفرات أو ما يدعى Linter.

لنجرب تثبيت اعتمادية تطوير لتنقيح صياغة الشيفرات تدعى eslint ضمن المشروع بتنفيذ الأمر التالي:

npm i eslint@8.0.0 --save-dev

نلاحظ إضافة الخيار ‎--save-dev، والذي يخبر npm بحفظ الاعتماديات التي نثبتها كاعتمادية تطوير فقط، لاحظ أيضًا إضافة اللاحقة ‎@8.0.0 بعد اسم الاعتمادية حيث يتم وسم إصدارات المكتبات عند تحديثها، ويدل الرمز @ مدير الحزم npm أن يثبت إصدار معين من تلك الاعتمادية وفي حال تجاهلنا إضافة ذلك الوسم سيتم تثبيت آخر نسخة موسومة متاحة من تلك الاعتمادية، والآن لنعاين ملف package.json مجددًا:

nano package.json

ونلاحظ تغير محتواه وإضافة اعتمادية التطوير:

{
  "name": "locator",
  "version": "1.0.0",
  "description": "Finds the country of origin of the incoming request",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "ip",
    "geo",
    "country"
  ],
  "author": "Hassan hassan@your_domain (https://your_domain)",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.19.0"
  },
  "devDependencies": {
    "eslint": "^8.0.0"
  }
}

نلاحظ إضافة الاعتمادية eslint ضمن الحقل devDependencies مع رقم الإصدار الذي حددناه لها.

المجلد node_modules والملف package-lock.json المولدان تلقائيا

عند أول تثبيت لأي حزمة ضمن مشروع نود سيُنشئ npm تلقائيًا المجلد node_modules ليُخزن ضمنه كل الوحدات البرمجية التي يحتاج إليها المشروع الحالي، وأيضًا سيُنشئ الملف package-lock.json والذي يحوي معلومات عن تفاصيل إصدارات المكتبات المُثبتة في المشروع، ولنتأكد من وجود تلك الملفات ضمن مجلد المشروع يمكننا ذلك بتنفيذ الأمر ls في سطر الأوامر لعرض الملفات الموجودة وسيظهر لنا التالي:

node_modules    package.json    package-lock.json

يحوي المجلد node_modules كافة الاعتماديات المُثبتة في المشروع، وعادة لا نضيف هذا المجلد إلى مستودع المشروع لأن حجم هذا المجلد سيكبر بعد تثبيتنا لعدة اعتماديات، ولأن ملف package-lock.json يحوي داخله أساسًا تفاصيل إصدارات المكتبات المثبتة ضمن مجلد node_modules تمامًا كما هي، ما يجعل وجود ذلك المجلد ضمن مستودع المشروع غير ضروري.

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

تثبيت الاعتماديات باستخدام package.json

يمكن باستخدام الملفين package.json و package-lock.json إعداد الاعتماديات المحددة فيهما لبدء أو استئناف العمل على تطوير مشروع مع فريق، ولنفهم ذلك أكثر يمكننا إنشاء مجلد جديد فارغ بجوار مجلد المشروع الحالي بالاسم cloned_locator بتنفيذ الأوامر:

cd ..
mkdir cloned_locator

ثم ننتقل إلى ذلك المجلد:

cd cloned_locator

ننسخ الآن ملفي package.json و package-lock.json من مجلد المشروع الأصلي locator إلى المجلد الجديد cloned_locator بتنفيذ الأمر:

cp ../locator/package.json ../locator/package-lock.json .

والآن يمكننا تثبيت نفس اعتماديات المشروع الأصلي بتنفيذ الأمر التالي:

npm i

سيتحقق بعدها npm من وجود ملف package-lock.json داخل المجلد الحالي، وفي حال عدم وجوده سيقرأ محتويات ملف package.json لمعرفة الاعتماديات المطلوب تثبيتها، وعادة تكون عملية التثبيت أسرع عند وجود ملف package-lock.json لأنه يحوي الأرقام الدقيقة لإصدارات الاعتماديات المطلوبة، ولن يحتاج حينها npm للبحث عن أرقام إصدارات تناسب المشروع.

وكما ذكرنا، يمكن تجاهل تثبيت اعتماديات التطوير عند نشر التطبيق في مرحلة الإنتاج، وهي الاعتماديات المذكورة في ملف package.json ضمن الحقل devDependencies ولا تؤثر أبدًا على عمل التطبيق، لذا عند تثبيت المشروع خلال عملية نشر التطبيق يمكن تجاهل تثبيت تلك الاعتماديات بتنفيذ أمر التثبيت كالتالي:

npm i --production

حيث يشير الخيار ‎--production إلى تجاهل اعتماديات التطوير خلال عملية تثبيت اعتماديات المشروع، ولن نستعمل هذا الخيار إلا في حالات محدَّدة فقط تتعمل بمرحلة بناء المشروع وتجهيزه للنشر على الإنترنت.

ولا ننسَ أيضًا العودة إلى مجلد المشروع الأساسي قبل لمتابعة تطبيق باقي الأمثلة:

cd ../locator

تثبيت الحزم على مستوى النظام

ثبتنا حتى الآن الاعتماديات الخاصة بمشروعنا locator، ولكن يمكن استخدام npm أيضًا للتثبيت اعتماديات وحزم على مستوى نظام التشغيل، ما يعني أن الحزمة المثبتة بتلك الطريقة ستكون متاحة للمستخدم في أي مكان ضمن النظام بشكل مشابه للأوامر المتوفرة في سطر الأوامر، حيث تفيد هذه الميزة باستخدام الوحدات البرمجية كأدوات سطر الأوامر لتنفيذ مهام محددة في المشروع، فمثلًا يمكن استخدام مكتبة Hexo من سطر الأوامر من أي مكان بعد تثبيتها لإنشاء موقع لمدونة بمحتوى ثابت، وذلك بتنفيذ أمر التثبيت العام كالتالي:

npm i hexo-cli -g

كما نلاحظ إذا أردنا تثبيت أي حزمة عامة سنضيف الخيار ‎-g -اختصارًا إلى الكلمة Global عام- لنهاية أمر التثبيت فقط.

ملاحظة: قد يظهر خطأ عند محاولة تثبيت حزمة عامة والسبب قد يكون في صلاحيات المستخدم الحالي، لذا قد تحتاج لصلاحيات مستخدم مسؤول وحاول آنذاك فتح الطرفية بصلاحية مسؤول super user أو إذا كنت تستخدم نظام شبيه بيونكس يمكن تنفيذ الأمر كالتالي: sudo npm i hexo-cli -g.

ويمكن التأكد من نجاح عملية التثبيت للمكتبة بتنفيذ الأمر التالي:

hexo --version

سيظهر خرج مشابه للتالي:

hexo-cli: 4.3.0
os: linux 5.15.0-35-generic Ubuntu 22.04 LTS 22.04 LTS (Jammy Jellyfish)
node: 18.3.0
v8: 10.2.154.4-node.8
uv: 1.43.0
zlib: 1.2.11
brotli: 1.0.9
ares: 1.18.1
modules: 108
nghttp2: 1.47.0
napi: 8
llhttp: 6.0.6
openssl: 3.0.3+quic
cldr: 41.0
icu: 71.1
tz: 2022a
unicode: 14.0
ngtcp2: 0.1.0-DEV
nghttp3: 0.1.0-DEV

تعلمنا كيف يمكن تثبيت الوحدات البرمجية الخارجية باستخدام npm، وكيف أنه يمكن تثبيت الحزم محليًا إما كاعتمادية إنتاج أو تطوير، وشاهدنا كيف يمكن تثبيت الحزم باستخدام ملف package.json بمفرده أو مع ملف package-lock.json مجهزة مسبقًا لتوحيد تثبيت إصدارات الاعتماديات للمشروع بين أفراد فريق المطورين، وتعلمنا كيف يمكن تثبيت الحزم عمومًا على النظام باستخدام الخيار ‎-g لنتمكن من استخدامها من أي مكان سواء داخل مشروع نود أو خارجه.

والآن بعد ما تعلمناه من طرق لتثبيت الوحدات البرمجية، سنتعلم في الفقرة التالية طرق إدارة تلك الاعتماديات.

إدارة الوحدات البرمجية

لا يقتصر دور مدير الحزم على تثبيت الوحدات البرمجية بل يتوسع إلى تنفيذ العديد من المهام الأخرى التي تتعلق بإدارة الحزم بعد تثبيتها فمثلًا يحوي npm على أكثر من 20 أمرًا يتعلق بذلك، حيث سنتعرف في هذه الفقرة على بعضها والتي تقوم بما يلي:

  • عرض الوحدات البرمجية المثبتة.
  • ترقية الوحدات البرمجية إلى إصداراتها الأحدث.
  • إلغاء تثبيت الوحدات البرمجية التي لا نحتاج إليها.
  • فحص الوحدات البرمجية لتحديد الثغرات الأمنية وإصلاحها.

سنطبق الأوامر المتعلقة بتلك المهام على مجلد مشروعنا locator، ويمكن تنفيذ نفس تلك المهام بشكل عام عبر إضافة الخيار ‎-g في نهاية الأوامر، كما فعلنا عند تثبيت حزمة عامة على مستوى النظام سابقًا.

عرض قائمة بالوحدات المثبتة

يمكن معرفة الوحدات البرمجية المُثبتة ضمن مشروع ما بتنفيذ الأمر list أو ls الخاص بمدير الحزم npm بدلًا من معاينة الملف package.json يدويًا، وذلك بتنفيذ الأمر كالتالي:

npm ls

ليظهر لنا خرج مشابه للتالي:

├── axios@0.27.2
└── eslint@8.0.0

يمكن إضافة الخيار ‎--depth لتحديد مستوى عرض شجرة الاعتماديات السابقة، فمثلًا عندما نمرر له القيمة 0 سيظهر لنا الاعتماديات في أول مستوى فقط وهي اعتماديات المشروع الحالي فقط كما لو نفذنا الأمر npm ls دون خيارات إضافية، ويمكن إضافة الخيار ‎--all لعرض شجرة الاعتماديات كاملة كالتالي:

npm ls --all

ليظهر خرج مشابه للتالي:

├─┬ axios@0.27.2
 ├── follow-redirects@1.15.1
 └─┬ form-data@4.0.0
   ├── asynckit@0.4.0
   ├─┬ combined-stream@1.0.8
    └── delayed-stream@1.0.0
   └─┬ mime-types@2.1.35
     └── mime-db@1.52.0
└─┬ eslint@8.0.0
  ├─┬ @eslint/eslintrc@1.3.0
   ├── ajv@6.12.6 deduped
   ├── debug@4.3.4 deduped
   ├── espree@9.3.2 deduped
   ├── globals@13.15.0 deduped
   ├── ignore@5.2.0
   ├── import-fresh@3.3.0 deduped
   ├── js-yaml@4.1.0 deduped
   ├── minimatch@3.1.2 deduped
   └── strip-json-comments@3.1.1 deduped

. . .

ترقية الوحدات البرمجية

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

npm outdated

سيظهر خرج كالتالي:

Package  Current  Wanted  Latest  Location             Depended by
eslint     8.0.0  8.17.0  8.17.0  node_modules/eslint  locator

يحوي العمود الأول Package من الجدول السابق على أسماء الحزم الممكن ترقيتها، والعمود الثاني Current يُظهر رقم الإصدار الحالي للحزمة المثبتة ضمن المشروع، والعمود Wanted يُظهر رقم آخر إصدار يوافق متطلبات المشروع من الحزمة المطلوب ترقيتها والعمود Latest يُظهر آخر إصدار منشور من تلك الحزمة وقد لا يوافق متطلبات المشروع، والعمود Location يُظهر مسار مجلد الحزمة الحالي، حيث يمكن تمرير الخيار ‎--depth أيضًا للأمر outdated تمامًا كما فعلنا مع الأمر ls، وتكون قيمته الافتراضية هي الصفر.

ونجد من الخرج السابق أن الحزمة eslint يمكن ترقيتها إلى إصدار أحدث، لهذا يمكن استخدام أمر الترقية update أو اختصاره up مع ذكر أسماء الحزم التي نرغب بترقيتها كالتالي:

npm up eslint

سيُظهر لنا خرج هذا الأمر رقم إصدار النسخة الجديدة المثبتة:

removed 7 packages, changed 4 packages, and audited 91 packages in 1s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

وللتأكد من ذلك يمكننا الاستفادة من الأمر npm ls وتمرير اسم الحزمة eslint ليظهر لنا تفاصيل الحزمة المثبتة ضمن المشروع كالتالي:

npm ls eslint

نلاحظ عند تمرير اسم حزمة معينة للأمر npm ls ستظهر لنا شجرة الاعتماديات المثبتة ضمن المشروع لكن ستحوي فقط على ما يخص الحزمة المحددة eslint:

└─┬ eslint@8.17.0
  └─┬ eslint-utils@3.0.0
    └── eslint@8.17.0 deduped

ويمكن ترقية كل الاعتماديات في المشروع باستخدام أمر الترقية دون تحديد اسم أي حزمة كالتالي:

npm up

إلغاء تثبيت الوحدات البرمجية

يمكن استخدام الأمر uninstall الخاص بمدير الحزم npm لإلغاء تثبيت وحدات من المشروع بإزالة الحزمة أو الوحدة تلك من مجلد node_modules ويُحذف اسم تلك الحزمة من قائمة الاعتماديات ضمن الملف package.json وملف package-lock.json.

نضطر في الكثير من الأحيان لإزالة حزم معينة من مشروع نعمل عليه، مثلًا لإزالة حزمة ما بعد تجربتها وتبين أنها لا تحقق المطلوب أو أنها صعبة الاستخدام، فمثلًا لو أن حزمة axios التي نستخدمها لم تفي بالغرض المطلوب منها وهو إرسال طلبات HTTP أو أنها صعبة الاستخدام بالنسبة لهذا المشروع يمكن إلغاء تثبيتها بتنفيذ الأمر uninstall أو اختصاره un وتمرير اسم الحزمة كالتالي:

npm un axios

نحصل على الخرج:

removed 8 packages, and audited 83 packages in 542ms

13 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

نلاحظ عدم ظهور اسم الحزمة التي ألغي تثبيتها، لذا نتأكد من ذلك بعرض الحزم المثبتة حاليًا كالتالي:

npm ls

سنلاحظ من الخرج التالي أن الحزمة eslint أصبحت الوحيدة المثبتة ضمن المشروع، ما يدل على إلغاء تثبيت حزمة axios بنجاح:

locator@1.0.0 /home/ubuntu/locator
└── eslint@8.17.0

فحص الوحدات وتدقيقها

يُستعمل الأمر audit من مدير الحزم npm في تدقيق الحزم وفحصها لعرض المخاطر الأمنية المحتملة ضمن شجرة اعتماديات المشروع المثبتة، ولنختبر ذلك مثلًا بتثبيت إصدار قديم من حزمة request كالتالي:

npm i request@2.60.0

وسنلاحظ فورًا عند تثبيت حزم قديمة منتهية الصلاحية ظهور خرج مشابه للتالي:

npm WARN deprecated cryptiles@2.0.5: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated sntp@1.0.9: This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.
npm WARN deprecated boom@2.10.1: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated node-uuid@1.4.8: Use uuid module instead
npm WARN deprecated har-validator@1.8.0: this library is no longer supported
npm WARN deprecated hoek@2.16.3: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated request@2.60.0: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated hawk@3.1.3: This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.

added 56 packages, and audited 139 packages in 4s

13 packages are looking for funding
  run `npm fund` for details

9 vulnerabilities (5 moderate, 2 high, 2 critical)

To address all issues, run:
  npm audit fix --force

Run `npm audit` for details.

يخبرنا npm بوجود حزم قديمة يُفضل عدم استخدامها ووجود ثغرات ضمن الاعتماديات الحالية للمشروع، ولعرض تفاصيل أكثر عن ذلك يمكننا تنفيذ الأمر:

npm audit

سيظهر لنا جدولًا يعرض المخاطر الأمنية الموجودة:

# npm audit report

bl  <1.2.3
Severity: moderate
Remote Memory Exposure in bl - https://github.com/advisories/GHSA-pp7h-53gx-mx7r
fix available via `npm audit fix`
node_modules/bl
  request  2.16.0 - 2.86.0
  Depends on vulnerable versions of bl
  Depends on vulnerable versions of hawk
  Depends on vulnerable versions of qs
  Depends on vulnerable versions of tunnel-agent
  node_modules/request

cryptiles  <=4.1.1
Severity: critical
Insufficient Entropy in cryptiles - https://github.com/advisories/GHSA-rq8g-5pc5-wrhr
Depends on vulnerable versions of boom
fix available via `npm audit fix`
node_modules/cryptiles
  hawk  <=9.0.0
  Depends on vulnerable versions of boom
  Depends on vulnerable versions of cryptiles
  Depends on vulnerable versions of hoek
  Depends on vulnerable versions of sntp
  node_modules/hawk

. . .

9 vulnerabilities (5 moderate, 2 high, 2 critical)

To address all issues, run:
  npm audit fix

نلاحظ ظهور مسارات لتلك الثغرات واقتراح npm طرقًا لسدها إما بتحديث تلك الاعتماديات أو تنفيذ الأمر الفرعي fix للأمر audit لإصلاح المشاكل تلقائيًا كما هو مقترح، ولنجرب ذلك الأمر ونرى ما يحصل:

npm audit fix

يظهر لنا:

npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN deprecated uuid@3.4.0: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142

added 19 packages, removed 34 packages, changed 13 packages, and audited 124 packages in 3s

14 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

نفذ npm ترقية لحزمتين موجودتين ما أدى لحل المشاكل الأمنية الموجودة، مع ذلك لا زال هناك ثلاث حزم ضمن المشروع قديمة ويفضل عدم استخدامها، وبهذا نرى أن الأمر audit fix لا يُصلح كافة المشاكل الموجودة دومًا، وذلك لأن حل تلك المشاكل يتطلب ترقية الحزم إلى إصدارات أعلى والتي قد تؤدي بدورها إلى حصول تعارض في شجرة الاعتماديات مما يتسبب بمشاكل توقف عمل المشروع كله، ولكن يمكن إجبار npm على ترقية تلك الحزم بتمرير الخيار ‎--force وحل جميع تلك المشاكل كالتالي:

npm audit fix --force

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

ختامًا

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

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

ترجمة -وبتصرف- للمقال How To Use Node.js Modules with npm and package.json لصاحبه Stack Abuse.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...