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:
<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:
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: