C#
ASP.NET_Core
Blazor

C# で Single Page Web Application が書ける Blazor が凄かった件

Blazor との出会い

今年2018年2月7日に、自分のソーシャルネットワークのタイムラインに Microsoft のブログ記事が流れてきました。

A new experiment: Browser-based web apps with .NET and Blazor

ブラウザベースの .NET による Web アプリフレームワーク、"Blazor" (ブレイザー) だそうです。

これを読んだ当時、自分はこんな感想を持ちました。

「 "ブラウザベースの .NET による Web アプリ" ってなんのこっちゃ? まだ実験段階的なこと書いてるし、急いで試さなくてもいいかー。それよりも、これまで作った Angular 1.x な Web アプリの Angular5 への移行を急がなきゃ...」

...ということで、何度も import 文を書く苦行や、*[(xyz)] みたいな呪文マークアップに四苦八苦で、ムキーッ!となりつつ Angular な日々を過ごしていました。

しかし先日2018年3月9日、ふとした機会を得て、Blazor を実際に試してみることにしました。

Blazor の公式 GitHub リポジトリを自分の Windows PC に git clone し、続けて README の記載に従って環境整備を進めます。

Blazor - GitHub repository
https://github.com/aspnet/blazor

そして Visual Studio でサンプルのソリューションを開いてビルドし、実行してみたのですが...

...

す、すごいじゃないですか、これー!

もう大興奮ですw

実験段階とはいいつつも、デモ用のしごく簡素な程度とはいえ、ちゃんと Single Page Web Application をデモンストレーションできる程度には、ランタイム、コンパイラ、ツール類が、既に完備されていたのです。

Blazor の何がうれしいのか?

この Blazor によって何がうれしいかっていうと、開発者体験、とくにコーディング体験がはるかに向上する、ってことです。

自分はサーバー側もフロントエンド側もいずれも実装を担当してまして、で、サーバー側は C# + ASP.NET MVC で実装してるんですが、その ASP.NET MVC 開発の経験をとおして慣れた、サーバー側ビュー記述言語の Razor 構文でそのままに、クライアント側ビューを記述できる、っていうのが凄くうれしい。

しかも Blazor では、ちゃんとクライアント側実装におけるコンポーネントとして機能するように調整されているのです。

Foo.cshtml を作成したら、それだけで、ほかの .cshtml 内にて <c:Foo> って書けるんです。

当然、<c:Foo> の箇所は、Foo.cshtml の実装内容でレンダリングされます。

C# で書ける!

そしてこのクライアント側実装用の Blazor ビューなんですが、ロジックの記述言語が、ふつーに C# で書けるんです!

しかもこの C# コードは、JavaScript にトランスパイルされるんじゃなくて、そのままブラウザ上で動くんです!

どうしてそんなことができるのかっていうと、C# のコンパイル結果である .NET の IL コードを WebAssembly にコンパイルする Blazor ランタイムが最初にブラウザにロード&実行されてて、こいつが仕事してるわけ。

言い換えると、ブラウザ上に .NET 実行環境ができちゃってたんですね。

なので、実際、Blazor アプリをブラウザで開くと、System.dll とかがどんどんブラウザに HTTP GET で吸い上げられていきますw

fig-001.png

既存の NuGet パッケージも使えちゃうw

また、「ブラウザ上に .NET 実行環境を作っちゃった」というこの仕掛けなので、既存の .NET 用ライブラリ(NuGet パッケージで配布されてるやつも含め)も、実行環境に依存しないかぎりは、なんの事前処理も要らずに、ふつーに使えてしまいます。

I/O 処理を行わない計算中心のライブラリであれば、ほぼ動くことでしょう。

実際、自分は、IPAddressRange っていう、IPアドレス範囲の文字列表現を扱うライブラリを NuGet パッケージを公開しているのですが、試しにこの IPAddressRange を Blazor アプリに PM> Install-Package して簡単な SPA 作ってみたところ、あっさり動いてしまいました!

fig-002.png

さらにこの後、別件で紹介する C# で書かれた Prolog 言語のインタープリターも、Blazor 上で動いてしまいましたw

現世代のブラウザならどれでも動く!

前述の Blazor ランタイムそれ自体が、実装形態が WebAssembly であるので、WebAssembly 機能をサポートしている Web ブラウザであればどんな Web ブラウザでも動作します。

fig-003.png

"Can I use..." で見てみると (上図)、モバイルデバイスも含めて、概ね主だったブラウザはすべて WebAssembly 機能が使えるようです。
ただし残念ながら iOS10 のサポートは無い模様。
あと、上図ではわかりませんが、WebAssembly 未実装な IE11 であっても asm.js によるフォールバックで動作できちゃうというのも面白いです。

