Skip to content

Fix WASM boot config ContentRoot to use IntermediateOutputPath#124125

Open
lewing wants to merge 2 commits intodotnet:mainfrom
lewing:fix/wasm-compression-stale-files
Open

Fix WASM boot config ContentRoot to use IntermediateOutputPath#124125
lewing wants to merge 2 commits intodotnet:mainfrom
lewing:fix/wasm-compression-stale-files

Conversation

@lewing
Copy link
Member

@lewing lewing commented Feb 7, 2026

Summary

Fix a .NET 11 regression causing SRI integrity failures during incremental Blazor WASM builds. Two changes in Microsoft.NET.Sdk.WebAssembly.Browser.targets:

  1. ContentRoot fix: Change the boot config's DefineStaticWebAssets ContentRoot from $(OutDir)wwwroot to $(IntermediateOutputPath)
  2. Preload matching fix: Replace fragile %(FileName)%(Extension)-based scanning with direct references to the boot config output items

Regression

This is a regression in .NET 11 (works in 10.0). It was introduced by dotnet/sdk#52283, which fixed an esproj compression bug by flipping the order in AssetToCompress.TryFindInputFilePath to prefer RelatedAsset (Identity) over RelatedAssetOriginalItemSpec. That fix was correct for esproj, but exposed a latent issue in the WASM SDK targets: the boot config asset's Identity pointed to a wwwroot copy rather than the actual source file in obj/.

Before sdk#52283, OriginalItemSpec happened to point to the real file and was checked first, masking the wrong ContentRoot. After the flip, RelatedAsset (Identity) is checked first, and its stale wwwroot path is used — producing incorrect SRI hashes on incremental builds.

Reported in aspnetcore#65271.

Problem

The WASM boot config file (e.g. dotnet.js) is generated at $(IntermediateOutputPath) (the obj/ folder), but its static web asset was defined with ContentRoot="$(OutDir)wwwroot". This caused DefineStaticWebAssets to compute an Identity pointing to the wwwroot copy rather than the actual file in obj/.

During incremental builds, the compression task's RelatedAsset (which uses Identity) would point to the stale wwwroot copy, producing incorrect SRI fingerprints and causing integrity check failures at runtime.

Fix

1. ContentRoot change

Change ContentRoot to $(IntermediateOutputPath) so the asset Identity matches the real file location on disk. The CopyToOutputDirectory="PreserveNewest" attribute still ensures the file is copied to wwwroot for serving.

This follows Javier's suggestion in dotnet/sdk#52847 to "stop defining these assets with an item spec in the wwwroot folder and just define them in their original location on disk".

2. Preload matching simplification

The _AddWasmPreloadBuildProperties and _AddWasmPreloadPublishProperties targets previously scanned all @(StaticWebAsset) items by %(FileName)%(Extension) to find the boot config asset. This relied on the Identity path containing the fingerprint in the filename (e.g. dotnet.FINGERPRINT.js), which is an implementation detail of how DefineStaticWebAssets computes Identity based on ContentRoot.

With the ContentRoot change, Identity uses the physical filename (dotnet.js), so the fingerprint-in-filename matching fails and the preload filter returns all endpoints instead of just the boot config's.

The fix replaces the scanning with direct references to @(_WasmBuildBootConfigStaticWebAsset) and @(_WasmPublishBootConfigStaticWebAsset) — the output items already produced by DefineStaticWebAssets in the boot config generation targets. This is both correct and simpler: no filename decomposition, no fingerprint-dependent matching, and the same item that was defined is what gets used.

What's not changed

  • WebCil ContentRoot (line ~366, ContentRoot="$(_WasmBuildOuputPath)"): WebCil candidates come from multiple source directories and don't change on incremental builds unless the assembly changes, so they don't hit the staleness issue.
  • Publish boot config ContentRoot (line ~820, ContentRoot="$(PublishDir)wwwroot"): Publish builds are clean and don't have the incremental staleness problem.

Testing

  • All 9 Blazor SimpleRunTests pass (build, publish, AOT, different output paths)
  • Full Wasm.Build.Tests suite: 352/434 passed with workloads; remaining failures are flaky timeouts and pre-existing infrastructure issues unrelated to this change

Companion PR

SDK PR dotnet/sdk#52847 will need baseline JSON updates to reflect the changed Identity/ContentRoot paths.

Fixes dotnet/aspnetcore#65271

Change the boot config's DefineStaticWebAssets ContentRoot from
wwwroot to  so the asset Identity
points to the actual file location on disk rather than a stale copy
in the output wwwroot folder.

This fixes SRI integrity failures during incremental Blazor WASM builds
where the compressed boot config used a stale fingerprint from the
wwwroot copy instead of the fresh file in obj/.

Fixes aspnetcore#65271
Copilot AI review requested due to automatic review settings February 7, 2026 03:23
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 7, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Blazor WASM SDK targets to define the build boot config static web asset from its actual on-disk generation location (obj/) to prevent stale-asset Identity selection during incremental builds (which can lead to incorrect SRI integrity values at runtime).

Changes:

  • Change DefineStaticWebAssets ContentRoot for the build boot config asset from $(OutDir)wwwroot to $(IntermediateOutputPath).

@lewing lewing requested a review from javiercn February 7, 2026 03:33
@lewing lewing marked this pull request as ready for review February 7, 2026 03:33
@lewing lewing requested a review from akoeplinger as a code owner February 7, 2026 03:33
@lewing lewing requested a review from maraf February 7, 2026 03:49
@lewing lewing assigned javiercn and unassigned javiercn and lewing Feb 7, 2026
Replace the fragile FileName-based scanning of all StaticWebAsset items
with direct references to _WasmBuildBootConfigStaticWebAsset and
_WasmPublishBootConfigStaticWebAsset. These items are already produced
by the DefineStaticWebAssets task in _GenerateBuildWasmBootJson and
_AddPublishWasmBootJsonToStaticWebAssets respectively.

The previous approach relied on FileName containing the fingerprint
(e.g. dotnet.FINGERPRINT.js), which is an implementation detail of
how DefineStaticWebAssets computes Identity. Using the pipeline's
own output items is correct regardless of ContentRoot or Identity
format.
@lewing lewing added arch-wasm WebAssembly architecture area-Meta os-browser Browser variant of arch-wasm and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 7, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-meta
See info in area-owners.md if you want to be subscribed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-Meta os-browser Browser variant of arch-wasm

Projects

None yet

2 participants