Skip to content

Unable to reference library made using Microsoft.NET.Sdk.WebAssembly SDK. #132877

Description

@rotanov

Description

Microsoft.NET.Sdk.WebAssembly library project causes conflicting static web assets when referenced by another WebAssembly (Library or Executable) project.

Summary

I am trying to build a browser-based WebAssembly application consisting of two C# projects:

  • App — executable WebAssembly application
  • Lib — C# library referenced by App

Neither project uses Blazor, Razor, or any ASP.NET framework. The application is a plain .NET WebAssembly application running directly in the browser.

The library also needs to provide JavaScript/TypeScript files. JS files being in wwwroot are served as part of combined static web assets with specified StaticWebAssetBasePath. And TypeScript files ready to be consumed by App's TypeScript files.

To make JS assets from the library available to the application, I initially added:

<Sdk Name="Microsoft.NET.Sdk.StaticWebAssets" />

to the library project and it worked.

However, the library's TypeScript files depend on the dotnet.d.ts generated/provided by the .NET WebAssembly runtime, so I also need a reliable way for the library to obtain the appropriate dotnet.d.ts.

I read up on the topic and found:

  1. It's been implemented here (but unavailable in .NET10) Copydotnet.d.ts to wwwroot on build/publish. #120097
  2. The workaround here dotnet.d.ts should be include in the wasmbrowser template #77174

I tried both workaround (below) and attempt to use the flag WasmEmitTypeScriptDefinitions with .NET11 RC. Neither worked in Lib project.

<Target Name="CopyDotnetDTs" AfterTargets="ProcessFrameworkReferences">
  <ItemGroup>
    <_DotnetDTsPath Include="%(RuntimePack.PackageDirectory)\runtimes\browser-wasm\native\dotnet.d.ts"
                    Condition="'%(RuntimePack.Identity)' == 'Microsoft.NETCore.App.Runtime.Mono.browser-wasm'" />
  </ItemGroup>
  <Copy SourceFiles="@(_DotnetDTsPath)"
        DestinationFolder="$(MSBuildProjectDirectory)\wwwroot" />
</Target>

Then I changed my Lib project SDK from <Project Sdk="Microsoft.NET.Sdk"> to <Project Sdk="Microsoft.NET.Sdk.WebAssembly"> and explicitly specified <OutputType>Library</OutputType>

With this setup both the flag and the workaround worked as expected.

However, this introduces a different problem.

When the Lib project is referenced by the App project, the build fails with an error similar to:

Conflicting assets with the same target path '_framework/Lib#[.{fingerprint}]!.pdb'.

For assets
'Identity: C:\...\Lemon\bin\Lemon.Web\Debug\net10.0-browser\wwwroot\_framework\Lemon.65s2n5qtql.pdb,
SourceType: Project,
SourceId: Lemon,
ContentRoot: C:\...\Lemon\bin\Lemon.Web\Debug\net10.0-browser\wwwroot\,
BasePath: /,
RelativePath: _framework/Lemon#[.{fingerprint}]!.pdb,
AssetKind: Build,
AssetMode: All,
AssetRole: Primary,
RelatedAsset: ,
AssetTraitName: WasmResource,
AssetTraitValue: symbol,
Fingerprint: 65s2n5qtql,
...

and

'Identity: C:\...\Lime\bin\Lime.Web\Debug\net10.0-browser\wwwroot\_framework\Lemon.65s2n5qtql.pdb,
SourceType: Computed,
SourceId: Lime,
ContentRoot: C:\...\Lime\bin\Lime.Web\Debug\net10.0-browser\wwwroot\,
BasePath: /,
RelativePath: _framework/Lemon#[.{fingerprint}]!.pdb,
AssetKind: Build,
AssetMode: All,
AssetRole: Primary,
...
'
from different projects.

The _framework/* files emitted by the WebAssembly SDK therefore become static web assets of the library. When the library is consumed by another WebAssembly application, those assets overlap with the assets produced by the consuming application.

Questions

  1. Is using Microsoft.NET.Sdk.WebAssembly with:

    <OutputType>Library</OutputType>

    a supported way of creating a reusable WebAssembly library?

  2. If so, is it expected that the SDK's generated _framework/* output becomes part of the library's Static Web Assets manifest?

  3. More generally, what is the intended SDK/project setup for a plain .NET WebAssembly library that:

    • does not use Blazor/Razor,
    • contains C# code,
    • needs to ship JavaScript/TypeScript files through wwwroot,
    • needs to JSImport/JSExport from/to it's own js.
    • and can be referenced by another plain .NET WebAssembly application?

?

Reproduction Steps

Create projects like this:

App/
App.csproj

Lib/
Lib.csproj

App.csproj:

<Project Sdk="Microsoft.NET.Sdk.WebAssembly">

  <PropertyGroup>
    <TargetFramework>net10.0-browser</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Lib\Lib.csproj" />
  </ItemGroup>

</Project>

Lib.csproj:

<Project Sdk="Microsoft.NET.Sdk.WebAssembly">

  <PropertyGroup>
    <TargetFramework>net10.0-browser</TargetFramework>
    <OutputType>Library</OutputType>
    <WasmEmitTypeScriptDefinitions>true</WasmEmitTypeScriptDefinitions>
  </PropertyGroup>

</Project>

and try to build the App project.

Expected behavior

A WebAssembly library should be able to reference another WebAssembly library in the same way as an ordinary .NET library.

To work without the library's generated WebAssembly runtime/application assets being treated as independent static web assets that conflict with the consuming application's own _framework assets.

The library needs to be able to provide its own intentional web assets (for example .js), while its intermediate/generated WebAssembly files should not cause duplicate static-web-asset entries in the consuming application.

Actual behavior

Build error.

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-Build-monountriagedNew issue has not been triaged by the area owner

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions