وابستگیها و lockfile؛ نصب قابل تکرار و بررسی ریسک بستهها
در این درس ۶ بخش
دو دانشجو یک پروژه را دریافت میکنند و هر دو npm install میزنند، اما چند هفته بعد نسخههای متفاوتی از وابستگیها میگیرند. برای توضیح این اتفاق باید فرق «محدودهٔ نسخهٔ مجاز» و «نسخهٔ دقیق انتخابشده» را بفهمیم. این درس مهارت کار با پروژهٔ دیگران را میسازد؛ پروژهٔ پایانی دوره به بستهٔ بیرونی نیاز ندارد، ولی بسیاری از برنامههای واقعی دارند. اضافهکردن وابستگی باید یک مسئلهٔ مشخص را حل کند.
کدام بسته برای اجرا لازم است؟
dependencies معمولاً بستههایی است که برنامه برای اجرای خود نیاز دارد؛ devDependencies برای کار توسعه، مانند ابزار آزمون یا تبدیل کد استفاده میشود. این دستهبندی بهتنهایی ریسک اجرا را تعیین نمیکند: ابزار توسعه نیز هنگام نصب یا ساخت میتواند کد اجرا کند. اگر برنامه در سرور به یک بسته import دارد، حذف آن از نصب تولیدی ممکن است برنامه را از کار بیندازد. در مقابل، ابزار لازم برای ساخت خروجی ممکن است در مرحلهٔ build لازم باشد، حتی اگر در اجرای خروجی نهایی استفاده نشود.
برای شناخت شکل فایل، قطعهٔ زیر یک نمونهٔ فرضی است و دستور نصب نیست. نامهای example-runtime و example-checker صرفاً جاینگهدار آموزشیاند؛ آنها را نصب نکنید. در یک پروژهٔ واقعی نام و نسخه را از مستندات همان ابزار انتخاب میکنید، نه از روی شباهت نام یا تعداد ستارهها.
{
"dependencies": { "example-runtime": "^2.3.0" },
"devDependencies": { "example-checker": "~4.1.0" }
}در نسخههای پایدار بزرگتر از صفر، ^2.3.0 معمولاً نسخههای از 2.3.0 تا پیش از 3.0.0 را مجاز میکند؛ ~4.1.0 تا پیش از 4.2.0 را میپذیرد. این قرارداد، وعدهٔ سازگاری نویسنده را دنبال میکند و تضمین نبودن خطا نیست. قواعد نسخههای 0.x محدودیتهای متفاوتی دارند، پس تعمیم همین مثال به همهٔ بستهها درست نیست. عدد دقیق مانند 2.3.0 نیز به معنی امنبودن آن نسخه نیست.
نقش package-lock.json
package.json نیازها و محدودهها را ثبت میکند. package-lock.json انتخاب دقیق درخت وابستگی را ثبت میکند تا نصب بعدی بتواند همان انتخاب را بازسازی کند. در یک برنامهٔ npm، lockfile را معمولاً همراه کد نگه میداریم؛ آن را فقط برای خاموشکردن خطا پاک نمیکنیم. node_modules خروجی نصب است و معمولاً وارد Git نمیشود. lockfile هم جای آزمون روی سیستمعامل هدف را نمیگیرد؛ بستهٔ دارای بخش بومی ممکن است روی ویندوز و لینوکس رفتار یا پیشنیاز متفاوت داشته باشد.
در پوشهٔ workspace-lab درس قبل، هیچ وابستگی بیرونی نداریم. این فرصت خوبی برای دیدن چرخهٔ فایلها بدون دریافت کد شخص ثالث است. فرمان نخست lockfile را ایجاد یا هماهنگ میکند و فرمان دوم نصب ثبتشده را بازسازی میکند. گزینههای این تمرین اجرای lifecycle script و درخواست audit و پیام تأمین مالی را کنار میگذارند؛ تنظیمات سراسری شما تغییر نمیکند.
npm.cmd install --package-lock-only --ignore-scripts --no-audit --no-fund
npm.cmd ci --ignore-scripts --no-audit --no-fund
npm.cmd testبا package.json بدون وابستگی، تعداد بستههای تازه معمولاً صفر است و آزمونهای درس قبل باید همان نتیجه را بدهند. npm ci به lockfile موجود و هماهنگ نیاز دارد؛ اگر نیازهای package.json با آن نخواند، بهجای بازنویسی lockfile شکست میخورد. همچنین node_modules موجود را بازسازی میکند، پس محل نگهداری فایل دستنویس شما نیست. این فرمان برای اضافهکردن تکبسته طراحی نشده است؛ تغییر نیازها را با فرایند install و بازبینی تغییر lockfile انجام میدهیم.
گزارش امنیت را چگونه بخوانیم؟
در پروژهٔ واقعی دارای وابستگی، npm audit گزارش آسیبپذیریهای شناختهشده را با اطلاعات رجیستری مقایسه میکند. خروجی صفر آسیبپذیری، نبود بدافزار یا درستی منطق برنامه را ثابت نمیکند. فرمان میتواند اطلاعات درخت وابستگی را به رجیستری پیکربندیشده ارسال کند؛ در پروژهٔ سازمانی، سیاست همان محیط را دنبال کنید. برای تمرین آفلاین این درس، اجرای audit لازم نیست.
با دیدن هشدار فوراً npm audit fix --force نزنید. ابتدا بستهٔ مستقیم یا غیرمستقیم، نسخهٔ اصلاحشده، شرایط بهرهبرداری و احتمال تغییر ناسازگار را بررسی کنید، سپس تغییر را در شاخهٔ جدا و با آزمون اعمال کنید. ignore-scripts هم راهحل همیشگی نیست: بعضی بستههای معتبر برای کارکردشان به اسکریپت نصب نیاز دارند. استفادهٔ آگاهانه از آن برای بررسی اولیه، با وعدهٔ اینکه هر بسته پس از آن سالم اجرا میشود فرق دارد.
خطاهای نصب به زبان علت
برای ERESOLVE، ابتدا ناسازگاری محدودهها و peer dependency را بخوانید؛ گزینههای force یا legacy-peer-deps را راهحل عمومی ندانید. برای خطای شبکه یا گواهی، زمان سیستم، رجیستری تنظیمشده و پراکسی مجاز محیط را بررسی کنید؛ strict-ssl را خاموش نکنید. خطای node-gyp نشانهٔ نیاز احتمالی همان بسته به ساخت بومی است؛ پروژهٔ بدون وابستگی این دوره به Python یا Visual Studio Build Tools نیاز ندارد. نصب ابزارهای سنگین باید پس از خواندن پیشنیاز رسمی همان بسته باشد.
تمرین، پاسخ و معیار تحویل
در یک کپی آزمایشی از workspace-lab، lockfile را بیرون پوشه نگه دارید و npm.cmd ci --ignore-scripts --no-audit --no-fund اجرا کنید. انتظار، شکست به دلیل نبود lockfile است؛ پیام دقیق ممکن است با نسخهٔ npm فرق کند. سپس lockfile را برگردانید و دوباره اجرا کنید. پاسخ تشریحی: ci اجازهٔ انتخاب آزاد اولیه را نمیدهد، چون وظیفهاش بازسازی نصب ثبتشده است. معیار تحویل، توضیح تفاوت سه فایل package.json، package-lock.json و node_modules و ثبت نسخهٔ Node و npm کنار نتیجهٔ آزمون است. روی پروژهٔ واقعی برای این تمرین چیزی را حذف نکنید.
منابع رسمی
npm، نصب وابستگیها: https://docs.npmjs.com/cli/v11/commands/npm-install/
npm، نصب با ci: https://docs.npmjs.com/cli/v11/commands/npm-ci/
npm، نسخهگذاری معنایی: https://docs.npmjs.com/about-semantic-versioning/
npm، lockfile: https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json/
npm، audit: https://docs.npmjs.com/cli/v11/commands/npm-audit/
تألیف و مثالهای اختصاصی: تحریریه درسآوند. چرخهٔ بدون وابستگی این درس با npm همراه Node.js 24.22.1 روی لینوکس آزموده شده؛ نصب بستههای فرضی یا ابزار بومی انجام نشده است.
متن درسهای عمومی را بدون ورود بخوانید.