mcpField
D
dotnet-aot-wasm

dotnet-aot-wasm

github.com/wshaddix开发8671 次安装35 周前更新
代码仓库

关于 dotnet-aot-wasm

此技能介绍 Blazor WASM 和 Uno WASM 应用的 AOT 编译,帮助 .NET 开发者权衡下载体积与运行速度,并讲解裁剪、延迟加载和 Brotli 压缩。

主要功能

  1. 01比较 WASM 下载体积与运行速度
  2. 02配置 Blazor 和 Uno WASM AOT
  3. 03结合使用 AOT 与裁剪
  4. 04通过延迟加载推迟程序集下载
  5. 05使用 Brotli 预压缩优化传输

适用场景

  1. 01加速 CPU 密集型 WASM 工作负载
  2. 02平衡初始下载与运行性能
  3. 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 大小优化清单

  1. 启用裁剪 -- 在 AOT 编译前移除未使用的 IL
  2. 使用延迟加载 -- 推迟加载非关键程序集
  3. 启用 Brotli 预压缩 -- 将传输大小减少 60-80%(默认开启)
  4. 选择性使用 AOT -- 仅对性能关键程序集进行 AOT 编译
  5. 如果不需要特定于区域性的格式化,请启用不变区域性:
    <PropertyGroup>
      <InvariantGlobalization>true</InvariantGlobalization>
    </PropertyGroup>
    
  6. 移除未使用的框架功能:
    <PropertyGroup>
      
      <EventSourceSupport>false</EventSourceSupport>
      <HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
    </PropertyGroup>
    
  7. 验证压缩文件是否已提供 -- 在浏览器开发者工具的 Network 选项卡中检查 content-encoding: br

Agent 注意事项

  1. 不要混淆 RunAOTCompilation 和 PublishAot。 Blazor WASM 使用 RunAOTCompilation 进行 WASM AOT。PublishAot 用于服务器端 Native AOT,会生成另一种类型的二进制文件。
  2. 不要认为 AOT 会减小 WASM 下载大小。 AOT 会增加构建产物大小,因为原生 WASM 代码比 IL 字节码更大。使用裁剪来减小大小,使用 AOT 来提高运行速度。
  3. 测试 AOT 时别忘了发布。 WASM AOT 仅在执行 dotnet publish 时运行,不会在 dotnet run 时运行。调试版本始终使用 IL 解释执行。
  4. 不要延迟加载启动时需要的程序集。 仅对初始导航后才会访问的功能延迟加载程序集。加载延迟程序集会触发网络请求。
  5. 不要跳过 Brotli 压缩验证。 确保 Web 服务器提供 .br 文件。没有压缩时,WASM 下载量会比所需大小大 3-5 倍。检查浏览器开发者工具中的 content-encoding: br 标头。
  6. 下载大小很重要时,不要对所有程序集进行 AOT 编译。 使用 BlazorWebAssemblyLazyLoad 推迟加载非关键程序集 -- 延迟加载的程序集使用 IL 解释执行,而不是 AOT。

参考资料

评论

支持 Markdown