Skip to content

_WriteBuildWasmBootJsonFile is not incremental #129280

Closed

Description

@jjonescz

Description

Target _WriteBuildWasmBootJsonFile prevents incremental builds.

Reproduction Steps

  1. dotnet new blazorwasm
  2. dotnet build /bl
  3. dotnet build /question /bl:question.binlog

Expected behavior

Succeeds - rebuilds should be incremental.

Actual behavior

Fails with error Building target "_WriteBuildWasmBootJsonFile" completely.
In the binlog I can also see Input file "obj\Debug\net11.0\blazor.build.boot-extension.json" is newer than output file "C:\Users\janjones\source\playground\BlazorWasmApp1\obj\Debug\net11.0\dotnet.js".

Regression?

Yes, incremental builds worked in .NET 11 Preview 4. (I have dotnet build /question check in my CI, maybe you should add tests for it too since I'm hitting this regularly.)

Known Workarounds

Yes, but it's not pretty: jjonescz/DotNetLab@1b58ccd

Configuration

.NET 11 Preview 5

Other information

No response

Activity

  1. dotnet-policy-service commented on Jun 11, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
    See info in area-owners.md if you want to be subscribed.

  2. added and removed
    untriagedNew issue has not been triaged by the area owner
    on Jun 11, 2026
  3. added this to the 11.0.0 milestone on Jun 11, 2026
  4. maraf commented on Jun 12, 2026

    @maraf
    Member

    Related to #125367

  5. lewing commented on Jun 18, 2026

    @lewing
    Member

    Adding evidence from a downstream variant of this same bug, surfaced by a different test path.

    Investigating WBT Wasm.Build.Tests.WasmTemplateTests.TypeScriptDefinitionsCopiedToWwwrootOnBuild(config: Debug, emitTypeScriptDts: True) failure on PR #129454 (build 1470806, workitem WBT-NoWebcil-MONO-ST-Wasm.Build.Tests.WasmTemplateTests). The reported failing target there is one level downstream:

    Building target "_BuildCopyStaticWebAssetsPreserveNewest" partially, because some output files are out of date with respect to their input files.
    [_BuildStaticWebAssetsPreserveNewest:
      Input  = obj\Debug\net11.0\compressed\{hash}-{0}-{fp}-{fp}.gz,
      Output = bin\Debug\net11.0\wwwroot\_framework\dotnet.{fp}.js.gz]
    Input file is newer than output file.
    

    Chain of causation (binlog-verified)

    1. _WriteBuildWasmBootJsonFile runs GenerateWasmBootJson (uses ArtifactWriter.PersistFileIfChanged — preserves old mtime on unchanged content) followed by <Touch Files="$(_WasmBuildBootJsonPath)" />. The Touch bumps obj/.../dotnet.js mtime to current.
    2. Same obj/.../dotnet.js is a source for the StaticWebAssets compression pipeline (GenerateBuildCompressedStaticWebAssets → GZipCompress task in dotnet/sdk src/StaticWebAssetsSdk/Tasks/Compression/GZipCompress.cs).
    3. In the -question rebuild, _WriteBuildWasmBootJsonFile correctly skips (UpToDate). But GenerateBuildCompressedStaticWebAssets has no Inputs=/Outputs= declaration, so its body runs unconditionally. GZipCompress's internal check (input.mtime < output.mtime strict) treats equal/newer as "compress" and re-writes obj/.../{0}.gz:
      Compressing 'obj\Debug\net11.0\dotnet.js' because file is newer than
      'obj\Debug\net11.0\compressed\{hash}-{0}-{fp}-{fp}.gz'.
      
    4. That re-written .gz now has a fresh mtime, exceeding the bin/.gz (last written during build WIP: repo consolidation scouting kick-off - make clr build locally on Windows #1's Copy). _BuildCopyStaticWebAssetsPreserveNewest sees its declared input newer than its declared output → -question fails.

    This is the symmetric symptom to what you reported: same root (<Touch> on the boot JSON, introduced by #125367), just the cascade extending one target further into the StaticWebAssets pipeline. Same fix addresses both.

    Historical context

    Worth noting: PR #118637 (Aug 2025, "Override boot config only when the content changes") was originally added specifically to fix the _BuildCopyStaticWebAssetsPreserveNewest symptom in dotnet/aspnetcore#63207 — by introducing PersistFileIfChanged so dotnet.js mtime would only change on content change. #125367's <Touch> undid that protection.

    Fix

    PR #129591 — touch a separate wasm-bootjson-{build,publish}.complete.stamp instead of the boot JSON itself, and use the stamp as the target's Outputs=. MSBuild's I/O check on the boot-JSON target works correctly via the stamp, while the boot JSON's mtime stays content-derived (restoring #118637's invariant for downstream consumers).

    Both build and publish targets get the same treatment in that PR.

    Note

    This comment was AI/Copilot-generated.

  6. added a commit that references this issue on Jun 22, 2026
    7f00936
  7. added a commit that references this issue on Jul 15, 2026
    591de2b
  8. locked and limited conversation to collaborators on Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions