.NETWebAssemblyAOT编译优化 dotnet-aot-wasm

此技能涉及将 .NET 代码通过 AOT 编译为 WebAssembly,应用于 Blazor 和 Uno WASM 前端框架,优化应用程序的下载大小和运行时性能。包括修剪、懒加载和 Brotli 压缩等关键技术,支持 SEO 关键词如 .NET、WebAssembly、AOT、Blazor、Uno、大小优化、速度优化。

前端开发 0 次安装 0 次浏览 更新于 3/6/2026

名称:dotnet-aot-wasm 描述:“将 .NET 编译到 WebAssembly AOT。Blazor/Uno WASM,大小与速度权衡,懒加载,Brotli。” 用户可调用:false

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 大)但 改善 运行时执行速度。结合使用两者以达到最佳平衡。

范围

  • 下载大小与运行时速度权衡分析
  • Blazor WASM AOT(RunAOTCompilation、选择性 AOT)
  • Uno WASM AOT(.NET 8+ 标准工作负载)
  • 懒加载程序集以减少大小
  • Brotli 预压缩用于下载优化
  • WASM 大小优化检查清单

范围外

  • 服务器端 .NET 的本地 AOT – 参见 [技能:dotnet-native-aot]
  • AOT 优先设计模式 – 参见 [技能:dotnet-aot-architecture]
  • 修剪安全库编写 – 参见 [技能:dotnet-trimming]
  • MAUI 特定 AOT – 参见 [技能:dotnet-maui-aot]
  • Blazor 托管模型和渲染模式 – 参见 [技能:dotnet-blazor-patterns]
  • Blazor 组件生命周期和 JS 互操作 – 参见 [技能:dotnet-blazor-components]
  • Uno Platform 架构 – 参见 [技能:dotnet-uno-platform]

交叉参考: [技能:dotnet-native-aot] 用于通用 AOT 流水线,[技能:dotnet-trimming] 用于修剪注释,[技能:dotnet-aot-architecture] 用于 AOT 安全设计模式,[技能:dotnet-serialization] 用于 AOT 安全序列化,[技能:dotnet-csharp-source-generators] 用于源生成作为 AOT 启用器,[技能:dotnet-blazor-patterns] 用于 Blazor 架构(软),[技能: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 应用: IL 解释对 UI 交互和 API 调用足够快
  • 快速迭代: AOT 编译增加显著发布时间

Blazor WASM AOT

启用 AOT

<!-- Blazor WASM .csproj -->
<PropertyGroup>
  <RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>
# 使用 AOT 发布(必需 -- AOT 仅在发布期间应用)
dotnet publish -c Release

注意:RunAOTCompilation 是 Blazor WASM 属性(非 PublishAot,后者用于服务器端本地 AOT)。AOT 编译仅在 dotnet publish 期间发生,不在 dotnet rundotnet build 期间。

通过懒加载进行选择性 AOT

Blazor WASM AOT 编译所有非懒加载程序集。要控制哪些程序集 AOT 编译,将非关键程序集标记为懒加载 – 它们将使用 IL 解释代替:

<PropertyGroup>
  <RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>

<ItemGroup>
  <!-- 这些程序集不 AOT 编译(通过 IL 解释器按需加载) -->
  <BlazorWebAssemblyLazyLoad Include="MyApp.Reporting.wasm" />
  <BlazorWebAssemblyLazyLoad Include="MyApp.Admin.wasm" />
  <!-- 所有其他程序集(MyApp.Core、MyApp.Calculations 等)AOT 编译 -->
</ItemGroup>

修剪 + AOT 结合

为最佳平衡,同时使用修剪和 AOT:

<PropertyGroup>
  <!-- 修剪减少未使用代码(更小下载) -->
  <PublishTrimmed>true</PublishTrimmed>

  <!-- AOT 编译剩余代码到原生 WASM(更快执行) -->
  <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+)

<!-- Uno WASM 头 .csproj -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0-browserwasm'">
  <RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>

旧版 Uno 使用 Uno.Wasm.Bootstrap 具有单独的 WasmShellMonoRuntimeExecutionMode 属性,带有 InterpreterInterpreterAndAOTFullAOT 模式。在 .NET 8+,使用 RunAOTCompilation 代替。

Uno WASM 中的修剪

<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
  <TrimMode>link</TrimMode>
</PropertyGroup>

参见 [技能:dotnet-uno-platform] 用于 Uno Platform 架构模式。


懒加载程序集

懒加载推迟下载程序集直到需要,减少初始下载大小。这在结合 AOT(增加每程序集大小)时特别有效。

Blazor WASM 懒加载

<!-- 在 .csproj 中标记程序集为懒加载 -->
<ItemGroup>
  <BlazorWebAssemblyLazyLoad Include="MyApp.Reporting.wasm" />
  <BlazorWebAssemblyLazyLoad Include="MyApp.Admin.wasm" />
  <BlazorWebAssemblyLazyLoad Include="ChartLibrary.wasm" />
</ItemGroup>
// 在组件或路由器中按需加载程序集
@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);
    }
}

基于路由器的懒加载

<!-- App.razor -->
@inject LazyAssemblyLoader LazyLoader

<Router AppAssembly="typeof(App).Assembly"
        AdditionalAssemblies="@_lazyLoadedAssemblies"
        OnNavigateAsync="@OnNavigateAsync">
    <Navigating>
        <div class="loading">加载模块...</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 预压缩通过 60-80% 减少 WASM 下载大小。Blazor WASM 在发布期间自动生成 Brotli 压缩文件。

工作原理

dotnet publish 期间,Blazor WASM 为 _framework/ 中所有静态文件生成 .br(Brotli)和 .gz(gzip)压缩版本。当浏览器支持时,Web 服务器提供预压缩文件。

# 发布后,检查压缩大小
ls -la bin/Release/net8.0/publish/wwwroot/_framework/

# 您会看到:
# MyApp.wasm       (原始)
# MyApp.wasm.br    (Brotli 压缩,约 60-80% 更小)
# MyApp.wasm.gz    (gzip 压缩,约 50-70% 更小)

服务器配置

Web 服务器必须配置为提供预压缩文件。大多数 Blazor 托管设置自动处理此。

ASP.NET Core 托管:

// 在托管 Blazor WASM 的服务器项目中
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
// Blazor 框架文件自动以压缩头提供

Nginx:

location /_framework/ {
    # 当可用时,提供 Brotli 压缩文件
    gzip_static on;
    brotli_static on;

    # 设置正确 MIME 类型
    types {
        application/wasm wasm;
    }

    # 积极缓存(文件内容哈希)
    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%

禁用压缩(很少需要)

<!-- 禁用 Brotli 预压缩 -->
<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. 验证压缩被提供 – 检查浏览器 DevTools 网络标签中的 content-encoding: br

代理常见错误

  1. 不要混淆 RunAOTCompilationPublishAot Blazor WASM 使用 RunAOTCompilation 用于 WASM AOT。PublishAot 用于服务器端本地 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 倍。检查浏览器 DevTools 中的 content-encoding: br 头。
  6. 当下载大小重要时,不要 AOT 编译所有程序集。 使用 BlazorWebAssemblyLazyLoad 推迟非关键程序集 – 懒加载程序集使用 IL 解释代替 AOT。

参考资料