そうそう、Blazor はこんな仕掛けで、ブラウザ上で動作するものなので、static コンテンツがホストできる Web サーバーさえあれば配置できます。
Blazor の動作それ自体には、サーバー側実装は不要です。

ブラウザで .NET が動くだけじゃなく、SPA フレームワークとして形にしている

で、このような基礎技術が凄いのはもちろんなんだけど、その上に Blazor は、ちゃんと、Single Page Web Application フレームワークを載せてきたのがさらにすごいと思うわけです。

慣れた Razor 構文と C# コードをそのままに、データモデルとの双方向バインディングとか、変更検知と再レンダリングとか、ルーティングであるとか、DI (依存性注入) とか、いまどきの SPA フレームワークが備えてる機能が提供されいます。

URL ルーティングも、なんの構成を記述しなくても URL セグメントがそのままコンポーネントにマップされるのが既定の動作のようです。
ルーティング定義をくどくど書かないと始まらないフレームワークと比べて好感が持てます。
最近忘れかけてたかもしれない "構成よりも規約が勝る" という言葉を思い出しました。

Visual Studio IDE 支援も強力

また、Visual Studio 上での Blazor ビューの編集時は、インテリセンスをはじめとした強力な IDE 支援が得られます!

例えば、モデルの変数名を変更したら、ビューのバインディング箇所まで含めて変更が追随します。

movie-001.gif

またビルド時ももちろん、編集の真っ最中のエディタ上でも、ビューのバインディング箇所で名前の間違いなどあれば、リアルタイムでエラーが表示されます。

movie-002.gif

ASP.NET MVC 開発でサーバー側ビューとしての .cshtml 編集時でもできてたことなので、当たり前といえば当たり前の機能なのですが、クライアント側実装でも同じ恩恵にあずかれるというのは、感無量です!

ちなみに、Blazor アプリ開発は、dotnet CLI を使うことで、非 Windows OS 上でも、ターミナルと任意のエディタで開発はできるはずです。
が、現時点では、Windows OS 上で Visual Studio (Visual Studio Code ではなく)を使わないとこのような IDE 支援は得られない模様です。
(Visual Studio も、素の状態では無理であるようで、Blazor 用の拡張を追加しています)

モデル型の実装コードの二重管理から解放される!

また、サーバー側もクライアント側も、いずれも C# で書けるようになったわけですから、データモデル型のサーバー側とクライアント側との共有も、なにもしなくてもよくなりました!

Angular であれば C# 側で FooBar クラスを実装したら、TypeScript 側でも対応する FooBar インターフェースを記述することとなるわけですが、下手すれば手作業で C# と TypeScript の2つのコードを保守する羽目になります。

まぁ、手作業は言い過ぎとしても、例えば何か下記のような Visual Studio 拡張を導入するなどして、この二重のモデル型実装コードをどうにか手なずける必要がありました。

Visual Studio Market Place - "Typewriter"

しかし Blazor アプリでは、サーバー側もクライアント側も、どちらも C# なんですから、モデル型実装が二か所に分裂することはありません!
一回記述すれば、はい、それだけです。

もっとも、サーバー側実装を Node.js + TypeScript でやってる方から見たら、「え、いままでそんな二重管理やってたの!?」と今更感満載に変に驚かれるかもですけど。

プロジェクトと名前空間を使ったアプローチなので、import 地獄から解放される!

あと、なんせ C# による実装なので、"プロジェクト" でコード参照のスコープが求まるのも素敵です。

最近の JavaScript ベースの SPA フレームワークというか、正確にはモジュールバンドラー側の問題(?)ですけど、あれって、個々のアプリケーションレイヤーの実装ですら、import で明示的に参照しないと触れないじゃないですか。
なので、何度も何度も import 文を書き重ねるという苦行を強いられてきたわけです。

しかし C# 開発ではプロジェクトで参照しているコードには気軽に手が届きます。
代わりに、名前空間で衝突を避けるアプローチですね。

とくに Blazor ビューでは、「これこれの名前空間はデフォで開けておいてー」とアプリケーショングローバルに指定することができます。
実際、個々のアプリケーションレイヤーの名前空間は既定でオープン済みの指定が書かれていますから、同一アプリケーションレイヤー内のクラスを参照するのに、いちいち import のような何かを書かないといけないということがありません。

fig-005.png

それに加えて、Visual Studio による C# プログラミングにおいては、名前空間をオープンせずに型名や拡張メソッドをコード上に記しても、そのあとから、Ctrl+ . で名前空間の using 節への追加が、IDE 支援でできてしまいます!

movie-003.gif

あの import 苦行から解放されるだけでも、うれしくて涙が出ます!

既存の JavaScript/CSS ライブラリも併用可能!

Blazor は、Adobe Flash や Silverlight のような、プラグインベースの実装技法ではないです。

