关于 dotnet-aot-wasm
此技能介绍 Blazor WASM 和 Uno WASM 应用的 AOT 编译,帮助 .NET 开发者权衡下载体积与运行速度,并讲解裁剪、延迟加载和 Brotli 压缩。
主要功能
- 01比较 WASM 下载体积与运行速度
- 02配置 Blazor 和 Uno WASM AOT
- 03结合使用 AOT 与裁剪
- 04通过延迟加载推迟程序集下载
- 05使用 Brotli 预压缩优化传输
适用场景
- 01加速 CPU 密集型 WASM 工作负载
- 02平衡初始下载与运行性能
- 03按需加载可选模块
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-aot-wasm安装后在 Claude Code 中输入/dotnet-aot-wasm确认已加载。
详细介绍
dotnet-aot-wasm
面向 Blazor WASM 和 Uno WASM 应用的 WebAssembly AOT 编译:编译流水线、下载体积与运行速度的权衡、修剪的协同作用、程序集延迟加载,以及用于优化下载的 Brotli 预压缩。
**版本假设:**以 .NET 8.0+ 为基线。Blazor WASM AOT 于 .NET 6 中推出,并在 .NET 8-10 中持续改进。Uno WASM 使用类似的编译流水线,并配有 Uno 专用工具。
重要权衡:修剪和 AOT 对 WASM 产物体积的影响相反。修剪会移除未使用的代码,从而缩小下载体积。AOT 会增大产物体积(原生 WASM 代码比 IL 更大),但能提升运行时执行速度。两者结合使用可获得最佳平衡。
**不在讨论范围内:**服务器端 .NET 的 Native AOT——请参阅 [skill:dotnet-native-aot]。AOT 优先的设计模式——请参阅 [skill:dotnet-aot-architecture]。适用于修剪的库编写——请参阅 [skill:dotnet-trimming]。MAUI 专用 AOT——请参阅 [skill:dotnet-maui-aot]。Blazor 组件模式和架构——请参阅 [skill:dotnet-blazor-patterns](次要)。Uno Platform 架构——请参阅 [skill:dotnet-uno-platform](次要)。
交叉引用:[skill:dotnet-native-aot] 介绍通用 AOT 流水线,[skill:dotnet-trimming] 介绍修剪注解,[skill:dotnet-aot-architecture] 介绍适用于 AOT 的设计模式,[skill:dotnet-serialization] 介绍适用于 AOT 的序列化,[skill:dotnet-csharp-source-generators] 介绍作为 AOT 推动因素的源生成器,[skill:dotnet-blazor-patterns] 介绍 Blazor 架构(次要),[skill:dotnet-uno-platform] 介绍 Uno Platform 模式(次要)。
下载体积与运行速度
了解体积与速度之间的权衡,对于 WASM AOT 决策至关重要:
| 编译模式 | 下载体积 | 运行速度 | 启动时间 |
|---|---|---|---|
| IL 解释器(无 AOT) | 最小 | 最慢 | 启动最快 |
| AOT(所有程序集) | 最大 | 最快 | 启动较慢 |
| AOT(选择性)+ 修剪 | 均衡 | 良好 | 适中 |
| 仅修剪(无 AOT) | 小 | 适中(JIT 解释) | 快 |
关键要点:修剪会移除未使用的 IL,从而缩小体积。AOT 会增大产物总体积,因为编译后的原生 WASM 代码比等效的 IL 字节码更大。不过,AOT 编译后的代码执行速度显著更快,因为运行时无需解释 IL。
何时使用 WASM AOT
- **CPU 密集型工作负载:**图像处理、复杂计算、数据转换
- **性能可预测:**执行速度稳定,不会出现 JIT 暂停
- **热点路径:**仅对性能关键的程序集进行 AOT 编译(选择性 AOT)
何时跳过 WASM AOT
- **带宽受限的用户:**AOT 会显著增大下载体积
- **简单的 CRUD 应用:**对于 UI 交互和 API 调用,IL 解释速度足够快
- **快速迭代:**AOT 编译会显著增加发布耗时
Blazor WASM AOT
启用 AOT
<PropertyGroup>
<RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>
# Publish with AOT (required -- AOT only applies during publish)
dotnet publish -c Release
注意:RunAOTCompilation 是 Blazor WASM 属性(而非用于服务器端 Native AOT 的 PublishAot)。AOT 编译仅在 dotnet publish 期间进行,不会在 dotnet run 或 dotnet build 期间进行。
通过延迟加载选择性使用 AOT
Blazor WASM AOT 会编译所有未延迟加载的程序集。若要控制哪些程序集进行 AOT 编译,请将非关键程序集标记为延迟加载——它们将改用 IL 解释:
<PropertyGroup>
<RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>
<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="MyApp.Reporting.wasm" />
<BlazorWebAssemblyLazyLoad Include="MyApp.Admin.wasm" />
</ItemGroup>
同时使用修剪和 AOT
要获得最佳平衡,请同时使用修剪和 AOT:
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<RunAOTCompilation>true</RunAOTCompilation>
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>
发布流水线按以下顺序运行:先修剪未使用的 IL,再将剩余程序集 AOT 编译为原生 WASM。这样生成的产物比仅修剪的产物更大,但比未修剪的 AOT 产物更小,同时拥有最佳运行时性能。
Uno WASM AOT
Uno Platform 5+ 搭配 .NET 8+ 使用标准 .NET WASM 工作负载,因此 AOT 配置与 Blazor WASM 相同。
启用 AOT(Uno 5+ / .NET 8+)
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0-browserwasm'">
<RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>
较旧版本 Uno 使用 Uno.Wasm.Bootstrap 时,有一个单独的 WasmShellMonoRuntimeExecutionMode 属性,支持 Interpreter、InterpreterAndAOT 和 FullAOT 模式。在 .NET 8+ 中,请改用 RunAOTCompilation。
Uno WASM 中的裁剪
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode>
</PropertyGroup>
请参阅 [skill:dotnet-uno-platform],了解 Uno Platform 架构模式。
延迟加载程序集
延迟加载会将程序集的下载推迟到需要时,从而减小初始下载大小。与 AOT 配合使用时尤其有效,因为 AOT 会增加每个程序集的大小。
Blazor WASM 延迟加载
<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="MyApp.Reporting.wasm" />
<BlazorWebAssemblyLazyLoad Include="MyApp.Admin.wasm" />
<BlazorWebAssemblyLazyLoad Include="ChartLibrary.wasm" />
</ItemGroup>
// Load assemblies on demand in a component or router
@inject LazyAssemblyLoader LazyLoader
@code {
private List<Assembly> _lazyLoadedAssemblies = new();
private async Task LoadReportingModule()
{
var assemblies = await LazyLoader.LoadAssembliesAsync(new[]
{
"MyApp.Reporting.wasm"
});
_lazyLoadedAssemblies.AddRange(assemblies);
}
}
基于路由的延迟加载
@inject LazyAssemblyLoader LazyLoader
<Router AppAssembly="typeof(App).Assembly"
AdditionalAssemblies="@_lazyLoadedAssemblies"
OnNavigateAsync="@OnNavigateAsync">
<Navigating>
<div class="loading">Loading module...</div>
</Navigating>
</Router>
@code {
private List<Assembly> _lazyLoadedAssemblies = new();
private async Task OnNavigateAsync(NavigationContext context)
{
if (context.Path.StartsWith("admin"))
{
var assemblies = await LazyLoader.LoadAssembliesAsync(new[]
{
"MyApp.Admin.wasm"
});
_lazyLoadedAssemblies.AddRange(assemblies);
}
else if (context.Path.StartsWith("reports"))
{
var assemblies = await LazyLoader.LoadAssembliesAsync(new[]
{
"MyApp.Reporting.wasm"
});
_lazyLoadedAssemblies.AddRange(assemblies);
}
}
}
延迟加载策略
| 策略 | 初始加载 | 功能加载 | 最适用场景 |
|---|---|---|---|
| 不进行延迟加载 | 一次性全部加载 | 即时 | 小型应用(总大小 <5 MB) |
| 基于路由的延迟加载 | 仅核心内容 | 导航时 | 多模块应用 |
| 基于功能的延迟加载 | 仅核心内容 | 按需 | 含可选功能的应用 |
Brotli 预压缩
Brotli 预压缩可将 WASM 下载大小减少 60-80%。Blazor WASM 会在发布期间自动生成 Brotli 压缩文件。
工作原理
执行 dotnet publish 时,Blazor WASM 会为 _framework/ 中的所有静态文件生成 .br(Brotli)和 .gz(gzip)压缩版本。浏览器支持时,Web 服务器会提供预压缩文件。
# After publish, check compressed sizes
ls -la bin/Release/net8.0/publish/wwwroot/_framework/
# You'll see:
# MyApp.wasm (original)
# MyApp.wasm.br (Brotli compressed, ~60-80% smaller)
# MyApp.wasm.gz (gzip compressed, ~50-70% smaller)
服务器配置
Web 服务器必须配置为提供预压缩文件。大多数 Blazor 托管配置都会自动处理此项。
ASP.NET Core 托管:
// In the server project hosting Blazor WASM
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
// Blazor framework files are served with compression headers automatically
Nginx:
location /_framework/ {
# Serve Brotli-compressed files when available
gzip_static on;
brotli_static on;
# Set correct MIME types
types {
application/wasm wasm;
}
# Cache aggressively (files are content-hashed)
add_header Cache-Control "public, max-age=31536000, immutable";
}
Azure Static Web Apps / GitHub Pages:
存在 Accept-Encoding: br 标头时,会自动提供预压缩的 .br 文件。
压缩效果
| 内容 | 原始大小 | Brotli(.br) | 缩减比例 |
|---|---|---|---|
| .NET WASM 运行时 | ~2.5 MB | ~0.8 MB | ~68% |
| 应用程序集(IL) | 不定 | 小约 70% | ~70% |
| 应用程序集(AOT) | 不定 | 小约 65% | ~65% |
| JavaScript 胶水代码 | ~100 KB | ~25 KB | ~75% |
禁用压缩(很少需要)
<PropertyGroup>
<BlazorEnableCompression>false</BlazorEnableCompression>
</PropertyGroup>
WASM 大小优化清单
- 启用裁剪 -- 在 AOT 编译前移除未使用的 IL
- 使用延迟加载 -- 推迟加载非关键程序集
- 启用 Brotli 预压缩 -- 将传输大小减少 60-80%(默认开启)
- 选择性使用 AOT -- 仅对性能关键程序集进行 AOT 编译
- 如果不需要特定于区域性的格式化,请启用不变区域性:
<PropertyGroup> <InvariantGlobalization>true</InvariantGlobalization> </PropertyGroup> - 移除未使用的框架功能:
<PropertyGroup> <EventSourceSupport>false</EventSourceSupport> <HttpActivityPropagationSupport>false</HttpActivityPropagationSupport> </PropertyGroup> - 验证压缩文件是否已提供 -- 在浏览器开发者工具的 Network 选项卡中检查
content-encoding: br
Agent 注意事项
- 不要混淆
RunAOTCompilation和PublishAot。 Blazor WASM 使用RunAOTCompilation进行 WASM AOT。PublishAot用于服务器端 Native AOT,会生成另一种类型的二进制文件。 - 不要认为 AOT 会减小 WASM 下载大小。 AOT 会增加构建产物大小,因为原生 WASM 代码比 IL 字节码更大。使用裁剪来减小大小,使用 AOT 来提高运行速度。
- 测试 AOT 时别忘了发布。 WASM AOT 仅在执行
dotnet publish时运行,不会在dotnet run时运行。调试版本始终使用 IL 解释执行。 - 不要延迟加载启动时需要的程序集。 仅对初始导航后才会访问的功能延迟加载程序集。加载延迟程序集会触发网络请求。
- 不要跳过 Brotli 压缩验证。 确保 Web 服务器提供
.br文件。没有压缩时,WASM 下载量会比所需大小大 3-5 倍。检查浏览器开发者工具中的content-encoding: br标头。 - 下载大小很重要时,不要对所有程序集进行 AOT 编译。 使用
BlazorWebAssemblyLazyLoad推迟加载非关键程序集 -- 延迟加载的程序集使用 IL 解释执行,而不是 AOT。