dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.6k stars 10.06k forks source link

Using a Razor Component Library with TypeScript fails to copy assets #57662

Open FreyLuis opened 3 months ago

FreyLuis commented 3 months ago

Is there an existing issue for this?

Describe the bug

I have a Razor Component Library that includes some TypeScript files. The component library is referenced in a Blazor WebAssembly web app. My problem is that the generated files aren't included as static web assets when publishing. The problem has been a topic of other issues over the years (#12646, #13122, dotnet/sdk/issues/19474), but I currently can't get it to work.

I made a small solution that recreates the issue: https://github.com/FreyLuis/TypeScript.MsBuild.TestApp When running the following commands, the compiled typescript files are not included in the published output:

dotnet clean
dotnet publish .\TypeScript.MsBuild.TestApp\

I tried the solution that is documented here, but I'm getting an exception when I'm trying to publish it.

C:\Program Files\dotnet\sdk\8.0.400\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(507,5): error : Two assets found targeting the same path with incompatible asset kinds

I pushed the broken fix to the fix-from-documentation branch. I also deleted the tsconfig to get closer to the documentation, even though my goal would be to use a tsconfig. I also tried using Microsoft.TypeScript.MSBuild 5.6.0-beta, which didn't help.

I would appreciate any help with this, thank you in advance.

Expected Behavior

It should work

Steps To Reproduce

Exceptions (if any)

C:\Program Files\dotnet\sdk\8.0.400\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(507,5): error : Two assets found targeting the same path with incompatible asset kinds:  [C:\Users\luis\source\demos\TypeScript.MsBuild.TestApp\RazorClassLibrary\RazorClassLibrary.csproj]
C:\Program Files\dotnet\sdk\8.0.400\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(507,5): error : 'C:\Users\luis\source\demos\TypeScript.MsBuild.TestApp\RazorClassLibrary\wwwroot\Counter.js' with kind 'All' [C:\Users\luis\source\demos\TypeScript.MsBuild.TestApp\RazorClassLibrary\RazorClassLibrary.csproj]
C:\Program Files\dotnet\sdk\8.0.400\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(507,5): error : 'C:\Users\luis\source\demos\TypeScript.MsBuild.TestApp\RazorClassLibrary\wwwroot\Counter.js' with kind 'All' [C:\Users\luis\source\demos\TypeScript.MsBuild.TestApp\RazorClassLibrary\RazorClassLibrary.csproj]
C:\Program Files\dotnet\sdk\8.0.400\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(507,5): error : for path 'Counter.js' [C:\Users\luis\source\demos\TypeScript.MsBuild.TestApp\RazorClassLibrary\RazorClassLibrary.csproj]

.NET Version

8.0.400

Anything else?

.NET SDK: Version: 8.0.400 Commit: 36fe6dda56 Workload version: 8.0.400-manifests.56cd0383 MSBuild version: 17.11.3+0c8610977

Runtime Environment: OS Name: Windows OS Version: 10.0.22631 OS Platform: Windows RID: win-x64 Base Path: C:\Program Files\dotnet\sdk\8.0.400\

.NET workloads installed: Configured to use loose manifests when installing new manifests. [wasm-tools] Installation Source: VS 17.12.35209.166, VS 17.11.35222.181 Manifest Version: 8.0.8/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.current\8.0.8\WorkloadManifest.json Install Type: FileBased

[aspire] Installation Source: VS 17.12.35209.166, VS 17.11.35222.181 Manifest Version: 8.1.0/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.aspire\8.1.0\WorkloadManifest.json Install Type: FileBased

Host: Version: 9.0.0-preview.7.24405.7 Architecture: x64 Commit: static

.NET SDKs installed: 8.0.400 [C:\Program Files\dotnet\sdk] 9.0.100-preview.7.24407.12 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.App 6.0.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 9.0.0-preview.7.24406.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 9.0.0-preview.7.24405.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 6.0.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 9.0.0-preview.7.24405.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found: x86 [C:\Program Files (x86)\dotnet] registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables: Not set

global.json file: C:\Users\luis\source\global.json

Learn more: https://aka.ms/dotnet/info

Download .NET: https://aka.ms/dotnet/download

javiercn commented 3 months ago

@FreyLuis thanks for contacting us.

The issue here is that you are generating the outputs of the typescript build into a location that gets picked up as an input of the subsequent build.

  <ItemGroup>
    <Content Remove="wwwroot\*.js;wwwroot\*.js.map" />
    <None Include="wwwroot\*.js;wwwroot\*.js.map" />
  </ItemGroup>

Removing the outputs from the Content itemgroup makes the issue go away.

FreyLuis commented 3 months ago

Removing the output from content works great.

However, the tsconfig file was not used after the change. To make it work, I used this solution:

<PrepareForBuildDependsOn>
  FindConfigFiles;
  CompileTypeScript;
  CompileTypeScriptWithTSConfig;
  GetTypeScriptOutputForPublishing;
  $(PrepareForBuildDependsOn)
</PrepareForBuildDependsOn>

CompileTypeScriptWithTSConfig only runs, if FindConfigFiles can find a tsconfig.json. Otherwise CompileTypeScript will run.

Since the documentation here describes the same scenario, maybe it should be updated (including the <Content Remove=... from above)? If it is ok, I can update the docs (and become a contributor 😬).

FreyLuis commented 3 months ago

I found an issue with my solution above. When the project is checked out and has not been started/restored yet, Visual Studio throws the following error:

1>C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets(1193,7): error MSB4057: The target "FindConfigFiles" does not exist in the project.

But when running dotnet build via the CLI, it works fine. After that, Visual Studio no longer throws that error.

I have this workaround:

<Target Name="FixTypescriptCompileDependencies" BeforeTargets="BeforeBuild">
  <PropertyGroup>
    <PrepareForBuildDependsOn>
      FindConfigFiles;
      CompileTypeScript;
      CompileTypeScriptWithTSConfig;
      GetTypeScriptOutputForPublishing;
      $(PrepareForBuildDependsOn)
    </PrepareForBuildDependsOn>
  </PropertyGroup>
</Target>

But that's might be a little too hacky for the aspnetcore docs. I updated my repo to recreate the behaviour. Is there a better way of solving this?

javiercn commented 6 days ago

@FreyLuis we filed an issue about this https://github.com/microsoft/TypeScript/issues/60538, you might want to upvote that issue.

I recently did

<PrepareForBuildDependsOn>
  CompileTypeScript;
  CompileTypeScriptWithTSConfig;
  GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
</PrepareForBuildDependsOn>

And was enough for me, but I suspect that it might not be enough, so your solution might be better. I also had to remove the content like this:

<Target Name="RemoveDuplicateTypeScriptOutputs" BeforeTargets="GetTypeScriptOutputForPublishing">
  <ItemGroup>
    <Content Remove="@(GeneratedJavaScript)" />
  </ItemGroup>
</Target>