From cb166eb5359639c59f54d4547767a91404fb63da Mon Sep 17 00:00:00 2001 From: lewing Date: Thu, 18 Jun 2026 14:12:29 -0500 Subject: [PATCH 1/2] [browser] Wasm boot JSON: touch a stamp, not the boot JSON itself MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build and publish boot JSON targets used to give MSBuild's Inputs/Outputs check a current output timestamp despite GenerateWasmBootJson's content-preservation behavior (PR #125367). However the boot JSON ($(_WasmBuildBootJsonPath), typically obj/.../dotnet.js, and the publish equivalent) is also a source for the StaticWebAssets compression pipeline and the PreserveNewest copy target. Bumping its mtime on every successful build defeats their incrementality checks and breaks `dotnet build -question`: Building target "_BuildCopyStaticWebAssetsPreserveNewest" partially, because some output files are out of date with respect to their input files. [_BuildStaticWebAssetsPreserveNewest: Input = obj/.../compressed/{hash}-{0}-{fp}-{fp}.gz, Output = bin/.../wwwroot/_framework/dotnet.{fp}.js.gz] Input file is newer than output file. This is the same regression that PR #118637 (Aug 2025) originally fixed by introducing ArtifactWriter.PersistFileIfChanged. PR #125367's on the boot JSON re-broke it by bumping the file's mtime unconditionally after every successful run. Replace the on the boot JSON with a on a separate `wasm-bootjson-{build,publish}.complete.stamp` file, and use that stamp as the target's Outputs=. MSBuild now sees a current output timestamp for its own incrementality check on the boot-JSON target, without touching the boot JSON itself — preserving content-mtime semantics for downstream consumers. Fixes dotnet/runtime#129280 Fixes the downstream cascade observed on PR dotnet/runtime#129454 (WBT `TypeScriptDefinitionsCopiedToWwwrootOnBuild(Debug, emitTypeScriptDts:True)`). Same fix applied to both the build (`_WriteBuildWasmBootJsonFile`) and publish (`GeneratePublishWasmBootJson`) paths since both have identical shape and the same downstream consumers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) 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 ab8d6606aba35e..923058fb7f95a3 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 @@ -708,7 +708,7 @@ Copyright (c) .NET Foundation. All rights reserved. DependsOnTargets="_WriteWasmBootJsonBuildPropertyStamp" Condition="'$(WasmBuildingForNestedPublish)' != 'true'" Inputs="@(IntermediateAssembly);@(WasmStaticWebAsset);@(_WasmJsModuleCandidatesForBuild);@(_WasmFilesToIncludeInFileSystemStaticWebAsset);@(_WasmJsConfigStaticWebAsset);@(_WasmDotnetJsForBuild);@(WasmBootConfigExtension);$(ProjectRuntimeConfigFilePath);$(MSBuildProjectFullPath);$(MSBuildThisFileFullPath);$(_WebAssemblySdkTasksAssembly);$(IntermediateOutputPath)wasm-bootjson-build.stamp" - Outputs="$(_WasmBuildBootJsonPath)"> + Outputs="$(IntermediateOutputPath)wasm-bootjson-build.complete.stamp"> + - - + + - + + From 97a975c2cd9a8c5b57252bf09865286c6c4fbee9 Mon Sep 17 00:00:00 2001 From: lewing Date: Thu, 18 Jun 2026 14:20:38 -0500 Subject: [PATCH 2/2] Track .complete.stamp in always-run wrapper FileWrites Addresses Copilot review feedback on dotnet/runtime#129591: the .complete.stamp files added in the prior commit are only listed in FileWrites inside the incremental targets (_WriteBuildWasmBootJsonFile, GeneratePublishWasmBootJson). When those targets are skipped on incremental builds, the in-body entries are not populated, so `dotnet clean` would leave the stamps behind. Mirror the existing pattern from PR #125367: also add the stamp paths to FileWrites in the always-run wrapper targets (_GenerateBuildWasmBootJson and _AddPublishWasmBootJsonToStaticWebAssets) that track the boot JSON itself for the same reason. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../build/Microsoft.NET.Sdk.WebAssembly.Browser.targets | 7 +++++++ 1 file changed, 7 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 923058fb7f95a3..d586a4d6c80452 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 @@ -773,6 +773,11 @@ Copyright (c) .NET Foundation. All rights reserved. + + <_WasmBuildBootConfigCandidate Include="$(_WasmBuildBootJsonPath)" RelativePath="_framework/$(_WasmBootConfigFileName)" /> @@ -1092,6 +1097,8 @@ Copyright (c) .NET Foundation. All rights reserved. + + <_WasmPublishBootConfigCandidate Include="$([MSBuild]::NormalizePath($(IntermediateOutputPath), $(_WasmPublishBootConfigFileName)))" RelativePath="_framework/$(_WasmBootConfigFileName)" />