В .NET 6 запланирована поддержка AOT компиляции для Blazor WebAssembly приложений. Давайте попробуем запустить в Preview 2 версии.
Анонса и инструкций пока что нету. Поэтому и решено написать этот пост.
Краткая справка
Немного восстановим в памяти.
Blazor - Single Page Application веб-фреймворк от Майкрософт. Отличительная особенность: за динамику отвечает C#, а не привычный нам JavaScript.
Существует две версии:
Blazor Server. Код запускается на сервере, страница рендерится на сервере. Через веб-сокеты передаем измененную часть страницы и с помощью JS обновляем html в браузере. Здесь нам AOT не интересен.
Blazor WebAssembly. В браузере на WebAssembly запускается порезанная версия Mono. А уже на Mono запускается наше .NET приложение. Рендеринг страницы и вся логика в браузере. Сервер нужен только чтобы отдать скомпилированную статику.
Пытливый читатель сразу предположит, что наверняка мы теряем в скорости из-за дополнительной прослойки WebAssembly-Mono-Наше приложение. И будет прав! Именно для этого нам и нужна Ahead-of-Time компиляция, которая позволяет из .NET приложения сразу скомпилировать версию для WebAssembly.
Инструкция по запуску
Здесь нам важно использовать именно указанные версии. Потому что шаг влево, шаг вправо - не работает. И не всегда получается разобраться почему. Если вы читаете этот пост сильно позже марта 2021, то вероятно стоит поэкспериментировать с более свежими версиями.
Я все делал на Windows. В теории на других ОС тоже должно работать.
Устанавливаем SDK 6.0.100-preview.2. Просто скачать и запустить установщик.
Устанавливаем Emscripten. Это как раз и есть компилятор в WebAssembly.
Шаги для установки:
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
emsdk install 2.0.12
emsdk activate 2.0.12
emsdk_env.bat
Теперь консоль можно закрыть и в Environment Variables надо добавить EMSDK_PATH с путем до папки emsdk.
Инструкция для установки на других ОС. Версию 2.0.12 используем по совету.
Ставим пакет dotnet-install-blazoraot. Этот пакет как раз подружит dotnet и emscripten.
dotnet tool install -g dotnet-install-blazoraot --version 6.0.0-*
dotnet install-blazoraot
В одном из пакетов есть баг, он уже пофикшен в репозитории, но еще не выпущен. Так что пока что придется подправить локально.
В файле C:\Program Files\dotnet\packs\Microsoft.NET.Runtime.WebAssembly.Sdk\6.0.0-preview.2.21154.6\Sdk\WasmApp.targets меняем строчку 244 на:
<Exec Condition="'$(WasmLinkIcalls)' == 'true'" Command=""$(MonoAotCrossCompilerPath)" --print-icall-table > $(_WasmIntermediateOutputPath)/runtime-icall-table.h" />
С подготовкой мы закончили. Можем создать первое приложение:
mkdir myapp
cd myapp
dotnet new blazorwasm
И нам надо сконфигурировать RunAOTCompilation в csproj:
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference
Include="Microsoft.AspNetCore.Components.WebAssembly"
Version="6.0.0-preview.2.21154.6" />
<PackageReference
Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer"
Version="6.0.0-preview.2.21154.6" PrivateAssets="all" />
</ItemGroup>
<PropertyGroup>
<RunAOTCompilation>true</RunAOTCompilation>
</PropertyGroup>
</Project>
AOT компиляция будет работать только во время публикации. Поэтому публикуем приложение:
dotnet publish
Первые впечатления
Компиляция занимает значительное время. Нечто простое всего несколько минут. А вот один далеко не самый большой проект у меня компилируется полчаса.
Скомпилированный dotnet.wasm файл даже для дефолтного приложения 15 мб. Я легко получал и 50 и 60 мб. Это ожидаемо.
Элементарные события, например, клики на кнопки срабатывают, но в консоль сыпят ошибками. Асинхронные обработчики не работают. Пока что не получилось разобраться почему. Присоединяйтесь :)
НО! Скорость действительно заметно быстрее.
Я сделал эксперимент с одной из вычислительных задач: поиск простого числа. С AOT выходит в 3 раза меньше времени!
Для желающих самостоятельно проверить есть два одинаковых приложения.
Заключение
Чуда не случилось. Придется оптимизировать имеющийся код :)
Вся эта история еще в самом начале пути. В ближайшие полгода, думаю, не стоит рассчитывать на легкий способ увеличить производительность своих приложений.
Но эксперимент очень интересный. Посмотрим, куда приведет и что получится.
bcwd
При публикации .NET приложений можно указывать опции чистки неиспользуемого кода, не пробовали их использовать в Blazor приложениях?
JacobL Автор
Ага, IL Linker может вырезать неиспользуемый код. Соответсвенно, мы можем сэкономить на размере dll. На мелких приложениях вполне отлично работает. Крупные приложения у нас по исторический причинам завязаны на рефлекшн, поэтому приходится запрещать :( Я, кстати, думаю, что по дефолту IL Linker вырезает.