الشهرة والاستخدام الواسع لبيئة نود 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.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.