Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebuild fails when fingerprinting compiled TypeScript in VS 17.12.0 #58948

Closed
1 task done
kaleidocore opened this issue Nov 14, 2024 · 26 comments
Closed
1 task done

Rebuild fails when fingerprinting compiled TypeScript in VS 17.12.0 #58948

kaleidocore opened this issue Nov 14, 2024 · 26 comments
Assignees
Labels
area-ui-rendering Includes: MVC Views/Pages, Razor Views/Pages feature-static-web-assets ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved

Comments

@kaleidocore
Copy link

kaleidocore commented Nov 14, 2024

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

After upgrading to VS 17.12.0 / .Net9 SDK: Solution Rebuild fails during fingerprinting of static assets, if those assets are (re-)produced during build.

In particular this applies to TypeScript files that are compiled to .js files under wwwroot/ during the build process, using the standard Microsoft.TypeScript.MSBuild (5.6.2) nuget.

This worked in VS 17.11.x / .Net8 SDK.
The project is a .Net8 project.

NB: It is also unclear why fingerprinting is even applied to .Net8 projects, and how to turn it off.

Expected Behavior

Rebuild should not fail. Analysis of static assets produced during build should be scheduled so that fingerprinting succeeds.

Steps To Reproduce

Minimal repro here: https://github.com/kaleidocore/TSBuildFail

The minimal repro is based on the basic TypeScript template/example described here: https://learn.microsoft.com/en-us/visualstudio/javascript/tutorial-aspnet-with-typescript?view=vs-2022

Typically Clean+Build succeeds, but Rebuild fails.

Exceptions (if any)

System.InvalidOperationException: No file exists for the asset at either location 'wwwroot\js\app.js' or 'wwwroot\js\app.js'.
   at Microsoft.AspNetCore.StaticWebAssets.Tasks.StaticWebAsset.ComputeFingerprintAndIntegrity(String identity, String originalItemSpec)
   at Microsoft.AspNetCore.StaticWebAssets.Tasks.DefineStaticWebAssets.Execute()

.NET Version

9.0.100

Anything else?

Other static assets produced during build also fails in the same way, e.g. .scss -> .css using WebCompiler.

A temporary workaround for the issue is to force a downgrade of the .Net SDK using a global.json in the root folder:

{
	"sdk":
	{
		"version": "8.0.404",
		"rollForward": "latestPatch"
	}
}

I believe the core of this issue is actually much older, but the new Fingerprinting feature puts focus on it by failing completely, whereas it previously sort of "worked" - we have had very similar issues when publishing our projects (dotnet publish solution.sln ...) in previous versions of Visual Studio / .Net. It often appears random or timing based whether those same static files produced during build are actually included in the publish output. We've had to work around it by adding additional build steps such as Clean, Build, Publish and running it single-threaded.

I also suspect these issues are related:
#57147
#58748

@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Nov 14, 2024
@cal-tlabwest
Copy link

cal-tlabwest commented Nov 15, 2024

I also get this problem in .NET 8 Microsoft.NET.Sdk.Razor projects after installing .NET 9 SDK / VS 17.12:

