Enable ahead-of-time (AOT) compilation for Blazor WebAssembly

Blazor WebAssembly facilitates the development of SPAs (Single-page applications) that run in the browser using C# instead of JavaScript as the primary programming language.

Executing C# code in the browser is a rather neat trick, made possible via the revolutionary WebAssembly technology which is an open web standard. However, the default mechanism employed by Blazor to achieve this is not the most optimal for runtime performance. By default, when you publish your Blazor WebAssembly application, a WebAssembly-compiled version of .NET (Mono) is downloaded to the browser and is used to run your .NET libraries via IL (Intermediate Language) interpretation.

Although the default approach performs well in many scenarios, it can be relatively slow when performing intensive work or rendering complex user interfaces. Thankfully, there is a way to greatly improve the performance of complex Blazor WebAssembly applications using ahead-of-time (AOT) compilation.

This article will explain how to enable AOT compilation for your project as simply as possible and will also cover how to make the process configurable when implementing continuous deployment.

Some considerations

Before jumping into the AOT compilation configuration steps, I would like to briefly discuss some considerations you should make before deciding to enable AOT compilation for your project.

Application size

First of all, enabling AOT compilation will increase the overall size of your application, since the compiled WebAssembly code isn’t as compact as the .NET IL (Intermediate Language) instructions. You will find that your application will likely double in size after enabling AOT compilation. Naturally, this will result in a slower start-up experience for users. However, it shouldn’t be a huge concern for line-of-business applications, since the application files will be cached after the initial download.

Publish duration

Secondly, the AOT compilation process is intensive. This means that publish times will increase quite significantly. You can expect deploying your application to take 3-4 times longer. In cases where you deploy code to multiple environments, you will likely want to consider enabling AOT compilation only for the environments that particularly need it. For example, the QA (Quality Assurance) testing environment or the final production environment.

Performance

Lastly, AOT compilation can make a huge difference to the performance of your application. The performance benefits are likely to be most noticeable in areas of your application that render many components on a single page and for computationally intensive tasks that run on the front end. You’ll likely notice an even bigger difference on less powerful devices and your application should feel smoother across the board.


After reviewing the above considerations, if you’re convinced that enabling AOT compilation for your Blazor WebAssembly project is right for you, I invite you to proceed to the next section!

Enabling AOT compilation

Let’s enable AOT compilation for a Blazor WebAssembly project.

In the subsections that follow, I’m using Visual Studio and targeting the latest version of .NET which is 8.0 at the time of writing.

Project configuration

You can enable AOT compilation for your Blazor WebAssembly project via the Visual Studio tooling.

Assuming that you have your Blazor solution opened in Visual Studio, right-click on the Client (WebAssembly) project and select the ‘Properties’ option from the context menu to open the Properties window shown in the screenshot below.

Visual Studio - Project Properties
Visual Studio – Project Properties

If you search the Project Properties using the text ‘aot’ you should find that two properties are returned as shown above.

You should select the ‘Ahead-of-time (AOT) compilation’ checkbox which will apply the option immediately.

Note that the ‘Publish native AOT’ option is a separate thing you could consider enabling for your .NET APIs. The ‘Ahead-of-time (AOT) compilation’ option is the one we need for the Blazor WebAssembly AOT compilation.

Enabling the ‘Ahead-of-time (AOT) compilation’ in the Project Properties will automatically add the following two PropertyGroup sections to your Blazor WebAssembly project (.csproj) file.

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <RunAOTCompilation>True</RunAOTCompilation>
  </PropertyGroup>
 
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <RunAOTCompilation>True</RunAOTCompilation>
  </PropertyGroup>

Note that you can double-click on your Blazor WebAssembly project node in Visual Studio to open the .csproj file and edit it directly within Visual Studio.

I recommend that you remove the first property group so that the AOT compilation will only run for Release builds.

As indicated in the Project Properties help text, the AOT compilation will run when the project is published.

Publishing

At this stage, you can test out the AOT compilation locally by publishing your project via Visual Studio.

Publish via Visual Studio

To publish via Visual Studio, right-click on the main Blazor project and select the ‘Publish…’ option from the context menu to open the Publish window shown in the screenshot below.

Visual Studio - Publish Target
Visual Studio – Publish Target

