در داتنت 10، مایکروسافت ویژگی جدیدی به نام “package pruning” را معرفی کردهاست که به طور خودکار ارجاعهای غیرضروری به بستههای ارائهشده توسط فریمورک را از فایلهای پروژه و گراف وابستگی (.deps.json) حذف میکند. این ویژگی با هدف بهبود عملکرد بیلد، کاهش اندازه فایلها و تمیزتر کردن خروجیها طراحی شده است. با این حال، اگر پروژهای ارجاع مستقیم به بستههایی داشته باشد که بخشی از runtime .NET هستند (مانند System.Text.Json)، این ویژگی میتواند مشکلات احتمالی ایجاد کند. در ادامه، بر اساس مستندات رسمی مایکروسافت و توضیحات مرتبط، به بررسی این مشکلات میپردازیم.
مقدمهای بر ویژگی Package Pruning و هشدار NU1510
ویژگی pruning به طور پیشفرض برای هدفهایی مانند net8.0، net10.0 و .NET Standard 2.0 و بالاتر فعال است. فرآیند کار به این صورت است:
- SDK بستههایی را که توسط runtime .NET ارائه میشوند شناسایی میکند.
- اگر پروژه ارجاع مستقیم به این بستهها داشته باشد، آنها را حذف (prune) میکند.
- در نتیجه، هشدار NU1510 صادر میشود تا توسعهدهنده را از ارجاع غیرضروری آگاه کند.
این ویژگی مزایایی مانند کاهش زمان بیلد، صرفهجویی در فضای دیسک و کاهش false positive در اسکن وابستگیها دارد. اما وجود ارجاع مستقیم به بستههای SDK میتواند منجر به چالشهایی در فرآیند بیلد شود.
مشکلات احتمالی در بیلد پروژهها
اگرچه pruning به طور کلی بیلد را بهبود میبخشد، اما ارجاع مستقیم به بستههای SDK میتواند مشکلات زیر را ایجاد کند:
صدور هشدار NU1510 و تأثیر بر فرآیند بیلد:
این هشدار زمانی trigger میشود که ارجاع مستقیم با کتابخانههای ارائهشده توسط فریمورک همپوشانی داشته باشد و لازم نباشد. قبلاً چنین ارجاعهایی نادیده گرفته میشدند، اما حالا حذف میشوند و هشدار صادر میشود.
- مشکل: این هشدار میتواند بیلد را “noisier” کند، یعنی خروجی کنسول پر از هشدار شود که توسعهدهندگان را گیج کند. اگر پروژه بزرگ باشد، نادیده گرفتن این هشدارها ممکن است به مشکلات پنهان منجر شود، مانند عدم تشخیص ارجاعهای واقعاً لازم.
ناسازگاری منبع (Source-Incompatibility):
این تغییر به عنوان یک breaking change طبقهبندی شده است، به این معنا که پروژههای موجود ممکن است نیاز به بروزرسانی داشته باشند. اگر پروژه بر اساس ارجاع مستقیم به بستههای SDK نوشته شده باشد، حذف خودکار آنها میتواند رفتار غیرمنتظره ایجاد کند.
- مشکل: در بیلدهای اتوماتیک (مانند CI/CD)، این ناسازگاری میتواند باعث شکست بیلد نشود، اما نیاز به تغییرات دستی در فایل پروژه (مانند .csproj) ایجاد کند، که زمان و تلاش اضافی میطلبد.
مسائل در پروژههای Multi-Targeting:
در پروژههایی که چندین فریمورک را هدف قرار میدهند (مثلاً net6.0 و net10.0)، pruning ممکن است ارجاع را برای همه هدفها حذف کند، حتی اگر برای برخی لازم باشد.
- مشکل: این میتواند منجر به خطاهای زمان اجرا یا بیلد شود اگر بسته در فریمورکهای قدیمیتر موجود نباشد. برای مثال، اگر پروژه به System.Text.Json ارجاع مستقیم داشته باشد، در net10.0 prune میشود، اما در net6.0 ممکن است لازم باشد، که باعث confusion در مدیریت وابستگیها میشود.
تأثیر بر ابزارهای وابستگی و اسکن:
pruning ارجاعهای غیرضروری را حذف میکند، اما اگر توسعهدهنده به اشتباه فکر کند که ارجاع لازم است، ممکن است false positive در ابزارهایی مانند NuGet Audit کاهش یابد، اما در عوض، مشکلات جدیدی مانند عدم تشخیص وابستگیهای واقعی ایجاد شود.
- مشکل: در بیلدهای بزرگ، این میتواند زمان تحلیل را افزایش دهد یا منجر به دانلودهای غیرضروری اولیه شود تا pruning اعمال گردد.
ریسکهای عملکردی و نگهداری:
اگرچه بیلد سریعتر میشود، اما در صورت عدم مدیریت درست، پروژه ممکن است به نسخههای قدیمیتر بستهها وابسته شود که با runtime تداخل دارد.
- مشکل: این میتواند باعث تأخیر در بیلد اولیه (به دلیل شناسایی و pruning) یا مشکلات در محیطهای توسعه مشترک شود، جایی که توسعهدهندگان مختلف نسخههای متفاوتی از SDK دارند.
مثالهای عملی
فرض کنید پروژهای هدف net10.0 دارد و ارجاع مستقیم به System.Text.Json دارد. در بیلد، SDK این ارجاع را prune میکند و هشدار NU1510 صادر میشود: “Direct package reference to System.Text.Json is pruned because it’s provided by the framework.”
- مشکل احتمالی: اگر پروژه multi-target باشد، بیلد برای net10.0 موفق است، اما برای هدفهای قدیمیتر ممکن است شکست بخورد مگر اینکه ارجاع شرطی اضافه شود، مانند:
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net8.0'))">
<PackageReference Include="System.Text.Json" Version="8.0.0" />
</ItemGroup>
راهحلها و توصیهها
برای جلوگیری از مشکلات:
- حذف ارجاع غیرضروری: برای پروژههای تکهدف، ارجاع مستقیم را حذف کنید.
- استفاده از شرطیسازی: در پروژههای multi-target، از شرطها برای افزودن ارجاع تنها در فریمورکهای لازم استفاده کنید.
- غیرفعال کردن pruning: اگر لازم باشد، ویژگی را با تنظیم
RestoreEnablePackagePruning به false در فایل پروژه یا Directory.Build.props غیرفعال کنید. - بروزرسانی پروژه: پروژهها را برای سازگاری با .NET 10 بررسی کنید تا از ناسازگاریهای منبع جلوگیری شود.