ASP.NET Core Blazor WebAssembly のプリレンダリングを試してみよう

以下の記事でも説明しているように、ASP.NET Core Blazor (以下 Blazor) には2つのホスティングモデルが存在します。

<a href="https://blogs.jp.infragistics.com/entry/2020/10/30/152834" target="_blank">ASP.NET Core Blazor - Blazor WebAssembly と Blazor Server の違いは？ ５つのポイント</a>

それぞれのホスティングモデルには長所と短所がありますので、Blazor プロジェクトを開始する際には、実装するアプリケーションの要件に適したホスティングモデルを選択することになります。
このうち Blazor WebAssembly を選択すると、作られるアプリケーションは、いわゆる SPA（シングルページアプリケーション）と呼ばれる、クライアント側でコードを実行する形となります。
以下の画像は Blazor WebAssembly で作成したアプリケーションの Counter ページ表示時のソースをブラウザから見たものですが、実際にページに表示されているメニューやボタンなどのHTML要素がソースには含まれていないことが分かります。

[![Image from Gyazo](https://i.gyazo.com/2486fac6767be9a1d52a5909f8dc7bcc.png)](https://gyazo.com/2486fac6767be9a1d52a5909f8dc7bcc)
[![Image from Gyazo](https://i.gyazo.com/927548cc5cca5adc95a86e246cec8b5b.png)](https://gyazo.com/927548cc5cca5adc95a86e246cec8b5b)

これは SPA の特徴で、ブラウザから対象のページに初めてリクエストが行われた際に返却されるのは、上記のソースが含まれた index.html のみです。その後、index.html で読み込まれた WebAssembly JavaScript ファイル (`_framework/blazor.webassembly.js`) によって .NET ランタイム、アプリ、およびアプリの依存関係のダウンロードと、アプリを実行するランタイムの初期化が行われ、ルーティングに基づいて対応するコンポーネントが描画されます。
初回リクエスト以降の処理は、すでにクライアント側にダウンロード済みのアプリケーションによって行われるため、2回目以降のやり取りが高速に行われることが期待できます。反面、初期ロードには時間がかかるためユーザーが途中で離脱してしまう可能性も高くなります。また、検索エンジンのクローラーにも同じように index.html が返されるため、SEO の面で弱点があると言われています。

[![Image from Gyazo](https://i.gyazo.com/3723cef4411686906faf3e592d823562.png)](https://gyazo.com/3723cef4411686906faf3e592d823562)

ちなみに、こちらは Blazor Server を選択した場合の同じ画面のソースです。サーバー側で実行されたあとの html であることが分かります。

このような SPA の弱点を補うために、プリレンダリングという手法があります。
プリレンダリングとは簡単に言うと、初回リクエスト時に返却するHTMLを空っぽの状態のものではなく、サーバ側で処理することによりリクエストに沿ったレンダリング済みのものとすることです。
これにより SPA の短所をカバーしつつ、2回目以降のリクエストはクライアント側で行うことで SPA の長所を活かすことができます。

本記事では、マイクロソフトの <a href="https://docs.microsoft.com/ja-jp/aspnet/core/blazor/components/prerendering-and-integration?view=aspnetcore-5.0&pivots=webassembly" target="_blank">公式ドキュメント</a> に沿って Blazor WebAssembly プロジェクトをプリレンダリングに対応する方法についてご紹介します。

## 新規プロジェクトの作成
[![Image from Gyazo](https://i.gyazo.com/b68a3cc0efca92e6d91f474673469159.png)](https://gyazo.com/b68a3cc0efca92e6d91f474673469159)

Blazor WebAssembly で新規プロジェクトを作成します。今回の実装は .NET 5 の選択が必要であることに注意してください。また、プロジェクト作成時の詳細設定で `ASP.NET Core hosted` にチェックを入れてください。

[![Image from Gyazo](https://i.gyazo.com/c9f76b436919816ce1c2cca8a7dcb23b.png)](https://gyazo.com/c9f76b436919816ce1c2cca8a7dcb23b)

新規プロジェクトを作成するとこのように、3つのプロジェクトが含まれたソリューションが作成されます。プリレンダリングを行うためにサーバ側の処理も必要となるため、サーバ用のプロジェクト（末尾 `.Server`）があることが分かります。次のセクションより、プリレンダリングを行うための変更を行っていきます。

## クライアント用プロジェクトの変更
### wwwroot/index.html の削除
[![Image from Gyazo](https://i.gyazo.com/f6617e7840734d2407d750bee930c34c.png)](https://gyazo.com/f6617e7840734d2407d750bee930c34c)

クライアント用プロジェクトの `wwwroot` ディレクトリにある `index.html` を削除します。

### Program.cs の変更

[![Image from Gyazo](https://i.gyazo.com/0beba872d95649bc77eea199c6743736.png)](https://gyazo.com/0beba872d95649bc77eea199c6743736)

```
builder.RootComponents.Add<App>("#app");
```

の記述を削除、またはコメントアウトします。

## サーバ用のプロジェクトの変更

### Pages/_Host.cshtml の追加

サーバ用プロジェクトの `Pages` ディレクトリに `_Host.cshtml` ファイルを新規作成し、以下の内容を追加します。

```
@page "/"
@namespace BlazorApp_WASM_PreRendering.Server.Pages
@using BlazorApp_WASM_PreRendering.Client
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = null;
}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>BlazorApp_WASM_PreRendering</title>
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazorApp_WASM_PreRendering.Client.styles.css" rel="stylesheet" />
</head>
<body>
    <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
```

### Startup.cs の変更

[![Image from Gyazo](https://i.gyazo.com/ee81f5e0c0f953e5025bb1ec02772e05.png)](https://gyazo.com/ee81f5e0c0f953e5025bb1ec02772e05)

`endpoints.MapFallbackToPage` の指定を `index.html` から先ほど作成した `_Host.cshtml` に変更します。

## プリレンダリングを確認する

以上で作業は完了です。サーバ用のプロジェクトを実行をして確認してみます。

[![Image from Gyazo](https://i.gyazo.com/69231629bd65652b123196c5d17d2f4c.png)](https://gyazo.com/69231629bd65652b123196c5d17d2f4c)

ソースを確認すると、レンダリング済みのものであることが分かります。

### プリレンダリング対応の Blazor WebAssembly VS Blazor WebAssembly SPA

[![Image from Gyazo](https://i.gyazo.com/4c1a913a5085dbe29f0e5bc0c178f027.png)](https://gyazo.com/4c1a913a5085dbe29f0e5bc0c178f027)

こちらはプリレンダリング処理をした Blazor WebAssembly プロジェクトとデフォルトの Blazor WebAssembly プロジェクトの初期読み込み速度を比較したものです。
SPA では中身のほとんどないhtmlを読み込んでいるので `DOMContentLoaded` の時間は短いですが、その後のアプリケーション実行に必要なダウンロード処理によって最終的な完了時間はプリレンダリングのプロジェクトよりも多くかかっていることが分かります。

### JavaScript の実行を不許可にした場合の挙動を確認

以下は、途中でJavaScriptの実行を禁止した場合の挙動をテストしたものです。JavaScrpt を禁止した場合はページ遷移の際の処理がサーバ側に切り替わっていることが分かります。JavaScript の実行を禁止しているのでカウントアップの処理は行われません。

[![Image from Gyazo](https://i.gyazo.com/25e54533b16b9af3757faff8983f7a3f.gif)](https://gyazo.com/25e54533b16b9af3757faff8983f7a3f)

## まとめ

このように、Blazor WebAssembly にプリレンダリングを導入することは比較的簡単にできますが、デフォルトの Blazor WebAssembly とは異なり、サーバー側に .NET ランタイム が用意されている必要がある点に注意してください。Blazor WebAssembly を選択した場合に直面する、SPA の弱点をカバーする方法として、プリレンダリングを紹介いたしました。

#### Ignite UI for Blazor トライアル版を利用するには

インフラジスティックスでは充実した UI コンポーネントライブラリーを収録し、データリッチでレスポンシブなWebアプリケーションをより迅速に構築することを可能にする <a href="https://jp.infragistics.com/products/ignite-ui" target="_blank">Ignite UI</a> を開発しており、Blazor 対応の <a href="https://jp.infragistics.com/products/ignite-ui-blazor" target="_blank">Ignite UI for Blazor</a> もリリースしています。<br>
Ignite UI for Blazor はトライアル版での試用が可能です。<br>
トライアル版を利用するためには <a href="https://iam.infragistics.com/Account/Register" target="_blank">こちらのページ</a> よりアカウントの作成を行ってください。登録より30日間、弊社のテクニカルサポートをご利用いただくことが出来ますのでお気軽にお問い合わせください。<br>

また、製品をご購入をご検討のお客様は <a href="https://iam.infragistics.com/Account/Register" target="_blank">こちらのページ</a> よりお気軽にお問い合わせください。