From 31070bb9374a8506ca24467525f9091e2c1d6a0b Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Sun, 8 Mar 2026 12:33:33 -0500 Subject: [PATCH] Use Framework SourceType for WASM pass-through assets in multi-client solutions When multiple Blazor WebAssembly client projects reference the same runtime pack, pass-through files (JS, maps, ICU data, native wasm) share a NuGet cache path. This causes duplicate Identity keys in the static web assets pipeline, crashing DiscoverPrecompressedAssets with an ArgumentException. Instead of copying pass-throughs to the intermediate output path (which risks staleness on incremental builds when the runtime pack changes), materialize them to a per-project obj/fx/{PackageId}/ directory using the Framework SourceType convention from the SWA SDK. This gives each project a unique Identity while properly modeling the relationship: these are framework assets adopted by each consuming project. - Pass-through files: copied to obj/fx/{PackageId}/, registered with SourceType=Framework - WebCil-converted files: remain in obj/webcil/, registered with SourceType=Computed - Satellite assemblies: placed in culture subdirectories in both cases - Both groups get per-item ContentRoot for correct Identity resolution Requires SDK support for SourceType=Framework (dotnet/sdk#53135). Fixes duplicate-key crash introduced by #124125. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 30970d18aa4eb9..53dd2472a28da8 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -353,6 +353,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_WasmBuildWebcilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'webcil')) <_WasmBuildTmpWebcilPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'tmp-webcil')) + <_WasmFrameworkAssetPath>$([MSBuild]::NormalizeDirectory($(IntermediateOutputPath), 'fx', '$(PackageId)')) @@ -360,9 +361,42 @@ Copyright (c) .NET Foundation. All rights reserved. + + <_WasmFrameworkCandidates Include="@(_WebcilAssetsCandidates)" + Condition="!$([System.String]::new('%(Identity)').StartsWith($(_WasmBuildWebcilPath)))" /> + <_WebcilAssetsCandidates Remove="@(_WasmFrameworkCandidates)" /> + + + + + <_WasmCultureFrameworkAssets Include="@(_WasmFrameworkCandidates)" + Condition="'%(_WasmFrameworkCandidates.AssetTraitName)' == 'Culture'" /> + <_WasmFrameworkCandidates Remove="@(_WasmCultureFrameworkAssets)" /> + + + + + + + + + + <_WasmMaterializedFrameworkAssets Include="@(_WasmFrameworkCandidates->'$(_WasmFrameworkAssetPath)%(Filename)%(Extension)')" /> + <_WasmMaterializedFrameworkAssets Include="@(_WasmCultureFrameworkAssets->'$(_WasmFrameworkAssetPath)%(AssetTraitValue)/%(Filename)%(Extension)')" /> <_WebcilAssetsCandidates Update="@(_WebcilAssetsCandidates)" ContentRoot="%(RootDir)%(Directory)" /> + <_WasmMaterializedFrameworkAssets Update="@(_WasmMaterializedFrameworkAssets)" ContentRoot="%(RootDir)%(Directory)" /> <_WasmFingerprintPatterns Include="WasmFiles" Pattern="*.wasm" Expression="#[.{fingerprint}]!" /> <_WasmFingerprintPatterns Include="DllFiles" Pattern="*.dll" Expression="#[.{fingerprint}]!" /> <_WasmFingerprintPatterns Include="DatFiles" Pattern="*.dat" Expression="#[.{fingerprint}]!" /> @@ -370,6 +404,9 @@ Copyright (c) .NET Foundation. All rights reserved. <_WasmFingerprintPatterns Include="Symbols" Pattern="*.js.symbols" Expression="#[.{fingerprint}]!" /> + + + + +