あくまでも HTML ベースです。
ただ JavaScript エンジンじゃなくて、C# が使えるエンジンでロジックを実行している、ってイメージするとわかりやすいかな、と思います。

そのため、既存の JavaScript ライブラリや CSS ライブラリも、ふつうに共存・活用できます。

っていうか、Blazor は UIフレームワークは提供してないので、Bootstrap とか Materialize-CSS とか、なにかそういったものを使わないとしんどいと思います。

このような相互運用のために、Blazor 側の C# コードから、同じブラウザ内の JavaScript コードを呼び出したり、逆に JavaScript コードから Blazor ランタイム内に棲息している C# コードを呼び出したりすることができます。

実際に、UIライブラリに Materialize-CSS を採用した Angular5 で実装した SPA を、Blazor で再実装してみましたが、ちゃんと Materialize-CSS をそのまま使えました。

Blazor は素晴らしいですが、かといって、JavaScript の知識も依然として必要じゃないかな、と感じてます。

Blazor の短所

なんだか大絶賛になってしまいましたが、まぁ、そりゃ、短所もありますよね。

ダウンロードサイズ

まずはアプリケーションのファイルサイズでしょうか。

C# の実行環境って、Blazor みたいなものを想定してなかったでしょうから、Web アプリとしては .dll ファイルサイズが膨らみがちなんですね。

今回自分で試作したレベルだと、ダウンロードサイズが 16 メガバイト (!) にも達してます。

ただこれは AOT コンパイルなどの技術が活用されることで、ファイルサイズは激減する可能性もあります。
自分が Blazor GitHub リポジトリを git clone して試した範囲では確認できなかったのですが、Blazor のお披露目となった NDC Oslo でのセッションのビデオを確認すると、ToDo リスト SPA の実装が 326KB で済んでいる様子が見えます。
これくらいのファイルサイズ削減ができるのなら、よさそうですね。

あと、ふつうにブラウザのキャッシュには乗りますので、2回目以降は、ブラウザのキャッシュに残ってさえいれば、ダウンロードは発生しなくはなります。
大した慰めにはならないかもですが、ご参考までに。

処理速度

WebAssembly が高速に動作するとはいえ、Blazor のように IL コードの実行を行うような形態では、どうしても計算機的負荷は重くならざるを得ないのではと考えられます。

ものは試しということで、C# で実装された Prolog 言語のインタープリターを Blazor 上で動かしてみたのですが (ちなみにこれまたあっさりと動作しましたww)、コンソールアプリで動作させた場合は 200 msec くらいで済んでいる処理が、Blazor 上では 800 msec くらいかかりました。

fig-006.png

およそ4倍ほど時間がかかっています。

とはいえ、これは Prolog 言語のインタープリターということでかなり CPU 計算能力に依存した処理なので、実際上の SPA 製品では処理速度が体感的に問題となるケースは少ないのでは、という気もします。

あ、あと、このベンチマーク (?) を行ったハードウェアは、Intel 第4世代 Core i5 4300u 1.9GHz という、2014年ころの世代の、今となっては非力な部類の CPU 上で動作させたことを記しておきます。

C# な人にしかささらない?

次に思い浮かぶのは、自分がこんなに興奮しているのは、もともと自分が、サーバー側実装に C# + ASP.NET を採用していた背景があるかな、という点です。

Ruby、Python、Java、PHP などなど、C# じゃない言語でサーバー側実装している方々や、サーバー側実装とクライアント側実装で担当者が分かれている場合などは、興味薄いかもなー、という気はします。

今はまだ実験段階!

あと、これは必ずしも短所というものではないですが、今日時点ではまだ「実験的プロダクト」だということ。

ベータ版ではないのはもちろんのこと、αリリースやコミュニティプレビューよりも前の段階だ、との位置づけのようです。

今日からすぐに実用で使えるほど安定はしていない、ということですね。
"プロダクションでは使用しないでください!" とも注意書きがなされています。

もちろん、自分が試したように、今日時点でもかなりの範囲のコンセプトを実装・実証されています。

しかしいまはまだ実験段階ということなので、仕様の破壊的変更は当然のように発生するでしょう。
バグだって今時点ではまだまだ潜んでいることでしょう。
必要なのはわかっていてもまだ実装に着手できていない、といった機能も多々あるようです。

でも、Blazor の GitHub リポジトリの README を読む限りは、網羅するつもりの機能一覧 (下図) は鼻息荒いですw

fig-004.png

まぁ、いずれの機能も既存の JavaScript SPA フレームワークや開発環境技術で実現されているものばかりですから、技術的困難はさほどないでしょう。
実際、NDC Oslo でのセッションのビデオを見ますと、Live Reloading とか実際に動作していましたし。

なので、どれだけのリソースが Blazor 開発に注がれるかが焦点になりそうな気もします。