Note that for an ASP.NET Core Hosted Blazor WebAssembly app, the ‘main Blazor project’ will be the back-end API project, otherwise, it is the front-end client project you will need to publish.

Select the ‘Folder’ option from the list of Targets and press the ‘Next’ button.

Visual Studio - Publish Location
Visual Studio – Publish Location

You can accept the default output Location and press the ‘Finish’ button.

After the publishing setup process has finished and you close the Publish dialog, you will be brought back to the Publish window in Visual Studio.

Press the ‘Publish’ button to publish your project to the “bin\Release\net8.0\publish” folder. This may take a while depending on the size and complexity of your application.

After publishing has been completed, you can navigate to the publish directory and launch your application to check that it works locally before deploying it elsewhere (e.g. to a web server).

Publish error

You may receive the following error when attempting to publish your application.

NETSDK1147 To build this project, the following workloads must be installed: wasm-tools
To install these workloads, run the following command: dotnet workload restore

To fix the error, you can run the following command via the integrated Visual Studio terminal (View –> Terminal).

dotnet workload install wasm-tools

Note that you may receive a UAC (User Account Control) prompt which you will need to acknowledge.

Restart Visual Studio after the installation process has been completed.

If you try publishing the project again, you should find that the publishing finishes successfully.

Continuous deployment

If you use a platform such as Azure DevOps to enable continuous deployment for your application, you can integrate the AOT compilation into your build pipeline as an optional process.

Project file update

To make the AOT compilation configurable you can use a variable in your project file, as shown below.

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <RunAOTCompilation>$(EnableAOTCompilation)</RunAOTCompilation>
  </PropertyGroup>

In this case, the AOT compilation will only run if EnableAOTCompilation is set to ‘true’.

Publish

To enable the AOT compilation with the above changes in place, as part of a simple build script, we could run the following dotnet command.

dotnet publish -c Release -p:EnableAOTCompilation=true

This will publish in Release mode and set the ‘EnableAOTCompilation’ property to ‘true’.

If you prefer more explicit naming, you can do the following to achieve the same result.

dotnet publish --configuration Release --property:EnableAOTCompilation=true

It is easier to understand the nature of the command-line switches at a glance in this example.

Pipeline

To configure the optional AOT compilation in an Azure DevOps pipeline file, you could set the property via a parameter value, as shown in the following YAML file.

trigger:
- main
 
pool:
  vmImage: 'ubuntu-latest'
 
parameters:
- name: enableAOTCompilation
  type: boolean
  default: true
 
variables:
  BuildConfiguration: Release
 
steps:
- task: DotNetCoreCLI@2
  inputs:
    command: 'publish'
    projects: 'src/BlazorDemo/BlazorDemo.Api.csproj' # Path to your main Blazor project.
    arguments: '--configuration $(BuildConfiguration) --property:EnableAOTCompilation=${{ parameters.enableAOTCompilation }} --output $(Build.ArtifactStagingDirectory)'
  displayName: 'Publish'

Note that the above pipeline file is for illustration purposes only. You will likely want to include several other steps as part of your automated build process such as running tests etc.

In the above example, a ‘DotNetCoreCLI@2’ task has been defined within the ‘steps’ section of the pipeline file.

The task has been configured to call the publish command for the main Blazor project and the EnableAOTCompilation property is passed along as an argument, with its value being set according to the enableAOTCompilation pipeline parameter, which has a default value of true.

As mentioned in a previous section, the main project for an ASP.NET Core Hosted Blazor WebAssembly app will be the back-end API project, otherwise, it is the front-end client project that you should specify for the projects property.

Summary

In this article, I have covered how to enable ahead-of-time (AOT) compilation for a Blazor WebAssembly application.

I started by discussing some considerations that should be made before deciding to enable AOT compilation for your project, including application size, publish duration, and performance.

I then walked through the changes you need to make in the Blazor WebAssembly project to enable the AOT compilation.

Following this, I explained how to publish your project locally to test it out.

Finally, I looked at how you can optionally enable the AOT compilation as part of a continuous deployment process within an Azure DevOps Pipeline.


I hope you enjoyed this post! Comments are always welcome and I respond to all questions.

If you like my content and it helped you out, please check out the button below 🙂

Comments