Mojtaba Pourkhanlar
About meProjectsBlog

  • 👤About me
  • 🧰Projects
  • ✍️Blog

node_modules

وقتی یک پروژه React/Next می‌سازیم، اولین چیزی که بعد از نصب وابستگی‌ها ظاهر می‌شود یک پوشه بزرگ به نام node_modules است.
پوشه‌ای که معمولاً هیچ‌وقت واردش نمی‌شویم، ولی همیشه وجود دارد و بخش مهمی از ساختار پروژه ماست.

پوشه‌ای است که تمام پکیج‌ها و وابستگی‌های پروژه شما بعد از اجرای npm install یا yarn install داخل آن نصب می‌شوند.

ارتباط node_modules با package.json

فایل package.json لیست وابستگی‌های پروژه را مشخص می‌کند. و node_modules محل واقعی نصب و نگهداری آن وابستگی‌هاست.

"dependencies": {
  "react": "^18.2.0",
  "react-dom": "^18.2.0"
}

وقتی npm install می‌کنید:

  • خب npm نسخه مناسب را پیدا می‌کند

  • آن را دانلود می‌کند

  • داخل node_modules قرار می‌دهد

پس:

  • package.json = لیست سفارش\
  • node_modules = انبار واقعی پکیج‌ها

چرا node_modules حجیم است؟

به دلیل Dependency Tree (درخت وابستگی).
هر پکیج خودش به چند پکیج دیگر وابسته است و آن‌ها هم وابستگی دارند.
در نهایت مجموعه بزرگی از پکیج‌ها نصب می‌شود.

ساختار داخلی node_modules

اگر داخل آن بروید، چیزی شبیه این می‌بینید:


node_modules/
  react/
  react-dom/
  scheduler/
  loose-envify/
  ...

هر پوشه یک پکیج کامل است که شامل:

  • فایل‌های js

  • فایل package.json خودش

  • فایل‌های build شده

  • گاهی type definitions

  • گاهی source map

یعنی هر dependency خودش یک پروژه جداگانه است.

چرا node_modules داخل گیت قرار نمی‌گیرد؟

در فایل .gitignore معمولاً می‌بینیم:

دلیلش:

  1. حجم بسیار زیاد

    • صدها مگابایت فایل که قابل بازتولید هستند.
  2. قابل بازسازی بودن

هر کسی با داشتن: package.json , package-lock.json

می‌تواند با یک npm install دقیقاً همان نسخه‌ها را دوباره نصب کند.

پس نگه‌داشتن آن داخل گیت بی‌معنی است.

چرا نباید داخل node_modules تغییر ایجاد کنیم؟

چون:

  • با هر npm install دوباره overwrite می‌شود
  • قابل commit نیست
  • تغییرات شما از بین می‌رود

اگر نیاز به تغییر یک پکیج دارید باید:

  • باید fork کنید
  • یا از patch-package استفاده کنید
  • یا نسخه جدید منتشر کنید

روش استفاده از patch-package

  • ابتدا npm install patch-package --save-dev را بزنید
  • حالا تغییراتی که مد نظرتون هست رو درون node_modules پیاده سازی کنید
  • این کانفیگ را درون package.json بخش script قرار دهید
"scripts": {
  "postinstall": "patch-package"
}
  • و در آخر این کامند رو بزنید : npx patch-package axios (به جای axios نام پکیج مدنظرتون رو بنویسید)
  • بعد از اتمام کار یک دایرکتوری با نام patches ساخته میشه که بعد از پوش کردن روی گیت، از این به بعد npm i بزنید تغییراتی که در پکیج مدنظرتون دادید رو از این دایرکتوری patches میخونه

آیا React بدون node_modules کار می‌کند؟

خیر

حتی اگر شما فقط چند فایل js نوشته باشید، پروژه React برای build شدن به ابزارهایی مثل:

  • bundler
  • babel
  • react
  • react-dom

نیاز دارد.

همه این‌ها از node_modules خوانده می‌شوند.

آیا می‌توان node_modules را حذف کرد؟

بله. با حذف آن و اجرای مجدد npm install دوباره ساخته می‌شود.

rm -rf node_modules
npm install

نقش package-lock.json

فایل package-lock.json نسخه دقیق تمام وابستگی‌ها را قفل می‌کند.

چرا مهم است؟

چون اگر فقط بنویسید:

"react": "^18.2.0"

علامت ^ یعنی:

هر نسخه‌ای که با 18 سازگار باشد نصب کن.

ولی ممکن است روی سیستم شما 18.2.0 نصب شود و روی سیستم هم‌تیمی‌تان 18.3.1

برای جلوگیری از این اختلاف، lock file نسخه دقیق را ثبت می‌کند.

مفهوم Hoisting در node_modules

یکی از مفاهیم پیشرفته‌تر، Hoisting است.

اگر دو پکیج مختلف به یک dependency مشترک نیاز داشته باشند، npm سعی می‌کند آن را در سطح بالاتر نصب کند تا تکراری نشود.

node_modules/
  shared-lib/
  packageA/
  packageB/

به جای اینکه shared-lib دوبار نصب شود، فقط یک بار در ریشه نصب می‌شود.

این باعث کاهش حجم می‌شود.

جمع‌بندی

پوشه node_modules:

  • قلب وابستگی‌های پروژه است
  • تمام پکیج‌های موردنیاز را نگه می‌دارد
  • به صورت خودکار ساخته می‌شود
  • نباید داخل گیت باشد
  • وابسته به package.json و lock file است
  • نتیجه یک درخت پیچیده از dependency هاست