振り返って - 実験段階といいつつ、一定の完成度を見せつけられた!

今回のことがあって、あわてて Blazor の情報がいつから出てきてたか、InfoQ をさらってみたんですね。

そしたら、昨年2017年7月には、もう Blazor の情報は出てきてたようです。

もしかしたらいちどは目にしてたかもしれないのですが、流し読みしただけで、Blazor のインパクトが文字だけの記事からは読み解けなくて、スルーしていたのかもしれません。

さておき、先に書いた内容と被りますが、.NET をブラウザで動かすという基礎技術もなかなかスゴイとは思います。
とはいえ、これももとをただせば、DotNetAnywhere という、.NET 実行環境を C言語で再実装する、6年前に活動停止した (!) プロジェクトが活かされているとのこと (出典は上記記載の InfoQ の記事)。

また、.NET をブラウザで動かすプロジェクトは、旧来からの .NET のオープンソース実装である Mono プロジェクトのほうで進められていたようで (出典)。

Blazor でいきなり出てきたわけじゃないんですね。

ですが、Blazor が凄いのは、単に「ブラウザで C# で書いたプログラムが動きましたー」というだけにとどまらないというところではないかと。

これまで ASP.NET MVC をやってきた人には違和感ない形で SPA フレームワーク部分も作りこんできたことが凄いと思うんです。
まったく新しいビューテンプレートエンジンを持ち出してくるんじゃなくて、.cshtml/Razor 構文をそのまま持ち込んでくるとか。

当然そのためには、Blazor ビューコンポーネント (.cshtml) のコンパイラなどの実装も必要なわけですが、しっかり作りこまれています。

さらに加えて、インテリセンスをはじめとした「Visual Studio ならこうでなくっちゃ!」という IDE による支援機能もバッチリ載せてきたあたり。

この、個々の基礎技術は必ずしも目新しいものばかりじゃないんだけど、ツール類も含めてトータルパッケージとして SPA 開発環境&フレームワークとして出してきた、というところが、自分の感じる、Blazor の凄さです。

実験段階とはいいながら、Angular で書くよりははるかに快適・簡潔に、あっさりと、SPA を実装することができましたしw

これ、C# + ASP.NET MVC やってる人・やったことある人なら、そのノリで、SPA 作れちゃうよ、きっと。
前述のとおり、CSSフレームワークや JavaScript の知識が一切不要とまでは言いませんけれども、これから Angular やります! なんてのに比べたら、断然覚えるべきこと、無いですもん。
そういう破壊力がありますね、Blazor には。

補足 - VB や F# で作った .dll も使えるはず!

最後にちょっと補足を。

本文中では「C#」ばかり連呼してしまいましたが、Blazor の仕組み的には、.cshtml の記述を除けば、コンパイル済みの .NET アセンブリファイルバイナリ (.dll) に対して作用するものです。

ですから、.cshtml 以外の部分では、VB や F# などなど、最終的に .NET アセンブリを生成できるのであれば、ほかの言語でも実装できるはずですね! (自分は未確認ですけど)

あと、WebAssembly 技術でこんなことできるんだったら、Ruby や Python などなど、他の言語処理系でも同じことやってる人いるんじゃないかな、と思い至りました。

で、Ruby と Python について、"Ruby WebAssembly" みたいなキーワードでネットですこうし検索してみたりしたのですが、あまりこれといったのは見つかりませんでした。

Python を WebAssembly で動かす話題での StackOverflow の質問を見ると、Micropython を載せることには成功はしてるようです。
ですが、"とりあえず動くよ!" というレベル感で、Blazor のような SPA 実装の話題はほかの検索結果をみても自分には見つけられませんでした。

Ruby についても、「mrubyをブラウザで実行するまで (WebAssembly)」という記事を Qiita で見つけましたが、こちらも Hello World までというところで、SPA 実装までは踏み込まれていないようです。

Ruby については他にも、2017年9月の Ruby Kaigi 2017 で「Ruby, Opal and WebAssembly」というセッションがあったそうですが (日本語メモがこちらにあります)、Ruby を JavaScript に変換するトランスパイラでしょうか、Opal というプロダクトが既にあるそうでして (Ruby 詳しくなくてすみません)、それでじゅうぶん用が足りるのでは、ということらしいです。

とにかく楽しみ!

いろいろ書きましたが、とにかく、サーバー側実装を C# + ASP.NET MVC でやってきた身としては、Blazor が RTM (公式リリース)する日が待ち遠しいです。

RTM したら早速に実践投入する気満々ですw

いま、サーバー側実装を C# + ASP.NET MVC でやってて、しかしまだ SPA やってないがいずれやるつもりの人や、あるいはいますでに SPA やってるけど乗り換え考えている人は、Blazor の採用も選択肢に検討されるとよいかもですよ!

Happy Coding :)