[browser] Don't copy framework assets to output during build#126407
[browser] Don't copy framework assets to output during build#126407
Conversation
During build, the WebAssembly SDK was copying all .wasm and .js framework assets to bin/wwwroot/_framework/ via CopyToOutputDirectory=PreserveNewest. This is unnecessary because dotnet run uses the static web assets middleware, which serves files directly from their obj/ locations using the manifest. Change CopyToOutputDirectory from PreserveNewest to Never for: - Webcil-converted assets (Computed static web assets) - Materialized framework assets (dotnet.js, dotnet.native.wasm, etc.) This eliminates ~178 file copies during build while preserving correct behavior for dotnet run (static web assets middleware) and publish (CopyToPublishDirectory was already Never). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
This PR changes the WebAssembly SDK build targets to stop copying runtime/framework static web assets into bin/wwwroot/_framework during build, relying instead on the static web assets manifest/middleware to serve them from their source locations (typically under obj/ or the runtime pack).
Changes:
- Set
CopyToOutputDirectory="Never"for build-time static web assets emitted from webcil conversion (SourceType="Computed"). - Set
CopyToOutputDirectory="Never"for build-time runtime pack assets registered asSourceType="Framework". - Set
CopyToOutputDirectory="Never"for the post-UpdatePackageStaticWebAssets“materialized” framework assets (per-projectobj/fx/{SourceId}/copies).
| <!-- Materialized framework assets must be visible to referencing projects (e.g. Blazor WASM | ||
| hosted scenarios where the server project serves the client's framework files). | ||
| UpdatePackageStaticWebAssets defaults AssetMode to CurrentProject and CopyToOutputDirectory | ||
| to Never. Override both: AssetMode=All so assets flow through project references, and | ||
| CopyToOutputDirectory=PreserveNewest so they are copied from the intermediate materialized | ||
| path (obj/fx/{SourceId}/) to bin/wwwroot/_framework/ at build time. --> |
There was a problem hiding this comment.
The comment above this ItemGroup still says CopyToOutputDirectory is overridden to PreserveNewest to copy materialized framework assets into bin/wwwroot/_framework at build time, but the code now sets CopyToOutputDirectory="Never". Please update the comment to reflect the new behavior/rationale (and avoid referencing build-time copying if that is no longer intended).
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
|
Note This comment was generated with the assistance of GitHub Copilot. Blazor WASM Hosted Scenario AnalysisTesting revealed that the existing // Lines 169-179
string client1Framework = Path.Combine(client1Dir, "bin", config.ToString(),
DefaultTargetFrameworkForBlazor, "wwwroot", "_framework");
Assert.True(Directory.Exists(client1Framework), ...);
Assert.Contains(client1Files, f => Path.GetFileName(f).StartsWith("dotnet.") && f.EndsWith(".js"));This test creates two Blazor WASM client projects hosted by a single server and verifies that each client gets its own physical framework files — validating the Framework Impact Summary
Next StepsOptions to consider:
|
|
Note This comment was generated by GitHub Copilot. CI Failure AnalysisAll 4 failing jobs are caused by this PR. None are infrastructure or known issues. SummaryAll 4 jobs are Failing Tests (13 unique across 4 jobs)All fail with:
Root Cause in Test CodeThe common assertion point is Known IssuesBuild Analysis flagged 3 known issues (#109653, #125244, #117164) but none match these failures. These are genuinely new failures introduced by the PR. Next StepsTo land this change, the test assertions in |
With CopyToOutputDirectory=Never, framework assets are no longer copied to bin/wwwroot/_framework/ during build. They are served from obj/ locations via the static web assets middleware during dotnet run. Only assert bundle file layout for publish, where files are still physically copied to the output. Build-time tests that run the app (via dotnet run or xharness) still validate the app works correctly - they just don't check for files in bin/ that are intentionally no longer there. The Blazor-specific AssertBundle already had this guard WasmTemplateTestsBase path needed updating. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🤖 Copilot Code Review — PR #126407Note This review was generated by Copilot and may contain inaccuracies. A human reviewer should validate these findings. Holistic AssessmentMotivation: This PR optimizes WASM development builds by eliminating ~178 unnecessary file copies to Approach: Changing Summary: Detailed Findings
|
| // no longer contains framework files in bin/_framework/. The static web | ||
| // assets middleware serves them from obj/ locations during dotnet run. |
There was a problem hiding this comment.
The new comment says build output no longer contains framework files in bin/_framework/, but the bundle path used by these tests/providers is bin/<config>/<tfm>/wwwroot/_framework (see WasmSdkBasedProjectProvider.GetBinFrameworkDir). Consider correcting the path in the comment to avoid confusion for future test failures/investigations.
| // no longer contains framework files in bin/_framework/. The static web | |
| // assets middleware serves them from obj/ locations during dotnet run. | |
| // no longer contains framework files in | |
| // bin/<configuration>/<tfm>/wwwroot/_framework/. The static web assets | |
| // middleware serves them from obj/ locations during dotnet run. |
| if (buildOptions.AssertAppBundle) | ||
| { | ||
| _provider.AssertWasmSdkBundle(configuration, buildOptions, IsUsingWorkloads, isNativeBuild, wasmFingerprintDotnetJs, res.Output); | ||
| // With CopyToOutputDirectory=Never for framework assets, build output | ||
| // no longer contains framework files in bin/_framework/. The static web | ||
| // assets middleware serves them from obj/ locations during dotnet run. | ||
| // Only assert bundle contents for publish, where files are still copied. | ||
| if (buildOptions.IsPublish) | ||
| { | ||
| _provider.AssertWasmSdkBundle(configuration, buildOptions, IsUsingWorkloads, isNativeBuild, wasmFingerprintDotnetJs, res.Output); | ||
| } |
There was a problem hiding this comment.
Gating AssertWasmSdkBundle(...) to publish-only removes bundle verification for all build-based tests that rely on AssertAppBundle=true (the default). Instead of skipping the assertion entirely for build, consider updating the assertion logic to validate framework assets at their new source locations (e.g., obj/fx/... / static web assets manifest) so build scenarios remain covered.
| <!-- Materialized framework assets must be visible to referencing projects (e.g. Blazor WASM | ||
| hosted scenarios where the server project serves the client's framework files). | ||
| UpdatePackageStaticWebAssets defaults AssetMode to CurrentProject and CopyToOutputDirectory | ||
| to Never. Override both: AssetMode=All so assets flow through project references, and | ||
| CopyToOutputDirectory=PreserveNewest so they are copied from the intermediate materialized | ||
| path (obj/fx/{SourceId}/) to bin/wwwroot/_framework/ at build time. --> | ||
| <ItemGroup> | ||
| <_WasmMaterializedFrameworkAssets Update="@(_WasmMaterializedFrameworkAssets)" | ||
| AssetMode="All" CopyToOutputDirectory="PreserveNewest" /> | ||
| AssetMode="All" CopyToOutputDirectory="Never" /> |
There was a problem hiding this comment.
The comment above this ItemGroup still states that CopyToOutputDirectory is overridden to PreserveNewest for hosted scenarios, but the code now sets it to Never. Please update/remove the outdated comment text, and consider dropping the explicit CopyToOutputDirectory="Never" metadata override here since UpdatePackageStaticWebAssets already defaults it to Never (per the comment at lines 429-430).
With CopyToOutputDirectory=Never, framework files are no longer copied to bin/_framework/ during build. Update MultiClientHostedBuildAndPublish to assert framework files exist in obj/<config>/<tfm>/fx/<ProjectName>/ _framework/ for build, matching the materialization path used by UpdatePackageStaticWebAssets. Publish assertions remain unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Revert the IsPublish guard that skipped AssertWasmSdkBundle for builds.
Instead, add AssertBuildBundle that validates framework files are in their
correct obj/ subdirectories with CopyToOutputDirectory=Never:
- dotnet.js (boot config) in obj/{config}/{tfm}/
- dotnet.runtime.js, maps, ICU in obj/{config}/{tfm}/fx/{name}/_framework/
- dotnet.native.* in fx/_framework/ (non-native) or wasm/for-build/ (native)
- webcil assemblies in obj/{config}/{tfm}/webcil/
- framework files NOT in bin/_framework/
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Note
This PR was created with the assistance of GitHub Copilot.
Summary
During build, the WebAssembly SDK copies all
.wasmand.jsframework assets (~178 files) tobin/wwwroot/_framework/viaCopyToOutputDirectory=PreserveNewest. This is unnecessary becausedotnet runuses the static web assets middleware, which serves files directly from theirobj/locations via the manifest (staticwebassets.runtime.json).Changes
Set
CopyToOutputDirectory=Never(wasPreserveNewest) for threeDefineStaticWebAssets/ item-update calls inMicrosoft.NET.Sdk.WebAssembly.Browser.targets:.wasmfiles produced from.dlldotnet.js,dotnet.native.wasm, runtime JS, etc.UpdatePackageStaticWebAssets) — the per-project copies inobj/fx/Validation
dotnet buildwithTargetOS=browser)dotnet runstarts WasmAppHost dev server correctly42)bin/wwwroot/_framework/drops from ~178 files to 2 (only hot-reload module + dotnet.js from a separate code path)CopyToPublishDirectorywas alreadyNever— publish is unaffectedNotes
PreserveNewestwas added for Blazor WASM hosted scenarios where a server project serves the client's framework files. This scenario needs separate validation.obj/dirs), so physical copies inbin/are not needed fordotnet run.