Blazor WebAssembly on .NET6 の wasm-tools によるランタイム再リンクで、コンテンツサイズがどれくらい小さくなるか?

# wasm-tools ワークロードと "ランタイムの再リンク"

Blazor WebAssembly プログラミングにおける WebAssembly 周辺・ネイティブ依存関係の諸機能が、.NET 6 でずいぶんと強化されました。

それを可能にするワークロード、**`wasm-tools` ワークロード**がインストールされていると、特段、AOT やネイティブ依存機能を使っていなくても、Blazor WebAssembly プロジェクトの Release 発行時、**"ランタイムの再リンク"** が発動します (`wasm-tools` ワークロードがインストールされているだけで発動します)。
結果、その Blazor WebAssembly アプリの**発行後ファイルサイズの縮小**につながります。

詳細は、公式ブログの記事が参考になります。

https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-net-6-rc-2/#native-dependencies-support-for-blazor-webassembly-apps

ということで、以前に投稿した、Blazor WebAssembly on .NET 6 製の "snow catch" ゲームを使って、"ランタイムの再リンク" によって、どれくらいファイルサイズ (ダウンロードサイズ) が小さくなるのか、試してみました。

なお、前述の snow catch ゲームは、GitHub Actions 経由で GitHub Pages にも配置しています。

https://sample-by-jsakamoto.github.io/SnowCatch-on-BlazorWasm/

これに基づいて計測してみることにしました。

# wasm-tools 導入前

まずは `wasm-tools` 導入前のダウンロードサイズを、ブラウザの開発者ツール画面を見て確認してみます。

すると、下図のとおりダウンロードサイズ (通信量) は **1.9 MB**、`dotnet.wasm` (Brotli 圧縮済み) のサイズは **852 KB** 程となっています。

![blazor-snow-catch - download size - before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/056b833d-ad40-4ffc-172d-203cdfb17cbf.png)

# wasm-tools 導入後

では GitHub Actions で定義している発行スクリプトを改訂し、`wasm-tools` を導入して発行するようにしましょう。
GitHub Actions スクリプト (.yml) に、以下のように、`wasm-tools` をインストールするステップ、すなわち、`dotnet workload install wasm-tools` コマンドの実行を追加します。

```yaml:.yml
...
# Install .NET Core SDK
- name: Setup .NET Core
  uses: actions/setup-dotnet@v1
  with:
    dotnet-version: 6.0.100
  # 👇 .NET SDK インストールのあとに、下記 2行を追記する
- name: Install .NET WebAssembly Tools
  run: dotnet workload install wasm-tools
...
```

(※ローカル開発環境に `wasm-tools` ワークロードをインストールするには、Linux 等であれば `sudo dotnet workload install wasm-tools`、Windows であれば管理者権限を有効にしたターミナル内で `dotnet workload install wasm-tools` を実行する必要があるそうです。Windows で Visual Studio 2022 を使っている場合は、Visual Studio 2022 のインストールオプションとして ".NET WebAssembly build tools" を指定することでもよいようです)

以上のとおり、GitHub Actions スクリプトを改訂し、発行されたあとのダウンロードサイズを確認してみます。

![blazor-snow-catch - download size - after wasm-tools.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/a62663dc-1a68-a09c-7932-2aba09c3cff3.png)

すると、上図のとおりダウンロードサイズ (通信量) は **1.8 MB**、`dotnet.wasm` (Brotli 圧縮済み) のサイズは **794 KB** 程となっています。

なお、wasm-tools 導入前のダウンロードサイズ (通信量) は **1.9 MB**、`dotnet.wasm` (Brotli 圧縮済み) のサイズは **852 KB** 程ですので、たしかにサイズ縮小の傾向にはあります。

とはいえども、**そこまで劇的な縮小幅ではない印象**ですね (`dotnet.wasm` で 58KB 程減に留まる)。

# カルチャ対応もタイムゾーンも捨ててみると...

さてところで、実装する Web アプリの要件では、カルチャ依存がなかったり、タイムゾーン情報が一切不要だったりする場合もじゅうぶんあり得るかと思います。

そのような場合、Blazor WebAssembly アプリケーションのビルド・発行指定として、**「カルチャ依存不要」「タイムゾーン情報不要」**を明示することができます。
そうすることで、カルチャに関わるデータをランタイムから削減することができるため、Blazor WebAssembly アプリのサイズを**さらに縮小**することができます。

具体的には、プロジェクトファイル (.csproj) 中で、以下の MSBuild プロパティ値を設定してやればよいです。

```xml:.csproj
...
<PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <!-- 👇 以下 2行を追加 -->
    <InvariantGlobalization>true</InvariantGlobalization>
    <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
  </PropertyGroup>
  ...
```

上図のとおりプロジェクトファイルを改訂し、発行されたあとのダウンロードサイズを確認してみます。

![blazor-snow-catch - download size - after removed unused features.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/05d9c576-ca6f-9185-5df9-f77792b7df95.png)

すると、上図のとおりダウンロードサイズ (通信量) は **1.2 MB**、`dotnet.wasm` (Brotli 圧縮済み) のサイズは **353 KB** 程となっています。

`wasm-tools` 導入前のダウンロードサイズ (通信量) は **1.9 MB**、`dotnet.wasm` (Brotli 圧縮済み) のサイズは **852 KB** 程ですから、これと比べると、かなり良い感じで小さくなったのではないでしょうか。

ダウンロードサイズはおおよそ **37 % 削減**です。
内訳としては、`dotnet.wasm` (Brotli 圧縮済みのサイズで) については約 59 % 削減、タイムゾーン情報を不要としたので、`dotnet.timezone.blat` (Brotli 圧縮済みのサイズで) 約 44KB のダウンロードもなくなっています。

# まとめ

"snow catch" ゲームに対し、`wasm-tools` ワークロードを導入したり、カルチャ依存やタイムゾーン情報を捨ててみたりすることで、ダウンロードサイズがどれくらい小さくなるか、実測してみました。

結果、"snow catch" ゲームにおいては、なかなかいい感じでダウンロードサイズを 1.9 MB から 1.2 MB にまで縮小できました。

しかしながら、実用的な Web アプリと比べると、"snow catch" ゲームは遙かに小さなプログラム規模です。
ですので、実際的な場面では本記事のような削減幅には至らないことが充分予想されます。

それでもなお、今回の実測結果が、多少なりともなんらかの参考値・指標になれば幸いです。😊