LoginSignup
4

More than 1 year has passed since last update.

BlazorでTypeScriptを利用する

Last updated at Posted at 2020-12-22

この記事は C# Advent Calendar 2020 22日目の記事です。

ここで紹介したサンプルプロジェクトは、GitHubで公開しています。
Sumples/TypeScriptTest at master · Atria64/Samples

はじめに

今回はC#でのSPA開発が可能となる画期的なフレームワーク「Blazor」を話題に記事を投稿しようと思います。
Blazorが何かよくわからない方は、以下の記事を参照すると良いかもしれません。

また、Blazorを利用すると以下のようなものが作れます。

しかしここで断っておくと、初学者にとってこの記事の内容は少し難しいかもしれません。(難しく書いてすみません)
雰囲気だけでも楽しんでいただけたらなと思います。

BlazorでTypeScriptを導入する上で注意しなければならない事

はじめに注意しておかなければならないことは、C#とTypeScript間に型情報などは渡せないということです。
「じゃあ意味ねぇじゃねぇか」という人もいるかもしれませんが、少なからずメリットもあります。

Blazor/TypeScriptが提供するもの

Blazor/TypeScriptの構成では残念ながらC#/TypeScript間で型情報を渡すことができません。
しかし、TypeScript自身の型システムコンパイル時のチェックの恩恵を受けることができます。
また、JavaScript恐怖症の方やTypeScriptを愛する人にとって、BlazorでTypeScriptを利用することができるというのは朗報であるはずです。

環境

  • Visual Studio 2019
  • ASP.NET Core 3.1.9
  • Microsoft.AspNetCore.Components.WebAssembly.* 3.2.1
  • Microsoft.TypeScript.MSBuild 4.2.1

導入方法

今回目指す動作

今回はTypeScriptを用いて、以下2つの動作をさせるのを目的とします。

  • ボタンを押したときに、テキストエリアに書かれている文字列をalertする。(返り値なしの関数呼び出し)
  • ボタンを押したときに、テキストエリアに書かれている文字列を加工してボタン名を変更する。(返り値ありの関数呼び出し)

ここまで簡単な操作であればTypeScriptを使うまでもありませんが、サンプルということでご容赦ください。

プロジェクトの作成

新しいプロジェクトの作成→Blazorプロジェクト→Blazor WEBAssembly App の順にプロジェクトを作成します。
今回ここで作成するプロジェクト名は TypeScriptTest にします。
詳しくは割愛しますので、他のサイトなどを御覧ください。

テスト用ページの作成

TypeScriptを呼び出すためのテストページを作成します。
PagesからIndex.razorファイルを開きます。
image.png

今回は2つのボタンと一つのテキストエリアを必要とするため、以下のようにrazorファイルを書き換えます。

index.razor
@page "/"

<h1>TypeScriptTest</h1>

<input @bind="text" @bind:event="oninput" />
<button @onclick="TsAlertClick">TsAlert</button>
<button @onclick="TsEditTextClick">@TsEditText</button>

@code{
    string text;
    string TsEditText = "TsEditText";

    private void TsAlertClick()
    {

    }

    private void TsEditTextClick()
    {
        TsEditText = "hoge";
    }
}

起動すると以下のような画面が表示されるはずです。
image.png

TypeScriptファイルの作成

新しい項目の追加(Ctrl+Shift+A)からwwwroot直下にTypeScriptファイルを作成します。
image.png
今回はTypeScript.tsとします。
image.png
TypeSctipr.tsの中身は以下のようにします。

TypeScript.ts
namespace Test {
    class Functions {
        //与えられた文字列をalertで表示します
        public showAlert(message: string){
            alert(message);
        }
        //与えられた文字列を編集して返します。
        public editText(message: string): string {
            return message+" : edited";
        }
    }
    export function Load(): void {
        window['Functions'] = new Functions();
    }
}

Test.Load();

ビルドの構成

