Blazor WebAssembly — AOT Compilation and Link Trimming (v22.2)

ASP.NET Team Blog
16 March 2023

As you may already know, we recently introduced (v22.2) ahead-of-time (AOT) compilation support for .NET 7-based applications. AOT compilation allows you to improve Blazor WebAssembly application performance at the expense of larger app size.

In this blog post, we’ll describe AOT compilation and link trimming support for DevExpress Blazor UI components.

Ahead-of-Time Compilation

To begin, let’s first examine AOT compilation itself. By default, a browser runs Blazor WebAssembly apps using an IL interpreter. Interpreted code is generally slower when compared to Blazor Server-based apps. When ahead-of-time compilation is enabled, application code is compiled directly into native WebAssembly code on a developer machine or a build server. This enables native WebAssembly execution by the browser on client machines. Refer to the following Microsoft document for more information on AOT: Ahead-of-time (AOT) compilation.

To enable AOT compilation, set the RunAOTCompilation property to true in your Blazor WebAssembly app's project file. You can open this file by clicking Edit Project File in the project's context menu:

Edit the Application's Project File
<PropertyGroup>
    <RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>

Because of the time involved (for AOT compilation), Visual Studio will not initiate compilation until you publish a project. To start the publishing process, right-click your project in Solution Explorer and choose Publish:

Publish a Project

Alternatively, execute the following command in the .NET CLI:

dotnet publish -c Release

To see how AOT affects performance, we measured various Blazor Grid (DXGrid) operations in a WebAssembly app (DxGrid was rendered with 5000 cells). Test results were as follows:

Operation AOT Disabled AOT Enabled
DxGrid - Filtering 100k rows 220 ms 117 ms
DxGrid - Paging 900 ms 570 ms
DxGrid - Selecting a row 320 ms 85 ms
DxGrid - Sorting 100k rows 1000 ms 950 ms
Switching to another web page 735 ms 420 ms

As you can see, AOT optimization results vary from one operation to another. However, the benefits of AOT far outweigh its drawbacks. We’ve already received positive feedback from customers. Some have even reported a 10x increase in app performance after enabling AOT.

Link Trimming

Speaking of drawbacks, AOT-compiled apps are larger, so they usually take longer to download to the client (first request). To address this, hosting servers compress Blazor WebAssembly app files before transfer. In addition, you can enable link trimming - which removes unused portions of a given library from your app.

Link trimming is enabled in .NET 7 Blazor WebAssembly projects by default. However, not all .NET libraries support trimming or enable it by default.

For our v22.2 release cycle, we added link trimming support for our largest library - DevExpress.Data (Blazor WebAssembly apps). This option is disabled by default, because the DevExpress.Data library is used on other platforms, where trimming can produce unexpected results.

To enable trimming for DevExpress.Data, configure trimming settings in the application's project file as follows:

<ItemGroup>
    <TrimmableAssembly Include="DevExpress.Data.v22.2" />
    <TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>

Once configured, create the MyRoots.xml file in the project’s root folder. Add the following content to the newly created file:

<linker> 
    <assembly fullname="System.Runtime">
        <type fullname="System.DateOnly" />
        <type fullname="System.TimeOnly" /> 
    </assembly> 
    <assembly fullname="DevExpress.Data.v22.2">
        <type fullname="DevExpress.Data.Helpers.crtp_*" />
        <type fullname="DevExpress.Data.Helpers.ExpressiveGroupHelpers/crtp_*" />
        <type fullname="DevExpress.Data.Helpers.ExpressiveSortHelpers/crtp_*" />
        <type fullname="DevExpress.Data.Helpers.GenericDelegateHelper/crtp_*" />
        <type fullname="DevExpress.Data.Helpers.GenericEnumerableHelper/crtp_*" />
        <type fullname="DevExpress.Data.Helpers.SummaryValueExpressiveCalculator/crtp_*" />
        <type fullname="DevExpress.Data.Helpers.TreeListNodeComparerBase/crtp_*" />
        <type fullname="DevExpress.Data.Helpers.UnboundSourceCore/UnboundSourcePropertyDescriptor/crtp_*" />
        <type fullname="DevExpress.Data.ListSourceDataController" />
        <type fullname="DevExpress.Data.VisibleListSourceRowCollection/crtp_*" />
        <type fullname="DevExpress.Internal.WeakEventHandler`3">
            <method name="CreateDelegate" />
        </type> 
    </assembly>
</linker>

The impact of link trimming will vary from one app to another (based on libraries referenced and controls/features used within the app). The more controls/features used, the less removed through link trimming.

To demonstrate the effect of AOT and link trimming, we measured the size of a Blazor WebAssembly test app with DevExpress Grid, Editors, and Navigation components:

Trimming Disabled Trimming Does Not Include DevExpress.Data Trimming Includes DevExpress.Data
AOT Disabled 55 MB 43.9 MB 39.9 MB
AOT Enabled 188 MB 152 MB 137 MB

As I mentioned a moment ago, Blazor WebAssembly files are transferred to the client in a compressed form. The table below lists transfer sizes for the same test app:

Trimming Disabled Trimming Does Not Include DevExpress.Data Trimming Includes DevExpress.Data
AOT Disabled 21.4 MB 17.3 MB 16.2 MB
AOT Enabled 45.3 MB 37.1 MB 34 MB

Your Feedback Counts

As always, we welcome your thoughts/comments. Please take a moment to answer the following Blazor-related survey questions:

Free DevExpress Products - Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We'll be happy to follow-up.