Menu
العربية

أساسيات npm: تثبيت الحزم وإدارة التبعيات

تعرّف على npm من الداخل: كيف تثبّت الحزم، وتستخدم npm init، وتتعامل مع تبعيات التطوير، وما قصة مجلد node_modules وملف القفل.

ما هو npm بالضبط؟

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

عندما تنفّذ الأمر npm install express، تتواصل أداة الـ CLI مع المستودع، فتحمّل حزمة express وكل ما تعتمد عليه من حزم أخرى، ثم تضعها داخل مجلد اسمه node_modules، وتسجّل اسم الحزمة ورقم إصدارها في ملف package.json. هذه هي الدورة كاملةً باختصار.

إذا كان Node.js مثبّتاً لديك أصلاً، فإن npm موجود معه تلقائياً. للتأكد، نفّذ:

node --version
npm --version

إذا ظهر لك رقم إصدار في الحالتين، فأنت جاهز للانطلاق.

إنشاء مشروع جديد باستخدام npm init

أي مشروع npm لا بدّ أن يحتوي على ملف package.json، فهو بمثابة بطاقة تعريف المشروع: يضمّ الاسم والإصدار والـ scripts والاعتماديات (dependencies). وأسرع طريقة لتوليده هي الأمر npm init -y، الذي يعتمد القيم الافتراضية دون أي أسئلة:

mkdir my-app
cd my-app
npm init -y

يكتب شيئًا مثل:

{
  "name": "my-app",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

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

تثبيت حزمة باستخدام npm install

بعد أن يصبح لديك ملف package.json، يمكنك تثبيت أي حزمة عبر الأمر npm install (أو اختصارًا npm i):

npm install lodash

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

  1. يقوم npm بتنزيل مكتبة lodash مع كل اعتمادياتها داخل مجلد node_modules/.
  2. يضيف سطر "lodash": "^4.17.21" (أو أحدث إصدار متاح) إلى قسم dependencies في ملف package.json.
  3. يُنشئ ملف package-lock.json يسجّل فيه الإصدارات الدقيقة لكل حزمة موجودة في شجرة الاعتماديات.

الآن أصبح بإمكانك استخدام المكتبة:

index.js
Output
Click Run to see the output here.

استدعاء require (أو import في مشاريع ESM) يعثر على الحزمة بالبحث داخل مجلد node_modules. أنت لست مضطرًا لكتابة أي مسار، فمُحلِّل الوحدات في Node يتكفّل بهذه المهمة نيابةً عنك.

الفرق بين dependencies و devDependencies

ليست كل الحزم مطلوبة وقت تشغيل التطبيق في بيئة الإنتاج؛ فأدوات الاختبار ومدقّقات الكود (linters) وأدوات التجميع (bundlers) لا تهمّك إلا أثناء التطوير فقط. مثل هذه الحزم تُثبَّت باستخدام --save-dev (أو اختصارًا -D):

npm install --save-dev jest
npm install -D eslint prettier

تنزل هذه الحزم في قسم devDependencies بدلاً من dependencies:

{
  "dependencies": {
    "lodash": "^4.17.21"
  },
  "devDependencies": {
    "jest": "^29.7.0",
    "eslint": "^8.57.0",
    "prettier": "^3.2.5"
  }
}

على خادم الإنتاج، أمر npm install --omit=dev يتجاهل قسم التطوير بالكامل، مما يجعل عملية التثبيت أصغر حجمًا وأسرع. وتقسيم الحزم بشكل صحيح بين dependencies و devDependencies أهم مما يبدو — فوضع حزمة مثل webpack في dependencies عن طريق الخطأ يُضخّم حجم كل نشرة إنتاجية بلا داعٍ.

تثبيت جميع الحزم دفعة واحدة

عندما تستنسخ مستودعًا يحتوي مسبقًا على ملف package.json، لا داعي لكتابة اسم كل حزمة على حدة. يكفي تشغيل:

npm install

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

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

تحديث الحزم

الأمر npm outdated يعرض لك الحزم المتأخرة عن أحدث إصدار:

npm outdated

سترى جدولًا يحتوي على أعمدة Current وWanted وLatest. عمود Wanted يعرض أحدث إصدار مسموح به ضمن النطاق المحدد في ملف package.json (مثلًا مع ^4.17.21 يشمل أي إصدار أقل من 5.0.0). أما عمود Latest فيعرض أحدث إصدار منشور فعلًا، وقد يكون إصدارًا رئيسيًا جديدًا لم تختر الترقية إليه بعد.

للتحديث ضمن النطاق المسموح به:

npm update

للانتقال إلى أحدث إصدار فعلاً، بما في ذلك الترقيات في رقم الإصدار الرئيسي (major version)، ثبّت الحزمة من جديد مع @latest:

npm install lodash@latest

عادةً ما تكون الترقية الكبرى (Major) مؤشرًا على تغييرات قد تكسر شيفرتك، وهذا بالضبط ما يريد رقم الإصدار أن يوصله لك. لذلك قبل أن تقفز إلى إصدار رئيسي جديد، خذ دقيقة واطّلع على ملف التغييرات (changelog).

إزالة الحزم باستخدام npm uninstall

إزالة أي حزمة تتم بنفس منطق تثبيتها تمامًا:

npm uninstall lodash

هذا يحذف الحزمة من node_modules ويُزيل مُدخلها من package.json. أضف -D إذا كانت الحزمة من الـ devDependencies (npm يكتشفها في الحالتين، لكن التصريح بها يُجنّبك مفاجآت غير متوقعة في السكربتات).

الفرق بين التثبيت المحلي والعالمي في npm

الأصل أن يكون كل تثبيت محليًا — أي مرتبطًا بمشروع واحد داخل مجلد node_modules الخاص به. الاستثناء الوحيد هو أدوات سطر الأوامر التي تحتاجها متاحة في أي مكان على جهازك:

npm install -g typescript
npm install -g http-server

التثبيت العام (global install) يضع الأداة في مسار عام على مستوى النظام ويضيف مدخلها في bin إلى PATH، وبهذا تقدر تشغّل tsc أو http-server من أي مجلد. لكن المشكلة أن هذا النوع من التثبيت لا يُسجَّل ضمن المشروع نفسه، وغالباً ما يختلف من جهاز لآخر.

الحل الأنسب للأوامر العابرة هو استخدام npx الذي يأتي مع npm افتراضياً:

npx create-react-app my-app
npx prettier --write .

npx يشغّل أي حزمة دون الحاجة لتثبيتها بشكل عام (global) — ببساطة يجلبها عند الطلب، ينفذها، وانتهى الأمر. إذا كانت الأداة تستخدمها مرة واحدة فقط، فهذا أنظف بكثير من تثبيتها تثبيتاً دائماً على النظام.

مرجع سريع لأهم أوامر npm

الأوامر التي ستستخدمها فعلياً في عملك اليومي:

npm init -y                     # إنشاء package.json
npm install                     # تثبيت كل شيء في package.json
npm install <pkg>               # إضافة اعتمادية وقت التشغيل
npm install -D <pkg>            # إضافة اعتمادية تطوير
npm install -g <pkg>            # تثبيت أداة CLI بشكل عام
npm uninstall <pkg>             # إزالة اعتمادية
npm outdated                    # رؤية ما هو قديم
npm update                      # التحديث ضمن النطاقات المسموح بها
npm install <pkg>@latest        # الانتقال إلى أحدث إصدار
npm run <script>                # تشغيل سكريبت من package.json
npx <pkg>                       # تشغيل حزمة دون تثبيتها

هذا تقريبًا كل ما تحتاجه من npm. الباقي — كالنشر والـ workspaces والـ scoped packages — يمكنك تعلمه لاحقًا عندما تحتاجه فعلًا.

ماذا يوجد داخل مجلد node_modules؟

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

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

تعامَل مع node_modules باعتباره ناتجًا مُولَّدًا لا أكثر. لا تعدّل أي ملف بداخله أبدًا — أي تغيير تجريه سيختفي في المرة التالية التي يثبّت فيها أي شخص الحزم.

الخطوة التالية: شرح package.json

ملف package.json هو الملف الذي يقرأه npm ويعيد كتابته باستمرار خلف الكواليس. وعندما تتقن حقوله — مثل scripts وmain وtype ونطاقات الإصدارات وengines — يتحول npm من صندوق أسود غامض إلى أداة تمسك بزمامها تمامًا. وهذا موضوعنا القادم.

الأسئلة الشائعة

ما هو npm؟

npm هو مدير الحزم الافتراضي لـ Node.js، ويأتي مثبّتًا معه تلقائيًا. يوفّر مستودعًا عامًا ضخمًا لحزم JavaScript، بالإضافة إلى أداة سطر أوامر لتثبيت الحزم وتحديثها ونشرها. عند تنفيذ npm install lodash، يقوم npm بتنزيل حزمة lodash من المستودع إلى مجلد node_modules وتسجيلها في ملف package.json.

ما الفرق بين dependencies و devDependencies؟

dependencies هي الحزم التي يحتاجها تطبيقك فعليًا أثناء التشغيل في بيئة الإنتاج، مثل express أو react. أما devDependencies فهي حزم لا تحتاجها إلا أثناء التطوير أو البناء، كأدوات الاختبار وأدوات التجميع (bundlers) وأدوات فحص الكود (linters). لتثبيتها استخدم npm install --save-dev <pkg> أو الاختصار -D. وفي بيئة الإنتاج يمكنك تجاهلها بتمرير npm install --omit=dev.

هل يجب رفع مجلد node_modules إلى git؟

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

ما الفرق بين التثبيت المحلي والتثبيت العام في npm؟

التثبيت المحلي (npm install <pkg>) يضع الحزمة داخل مجلد node_modules الخاص بمشروعك ويسجّلها في package.json. أما التثبيت العام (npm install -g <pkg>) فيثبّتها على مستوى النظام بأكمله، وعادةً ما يُستخدم لأدوات سطر الأوامر التي تريد استخدامها في أي مكان. يُفضَّل التثبيت المحلي لتبعيات المشروع حتى تبقى الإصدارات مثبّتة لكل مشروع على حدة.

تعلّم البرمجة مع Coddy

ابدأ الآن