5>  Using "DefineStaticWebAssets" task from assembly "C:\Program Files\dotnet\sdk\9.0.100\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\..\tasks\net472\Microsoft.NET.Sdk.StaticWebAssets.Tasks.dll".
5>  Task "DefineStaticWebAssets"
5>    Task Parameter:RelativePathPattern=wwwroot/**
5>    Task Parameter:SourceType=Discovered
5>    Task Parameter:
5>        FingerprintPatterns=
5>            Initializer
5>                    Expression=#[.{fingerprint}]!
5>                    Pattern=*.lib.module.js
5>            MvcJsModule
5>                    Pattern=*.cshtml.js
5>            ComponentsJsModule
5>                    Pattern=*.razor.js
5>            MvcScopedCss
5>                    Pattern=*.cshtml.css
5>            ComponentsScopedCss
5>                    Pattern=*.razor.css
5>            JsModuleManifest
5>                    Pattern=*.modules.json
5>    Task Parameter:SourceId=MyProject
5>    Task Parameter:FingerprintCandidates=True
5>    Task Parameter:
5>        CandidateAssets=
5>            wwwroot\background.png
5>                    CopyToOutputDirectory=Never
5>                    CopyToPublishDirectory=PreserveNewest
5>                    ExcludeFromSingleFile=true
5>            wwwroot\tlab.css
5>                    CopyToOutputDirectory=Never
5>                    CopyToPublishDirectory=PreserveNewest
5>                    ExcludeFromSingleFile=true
5>            wwwroot\tlab.min.css
5>                    CopyToOutputDirectory=Never
5>                    CopyToPublishDirectory=PreserveNewest
5>                    ExcludeFromSingleFile=true
5>            tsconfig.json
5>                    CopyToOutputDirectory=Never
5>                    CopyToPublishDirectory=PreserveNewest
5>                    ExcludeFromSingleFile=true
5>            _Imports.razor
5>                    CopyToOutputDirectory=Never
5>                    ExcludeFromSingleFile=true
5>                    Pack=false
5>            Scripts\init.ts
5>                    CopyToOutputDirectory=Never
5>            Scripts\tlab.ts
5>                    CopyToOutputDirectory=Never
5>            Styles\tlab.scss
5>                    CopyToOutputDirectory=Never
5>            Styles\height.scss
5>                    CopyToOutputDirectory=Never
5>            Styles\scroll.scss
5>                    CopyToOutputDirectory=Never
5>            Styles\width.scss
5>                    CopyToOutputDirectory=Never
5>    Task Parameter:ContentRoot=F:\source\MyProject\wwwroot\
5>    Task Parameter:BasePath=_content/MyProject
5>    Accepted asset 'wwwroot\background.png' for pattern 'wwwroot/**' with relative path 'background.png'
5>    Computing fingerprint and integrity for asset 'wwwroot\background.png'
5>    Fingerprinting asset 'background.png' as 'background#[.{fingerprint}]?.png' because it didn't match any pattern
5>    Accepted asset 'wwwroot\tlab.css' for pattern 'wwwroot/**' with relative path 'tlab.css'
5>    Computing fingerprint and integrity for asset 'wwwroot\tlab.css'
5>    C:\Program Files\dotnet\sdk\9.0.100\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(662,5): error : System.InvalidOperationException: No file exists for the asset at either location 'wwwroot\tlab.css' or 'wwwroot\tlab.css'.
5>    C:\Program Files\dotnet\sdk\9.0.100\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(662,5): error :    at Microsoft.AspNetCore.StaticWebAssets.Tasks.StaticWebAsset.ComputeFingerprintAndIntegrity(String identity, String originalItemSpec)
5>    C:\Program Files\dotnet\sdk\9.0.100\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(662,5): error :    at Microsoft.AspNetCore.StaticWebAssets.Tasks.DefineStaticWebAssets.Execute()
5>  Done executing task "DefineStaticWebAssets" -- FAILED.

The .css files are compiled with BuildWebCompiler2022 from .scss.

@balachir
Copy link

@javiercn @halter73 this issue also got reported as a regression with VS 17.12 on Developer Community here. Many customers are reporting it. Can you investigate and help determine if the issue is on the runtime side or tooling? Thanks!

cc: @mkArtakMSFT

@Marius-du-Toit
Copy link

Marius-du-Toit commented Nov 17, 2024

After upgrade to VS 17.12, we experience the same with trying to bundle css. When I "build" the web project, it works. However, doing a "rebuild" on the web project fails.

Image

@Marius-du-Toit
Copy link

As suggested elsewhere - adding a "global.json" to the root of your solution with the following will target the 8.0 SDK as a short term workaround.

{
"sdk": {
"version": "8.0.404",
"rollForward": "latestPatch"
}
}

@fsea
Copy link

fsea commented Nov 18, 2024

As suggested elsewhere - adding a "global.json" to the root of your solution with the following will target the 8.0 SDK as a short term workaround.

{ "sdk": { "version": "8.0.404", "rollForward": "latestPatch" } }

非常感谢你,按你的方法已解决了我的问题:
System.InvalidOperationException: No file exists for the asset at either location 'wwwroot\lib\bootstrap.table\1.12.0\bootstrap-table.min.css' or 'wwwroot\lib\bootstrap.table\1.12.0\bootstrap-table.min.css'.
在 Microsoft.AspNetCore.StaticWebAssets.Tasks.StaticWebAsset.ComputeFingerprintAndIntegrity(String identity, String originalItemSpec)
在 Microsoft.AspNetCore.StaticWebAssets.Tasks.DefineStaticWebAssets.Execute()

@mkArtakMSFT mkArtakMSFT added feature-static-web-assets area-ui-rendering Includes: MVC Views/Pages, Razor Views/Pages and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Nov 18, 2024
@mkArtakMSFT
Copy link
Member

mkArtakMSFT commented Nov 18, 2024

Thanks for reporting this issue, everyone. For now, can you please try to disable the fingerprinting until we get to the bottom of this and address it:
You can do so by setting the following property in your project file:

<StaticWebAssetFingerprintingEnabled>false</StaticWebAssetFingerprintingEnabled>

@javiercn
Copy link
Member

The project doesn't seem to be following the guidance that we provide here. Although that documentation seems to be slightly out of date.

+       <PrepareForBuildDependsOn>
+               CompileTypeScriptWithTSConfig;
+               GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
+       </PrepareForBuildDependsOn>
  </PropertyGroup>

+  <ItemGroup>
+       <Content Remove="wwwroot\js\**" />
+  </ItemGroup>
  • The first bit is needed because otherwise the compiler runs too late in the pipeline for us to pick up the changes.
  • The second bit is because the compiler is dropping the outputs in the wwwroot folder, which is something we actively discourage, as it makes the outputs from one build into inputs for the next one.
    • The way to avoid this is to exclude the outputs in the wwwroot folder from the Content item group.

@javiercn
Copy link
Member

@balachir check the comment above, the likely cause has been that CompileTypeScript changed to be CompileTypeScriptWithTSConfig and things end up not being wired up correctly after that.

@javiercn
Copy link
Member

dotnet/AspNetCore.Docs#34165 <- Tracks updating the docs.

For people using other tools to compile/generate assets, make sure that you use https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-9.0&tabs=visual-studio#add-client-web-assets-to-the-build-process.

Or if you are wiring your own target, it needs to be wired up before static web assets are discovered, typically, AssignTargetPaths, or PrepareForBuild

@kaleidocore
Copy link
Author

kaleidocore commented Nov 19, 2024

@javiercn

The project doesn't seem to be following the guidance that we provide here. Although that documentation seems to be slightly out of date.

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

If i publish my project with the above markup added to the .csproj the generated .js files are not included in the published output, which defeats the entire purpose...

* The first bit is needed because otherwise the compiler runs too late in the pipeline for us to pick up the changes.

I think this is probably at the core of the issue - it has always seemed as if things are built or checked in the wrong order. It seems strange to me, however, that this dependency chain is not automatically enforced by the TS build target or similar...

* The second bit is because the compiler is dropping the outputs in the `wwwroot` folder, which is something we actively discourage, as it makes the outputs from one build into inputs for the next one.
  
  * The way to avoid this is to exclude the outputs in the wwwroot folder from the `Content` item group.

Could you please help me understand how this solves the issue - yes, it builds but only because the generated output is ignored and excluded from publish? I mean, what's the point then?

@DominikDostal
Copy link

For css files that were minified using https://marketplace.visualstudio.com/items?itemName=Failwyn.BundlerMinifier64 it worked for me with:

 <PropertyGroup>
  <PrepareForBuildDependsOn>
   BundleMinify;$(PrepareForBuildDependsOn)
  </PrepareForBuildDependsOn>
 </PropertyGroup>

If you are using something else to minify, you will have to find out what they called their build target.

For Typescript I followed the suggestion with the following config:

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

But now I get this error (even with the <Content Remove="wwwroot\js\**" />)

Two assets found targeting the same path with incompatible asset kinds: 
'PROJECTPATH_REMOVED\wwwroot\js\browserWindowOpener.js' with kind 'All'
'PROJECTPATH_REMOVED\wwwroot\js\browserWindowOpener.js' with kind 'All'
for path 'js/browserWindowOpener#[.{fingerprint}]?.js'

@javiercn
Copy link
Member

But now I get this error (even with the )

Two assets found targeting the same path with incompatible asset kinds:
'PROJECTPATH_REMOVED\wwwroot\js\browserWindowOpener.js' with kind 'All'
'PROJECTPATH_REMOVED\wwwroot\js\browserWindowOpener.js' with kind 'All'
for path 'js/browserWindowOpener#[.{fingerprint}]?.js'

This is because the typescript compiler adds the elements as Content items to the build, the issue here is that on subsequent builds, the elements are present in the wwwroot folder and get included twice. That's what the <Content Remove="wwwroot\js\** /> line was meant to address, but I've now realized based on @kaleidocore comment that the approach was naive.

I'll post an updated fix and we will document this in the docs.

@javiercn
Copy link
Member

The missing piece is this one target that removes existing content items before GetTypeScriptOutputForPublishing gets invoked. Ideally, this should be done by the TypeScript SDK itself.

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

@javiercn
Copy link
Member

I've filed microsoft/TypeScript#60538 on the typescript repository to improve the integration with ASP.NET Core, I suggest you go and upvote the issue to show interest.

Hopefully we can make this just work out of the box.

For other tools, hooking to PrepareForBuildDependsOn is a good solution. #38445 tracks offering official integration

@javiercn javiercn added question ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. and removed investigate labels Nov 19, 2024
@jswolf19
Copy link

@javiercn I'm sorry if this information is readily available elsewhere, but is there a difference between adding a task to the PrepareForBuildDependsOn list vs adding PrepareForBuild to a custom target's BeforeTargets attribute, or is it just that PrepareForBuildDependsOn works without modifying the target markup and thus a more general solution?

Copy link
Contributor

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

@Liebeck
Copy link

Liebeck commented Nov 21, 2024

I've been experiencing a similar error for an ASP.NET Core MVC project that I updated to .NET 9.
Rebuilding always fails and all my attempts to fix the issue in the last couple of hours failed.

In the end, this is my workaround: Don't use rebuild, use clean + build instead

The workaround with
<StaticWebAssetFingerprintingEnabled>false</StaticWebAssetFingerprintingEnabled>
did not work for me, unfortunately.

@kaleidocore
Copy link
Author

@Liebeck >

In the end, this is my workaround: Don't use rebuild, use clean + build instead

That is not a viable option for our build server, or for our devs in the long run. We've had some limited success with the proposed solution by @javiercn but it leads to other build problems, in particular with our MAUI hybrid project. I will probably open up a second issue once I have a new minimal repro prepared. For now our only workaround is still the global.json SDK downgrade.

The workaround with <StaticWebAssetFingerprintingEnabled>false</StaticWebAssetFingerprintingEnabled> did not work for me, unfortunately.

Yeah, we've had the same experience. That's why I mentioned in the original post that it's unclear why fingerprinting is running and how to turn it off.

@Smayke95
Copy link

Smayke95 commented Nov 21, 2024

For css files that were minified using https://marketplace.visualstudio.com/items?itemName=Failwyn.BundlerMinifier64 it worked for me with:

BundleMinify;$(PrepareForBuildDependsOn) If you are using something else to minify, you will have to find out what they called their build target.

For Typescript I followed the suggestion with the following config:

CompileTypeScriptWithTSConfig; GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn) But now I get this error (even with the ``)
Two assets found targeting the same path with incompatible asset kinds: 
'PROJECTPATH_REMOVED\wwwroot\js\browserWindowOpener.js' with kind 'All'
'PROJECTPATH_REMOVED\wwwroot\js\browserWindowOpener.js' with kind 'All'
for path 'js/browserWindowOpener#[.{fingerprint}]?.js'

For css files that were minified using https://www.nuget.org/packages/BuildWebCompiler2022 it worked for me with:

<PropertyGroup>
  <PrepareForBuildDependsOn>WebCompile;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn>
</PropertyGroup>

@bmiller-pm
Copy link

Well I'd like to add that I use both Mads BuildWebCompiler and BuildBundlerMinifier and this worked for me:

<PropertyGroup>
  <PrepareForBuildDependsOn>WebCompile;BundleMinify;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn>
</PropertyGroup>

@runeanderberg
Copy link

runeanderberg commented Nov 25, 2024

@javiercn

The missing piece is this one target that removes existing content items before GetTypeScriptOutputForPublishing gets invoked. Ideally, this should be done by the TypeScript SDK itself.

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

This does indeed prevent the error, but it seems to cause other issues. If I rebuild multiple times in a row, the generated files get deleted at the end of every other rebuild.

@robertmclaws
Copy link

I'm going to say it, and I'm sure that some people might interpret this as not helpful. As someone who has been bit repeatedly by releases of the StaticWebAssets SDK (including this one) throughout the .NET 9.0 release cycle, I feel I deserve to say it:

This SDK feels too rushed out the door for such a minimal impact on the platform. It doesn't feel like there were any real-world unit and integration tests built to handle the different ways that compiled assets are used on Blazor code, and that's why you're seeing the issues you are today.

I hope building this did not take away resources from Blazor Multithreading.

@bmiller-pm
Copy link

Furthermore, I just realized that using MapStaticAssets messes with my API GET endpoints -- but only under Development build. Freaked me out at first.

Had to crawl through the source code to find that setting
"DisableStaticAssetNotFoundRuntimeFallback": true,
in the app.settings.developement.json fixes this.

Note that there are 2 other dev settings as well:
"EnableStaticAssetsDevelopmentCaching" and "EnableStaticAssetsDevelopmentIntegrity"

So it seems that MapStaticAssets also checks your api endpoints for static resources?
I would rather it didn't do this by default.

@ray440
Copy link

ray440 commented Nov 25, 2024

<StaticWebAssetFingerprintingEnabled>false</StaticWebAssetFingerprintingEnabled> works for .net9.0.

But doesn't work for .net8.0. So our compiles with <TargetFrameworks>net9.0; net8.0</TargetFrameworks> break...

@robertmclaws
Copy link

<StaticWebAssetFingerprintingEnabled>false</StaticWebAssetFingerprintingEnabled> works for .net9.0.

But doesn't work for .net8.0. So our compiles with <TargetFrameworks>net9.0; net8.0</TargetFrameworks> break...

Yep, which is what I (and literally anyone else who makes Blazor assemblies) am targeting right now in my projects. Also, this thread needs to be re-opened because there is not actually a functioning fix yet.

@Watertight-skaat
Copy link

Watertight-skaat commented Dec 3, 2024

I'm still getting this error, but with an html file that is minified during our build process. Only happens in azure pipelines (works locally). This prevents us with moving forward with dotnet 9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-ui-rendering Includes: MVC Views/Pages, Razor Views/Pages feature-static-web-assets ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. question Status: Resolved
Projects
None yet
Development

No branches or pull requests