TypeScriptファイルが完成したので、ビルドの構成を行います。
まずはじめにMicrosoft.TypeScript.MSBuildを追加します。

Microsoft.TypeScript.MSBuildの追加

NuGetパッケージマネージャを起動して、検索欄にMicrosoft.TypeScript.MSBuildと入力します。
そして執筆時点での最新バージョンであるMicrosoft.TypeScript.MSBuild4.1.2をインストールします。
image.png
インストール完了後、.csprojファイルを編集します。

.csprojファイルの編集

.csprojファイルに、TypeScriptファイルをコンパイルするような命令を記述します。

TypeScriptTest.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <RazorLangVersion>3.0</RazorLangVersion>
    <TypeScriptToolsVersion>4.0</TypeScriptToolsVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.1" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.1" PrivateAssets="all" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.1" PrivateAssets="all" />
    <PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.1.2">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="System.Net.Http.Json" Version="3.2.0" />
  </ItemGroup>

  <ItemGroup>
    <TypeScriptCompile Include="wwwroot\TypeScript.ts" />
  </ItemGroup>

</Project>

<PropertyGroup></PropertyGroup>には<TypeScriptToolsVersion>4.0</TypeScriptToolsVersion>を追加してあげることで、プロジェクトのコンパイル時に使用するTypeScriptのバージョンをMSBuildに通知させます。
これを記述しなかった場合、MSBuildはシステムにインストールされている最新バージョンを利用します。

また、<ItemGroup></ItemGroup><TypeScriptCompile Include="wwwroot/TypeScript.ts" />を追加することで、MSBuildにどのファイルをビルドするかを通知させます。

ここで一度ビルドを走らせてみましょう。
うまくビルドが走った場合、TypeScript.mapTypeScript.jsが新しくwwwroot直下に生成されているはずです。
image.png

TypeScriptでコンパイルしたJavaScriptを呼び出す

あとは従来のJavaScriptをInvokeする手順とほとんど一緒です。

index.htmlへのタグ追加

wwwroot直下のindex.html<script src="TypeScript.js"></script>の一行を追加します。

index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>TypeScriptTest</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
</head>

<body>
    <app>Loading...</app>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
    <script src="TypeScript.js"></script>
</body>

</html>

IJSRuntimeを用いた呼び出し

IJSRuntimeをinjectした後、InvokeVoidAsyncInvokeAsync<T>を利用してJavaScriptメソッドを呼び出します。
コードは以下のようになります。

index.razor
@inject IJSRuntime JSRuntime
@page "/"

<h1>TypeScriptTest</h1>

<input @bind="text" @bind:event="oninput" />
<button @onclick="TsAlertClick">TsAlert</button>
<button @onclick="TsEditTextClick">@TsEditText</button>

@code{
    string text;
    string TsEditText = "TsEditText";

    private void TsAlertClick()
    {
        JSRuntime.InvokeVoidAsync("Functions.showAlert", text);
    }

    private async Task TsEditTextClick()
    {
        TsEditText = await JSRuntime.InvokeAsync<string>("Functions.editText", text);
    }
}

JavaScriptの呼び出しがイマイチわからない場合

僕の説明がわかりにくかった場合は以下の記事などを参考にすると良さそうです。

動作確認

実際にビルドし実行するとTypeScriptのコンパイラが走りJavaScriptが生成され、うまく呼び出すことができるようになっています。

テキストエリアに書かれている文字列のalert

image.png

テキストエリアに書かれている文字列を加工したボタン名の変更

image.png

おわりに

今回はBlazorにTypeScriptを導入する試みを行ってみました。
この知見が誰かの役に立つことがあれば幸いです。

また、今回作成したプロジェクトはGitHubでも公開しておりますので、ぜひお役立てください。
Sumples/TypeScriptTest at master · Atria64/Samples

次回の C# Advent Calendar 2020 23日目は @nqdior さんです!

参考文献

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4