Blazor WebAssembly (client-side) with AOT and SkiaSharp

As we’re working to stabilize our .NET 5 support for Uno Platform, and particularly Full AOT and Profile Guided AOT, it seemed natural to experiment and validate if the work we’ve been doing could also benefit Blazor. There is always something we learn when we experiment and help push the WebAssembly toolchain forward, so top-notch tooling is available as soon as possible.

It turns out that enabling AOT and native linking in Blazor WebAssembly (client-side) can work, producing as you’d expect, some great performance benefits! If you are like us and like to experiment with WebAssembly, read on to see how we turned AOT on for Blazor WebAssembly. Here it is running on our server. Make sure you run the sample more than once, just to also experience the performance difference you get with initial load vs cached WebAssembly applications.


About Uno Platform

For those new to Uno Platform – it allows for creation of pixel-perfect, single-source C# and XAML apps which run natively on Windows, iOS, Android, macOS, Linux and Web via WebAssembly. Uno Platform is free and Open Source (Apache 2.0) and available on GitHub.



We’ve built a simple sample “File New Project” template with Mixed Interpreter/AOT and Static Linking enabled, with a custom SkiaCanvas component providing the SkiaSharp support we introduced in Uno a year and half ago. Static linking gives a way to include code compiled in another languages (Rust, C, C++, etc…) to be used through .NET P/Invoke. This enables libraries like SQLite and Skia to be used from .NET apps.

You can see here the code for that page, which includes a callback to draw the Skia “sphere” from the official samples:

Breaking down .NET 6 AOT support

You’ll notice that the dotnet.wasm file is significantly larger, around 28MB uncompressed (8MB brotli compressed), up from 2MB uncompressed using interpreter only. There are two reasons for this. First, the app is built using Mixed Mode AOT, which takes parts of the IL and compiles it to WebAssembly, and second, the WebAssembly-compiled C++ libSkia is merged in.

All DLLs still contain the original IL, as some of the binaries cannot yet be compiled to AOT because of runtime issues. For instance, System.Text.Json or generic internal calls fail with runtime exceptions preventing the app to run. It’s also worth noting that all Blazor assemblies are excluded from the IL linker entirely, adding to the payload size.

The application starts faster with AOT than it does with the interpreter (1.4s vs. 2.5s), which is remarkable even with some assemblies still being fully interpreted.

Next Steps

The above experiment is not production ready. We welcome your ideas on how to push the WebAssembly toolchain further in our discord channel – — #Uno-Platform channel.

In addition, if you haven’t tried Uno Platform yet, please give it a go through this 2 minute tutorial.

Jerome Laban, CTO, Uno Platform

Share this post: