MS_NuGetDependencyBloat - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki
-
何か NuGet パッケージをインストールすると、異常な程多くの、
依存関係が package.config と *.csproj or *.vbproj ファイルに追加されるケースがある。 -
Visual Studio 2017 から Package Reference が利用可能になったが、
一部問題もあり、package.config を使用し続けているケースもある。
補足(なぜ「異常な程多く」なるのか): 原因は
packages.configが推移的依存を「平坦に、すべて」列挙するためである。【packages.config】 自分が入れたもの … Foo 1.0 Foo が必要とするもの … A 1.0, B 2.0 A が必要とするもの … C 1.0, D 3.0 …すべてが packages.config と .csproj に並ぶ 【PackageReference】 <PackageReference Include="Foo" Version="1.0" /> …これ 1 行だけ。残りは復元時に自動解決されるつまり、原文の問題は
**「依存が多い」のではなく「多い依存が全部見えてしまう」**ことにある。
packages.configPackageReference 推移的依存の記載 すべて列挙される 書かれない(暗黙に解決) 参照設定( .csproj)1 件ずつ <Reference>が並ぶ<PackageReference>のみ版の衝突 bindingRedirectで吸収復元時に統一(最も新しい版) 不要な依存の削除 手で消しても復活する そもそも書かれない 根本的な解決は PackageReference への移行である
(NuGet を使用したパッケージ管理 の
「Package Reference」節を参照)。
NuGet パッケージを作成する場合。
-
コチラに書いたように、
nuspec ファイルへの依存関係設定をミスっているケースも多い。 -
このため、nuspec ファイルの依存関係設定を適切に行う必要がある。
補足(典型的なミス): パッケージを作る側の設定ミスとしては、
次の 2 つが多い。①
dependenciesをgroupで切っていない<!-- 悪い:どのターゲットでもすべての依存が付く --> <dependencies> <dependency id="System.Text.Json" version="8.0.0" /> <dependency id="Newtonsoft.Json" version="13.0.3" /> </dependencies> <!-- 良い:ターゲットごとに必要なものだけ --> <dependencies> <group targetFramework="net48"> <dependency id="Newtonsoft.Json" version="13.0.3" /> </group> <group targetFramework="netstandard2.0"> <dependency id="System.Text.Json" version="8.0.0" /> </group> </dependencies>
groupを切らないと、
.NET Framework 側にも .NET Core 用の依存が流れ込む。
これが原文の言う「異常な程多く」の一因になる
(NuGetパッケージの開発と公開 の
targetFrameworkの節を参照)。② 開発時にだけ必要なものを依存に含めている
<!-- 利用側に伝播させない(分析ツール、ソース ジェネレーター等) --> <PackageReference Include="StyleCop.Analyzers" Version="1.2.0"> <PrivateAssets>all</PrivateAssets> </PackageReference>
PrivateAssets="all"を付け忘れると、
自分のビルドにしか要らないものが、利用者にまで伝播する。
dotnet packで作る場合、.csprojのPackageReferenceが
そのままnuspecのdependenciesになるため、
PrivateAssetsの指定が実質的なnuspec設定にあたる。
NuGet パッケージを利用する場合。
-
ウワモノのプロジェクトから直接、NuGet するのではなく、
- NuGet パッケージを集約するプロジェクトを作成し、
- そのプロジェクト出力を管理しておくと良いかも知れない。
-
...と言うのも、
- 自分が開発した「ライブラリ+テンプレート」のライブラリを NuGet 登録して、
- リリース時に「NuGet+テンプレート」とテンプレートの NuGet 参照を変更するのだけど、
- その際、不要な依存関係が大量に追加されるので、開発時のプロジェクト出力と比較して、
- リリースの度に不要な依存関係をテンプレートの NuGet 参照から削除する手順が必要に
なっているため。
補足(この回避策の評価): 「集約プロジェクトを 1 つ挟む」という
案は、packages.config方式における現実的な緩和策である。【直接参照】 テンプレート.csproj ──> Foo(+推移的依存が全部書かれる) 【集約プロジェクトを挟む】 テンプレート.csproj ──> 共通参照.csproj ──> Foo(依存はここに閉じる)ただし、これは症状への対処であり、
PackageReference に移行すれば構造的に不要になる。
現在の同種の要求には、次の標準機能で応えるのが定石である。
やりたいこと 現在の手段 版を 1 箇所で管理したい 中央パッケージ管理( Directory.Packages.props)全プロジェクト共通の参照を入れたい Directory.Build.props依存の集合をまとめて配りたい メタパッケージ(中身が無く依存だけを持つパッケージ) <!-- Directory.Packages.props:版はここだけで決める --> <Project> <PropertyGroup> <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> </PropertyGroup> <ItemGroup> <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> </ItemGroup> </Project><!-- Directory.Build.props:全プロジェクトに共通で入れる --> <Project> <ItemGroup> <PackageReference Include="MyCompany.Common" /> </ItemGroup> </Project>原文の「リリースの度に不要な依存関係を削除する手順」は、
移行すれば手順ごと消える種類の作業である。
補足(それでも依存が多いと感じる場合): PackageReference に
移行しても、実際にダウンロードされる依存の数が減るわけではない。
依存そのものを減らしたい場合は、次を確認する。# 依存ツリーを可視化する(推移的依存も含めて表示) dotnet list package --include-transitive # 使われていない参照を検出する dotnet tool install -g dotnet-outdated-tool
よくある原因 対処 メタパッケージを丸ごと参照 必要な個別パッケージだけにする 古い System.*個別パッケージnetstandard2.0以降では不要なものが多い分析ツール/ジェネレーター PrivateAssets="all"を付ける実質使っていない参照 削除する なお、依存の数そのものは、必ずしも問題ではない。
.NET Coreのデプロイ の
トリミングを使えば、実際に使われない部分は出力から除去される。
- パッケージ参照 (PackageReference)
https://learn.microsoft.com/ja-jp/nuget/consume-packages/package-references-in-project-files - 依存関係の解決
https://learn.microsoft.com/ja-jp/nuget/concepts/dependency-resolution - .nuspec ファイル リファレンス(dependencies)
https://learn.microsoft.com/ja-jp/nuget/reference/nuspec#dependencies-element - 中央パッケージ管理(Central Package Management)
https://learn.microsoft.com/ja-jp/nuget/consume-packages/central-package-management
Tags: 移行, .NET開発, デプロイ, NuGet