2022年2月5日土曜日

WASMとRustはVue.js/React.jsを打倒するのか? - JSへの侵略の歴史 2020.11.02に公開 2021.12.06に更新

https://zenn.dev/koduki/articles/c07db4179bb7b86086a1
シェアしました。

はじめに

Typescriptの次はRustかもしれない」という記事がバズってるのを見かけました。
なかなか面白くて、PAとしてのWASMとRustを比較している記事です。ちょうど最近「レガシーおじさん、SPAを始めてみた。そして限界を知る」でも書いた通り最近SPAに手を出してみたのですが、いろいろやろうとするとSSRのためのBackend for Frontend (BFF)等が必要になるとわかり「これJSでやる必要なくない?」とも感じていたのでちょうど良かったです。

こういうのを見るとRIAやGWTのように似たアプローチで廃れた技術や、登場が早すぎたMeteor、今も頑張ってるMSのBlazorなど色々頭をよぎります。といわけで歴史を俯瞰する意味でHTML + JavaScriptとそれ以外の技術のせめぎ合いの歴史やMSのBlazorやRustのyewなどWebassemblyを使うアプローチに関して考察していきたいと思います。

なお、戦いの歴史が思ったより長くなったので「過去の話なんてどうでもいいんだよ、大事なのは今だろ!?」って人は「Webassembly (WASM)はWeb UIの夢を見るのか?」までジャンプ!

王者JavaScript、戦いの歴史

HTML + JavaScriptは登場以来、そのWebのUI標準の地位を何度も脅かされました。そして、そのすべてに勝利してきているのです。

それはJava Appletから始まった

HTMLの登場は1993年ですが当時は論文の公開などを目的としており動的なアクションはできません。こうしたWebでインタラクティブな操作をするというのは1996年に登場したJavaAppletからです。JavaScriptもほぼ同時期に出ており当時はネットスケープ社とSunがビジネス提携をしてAppletを補完するものとしてJavaScriptという紛らわしい名前も戦略的に付けたようです。

このあたりの話はMisreading Chatでちょうど最近話されていてとても面白かったです。

MSも対抗してAcitiveX(とVBScript/JScript)を作りましたが最終的に彼らは失敗しました。セキュリティの基準が現代とは違うから仕方ないですね。今はレガシーの中に残っていて怨嗟の声を集める程度でしょう。

そして、1998年にDOMの登場とともに普及したダイナミックHTML (DHTML)によりJavaScript + HTMLがAppletやActiveXを駆逐しWebの標準UIとなったのです。

ASP.NETとJSF、サーバサイドからのコンポーネントという刺客

「アプリケーションフロントエンド」という視点でHTML + JSをぶっ壊そうとした最初の刺客は2002年に登場したマイクロソフトのASP.NETです。
当時はAJAXはまだ確立していないものの、DHTMLによりリッチな振る舞いをさせる事はできる、そんな時代です。
JavaScriptは今以上に非力な言語でしたし、なにより開発のためのエコシステムやライブラリが比べ物にならないくらい貧弱でした。
そのためリッチなUIを組むためにはお世辞にも生産性が高いといえる環境ではなかったわけです。
また、現代のようにAPIが中心では無くWeb UIというのは「サーバサイドのシステムに付属するオマケ」というくらいの位置づけでした。そのためサーバサイドのエンジニアが片手間でデザイナの作ったフォトショの画面や運が良ければHTMLをテンプレートエンジンに移植するという感じです。「そもそもJSとかサーバ側と違う言語を触りたくは無い」のです。

そんな中、最強のGUI開発プラットフォームであるVisualStudioと.NET Frameworkを持つMSが引っ提げてきたのがASP.NETです。
これは、GUIのエディタでまるでVBやC#のようにグラフィカルにWebページを作りC#でフロントエンドを記述できる夢のような技術でした。
GUI部品をコンポーネントとして組み立てており、今のReact/Vueのようなコンポーネント指向やイベントドリブンを実現していました。C#で書けるといっても直接ブラウザで実行されるようなコードを書くのではなく、コンポーネントの呼び出しなどを記述しこれらコンポーネントはブラウザではHTMLとJSに変換されて実行されたわけです。

良くも悪くも「HTMLの知識やHTTP通信の仕組み、ブラウザとサーバー間のデータのやりとりなどを抽象化して、デスクトップのようなアプリケーション開発」を実現する良い感じの技術でした。

ref: https://www.atmarkit.co.jp/fdotnet/entwebapp/entwebapp05/entwebapp05_01.html

ただ、抽象化してる割にはブラウザの仕様制限は受けるので結果それを意識せざる得ず、本当に「夢のような技術」とは実際は言えませんでした。

ちなみにJSF (JavaServer Faces) 1.0もJavaから登場しました。これはJava版ASP.NETと言ってよいでしょう。2.0系から路線を変えましたけど。

コンポーネント指向、イベントドリブン、強力な言語とエコシステムということで目指してる方向性は悪くないようにも見えるのですが、結果としてこれらは実質廃れます。
まあ、ASP.NETは普通に生きていますが今はGUIエディタでポトペタって方向性は変えたんじゃないかな? ちょっと自信がない。とはいえ、Web開発の主流とは言えないのは間違いないでしょう。

理由はいくつかあると思いますが、個人的な所感としてはベンダーニュートラルではなかったので普及が遅れ、結果としてWebのエコシステムとの統合が難しくなったと考えています。

AJAXの登場とシンプルなテンプレートエンジンへの回帰

AJAX登場

JavaScriptの登場に匹敵するWebの一大革命、それが2005年のAJAXの登場です。
当時からDHTMLはありましが、それは「マウスカーソルの後ろを★が追っかける」とか「Webページを開くと花弁が降ってくる」とかそういう「おもちゃ的な演出をするためのもの」という側面がありました。一応、ちゃんとしたUIに組み込んだ使い方もありましたけど、かなりのレアケース。

その認識を刷新しJSを一躍おもちゃから本物の道具にしたのが「Google Map」です。これは今と基本的なUIは変わっていないので登場当時から画面をドラックすると「リロード無く」無限に縮尺を変えたり座標の変更ができました。
あまりにも今となっては当たり前の挙動ですが、それまでは地図アプリというのは画面の四方や上部にボタンがあってそれを押すと「画面全体を描画」して移動先の地図を表示してたのです。
こうした画面をリロードすることなく非同期でAPIを呼び出すという思想は革命的でした。その後あらゆる部分でAJAXを使うというブームが始まります。

一過性のブームもありながらも、ここから現代につながるインタラクティブなWebが生まれました。今となってはAJAXという言葉をあえて使う事もなくなった気がしますし、なによりDHTMLなのかAJAXなのかという議論も今は昔ですね。

Ruby on Rails、jQuery、Bootstrapの登場

この頃に同時に起こったのがRuby on Railsに代表されるLLの躍進とそれに伴うテンプレートエンジンの簡素化です。
これによりASP.NETやJSFは所謂Web界隈と呼ばれるようなコンシューマよりへの拡大はもちろん、主戦場であるエンタープライズ領域すらLL言語にフロントエンド系を中心に浸食されていきました。
またこれらのFWは細かい理由は知りませんが結果的にコンポーネント指向ではなく、シンプルなMVC Model 2を採用しておりテンプレートエンジンはループや条件分岐、変数をバインディングしたりレイアウトを作れる程度の簡素なものでイベントドリブンなどは採用さていません。一部、ClickやWicketなんかは採用していましたが、まあ普及していませんし?

これは想像ですが、Post Backにはじめとされる仕様が抽象度が高すぎてWeb開発の馴染みが悪かったのと、なにより登場したばかりで進化の激しいAJAXに対応するためにはプレーンなHTMLやHTTPに近い方が対応しやすかったからでしょう。昔はRailsもRubyをJSに変換する謎仕様がありましたが途中からなくなりましたし。Post BackはURLがぐちゃぐちゃになるしあまり好きではないのですよね。。。 この辺がテンプレートエンジンがシンプルに回帰した理由だと思います。

Prototype.jsやjQueryの登場により難しかったクロスブラウザの対応も改善され、UIデザインに関してもBootstrapのようなCSSフレームワークも普及してサーバサイドの技術によらず、フロントエンドで共通的なエコシステムが徐々にでき始めてきたわけです。

個人的な印象としては、まだまだフロントエンジニアとして独立したロールは無かったと思いますが、言語に依存しない「フロントエンド」という領域の登場でもあります。

RIA 百花繚乱

RIA (Rich Interface Application)あるいは[リッチクライアント]と呼ばれる技術があります。
これは従来のHTMLよりも高度な、まるでデスクトップアプリケーションであるかのようなインターフェースを提供する技術の総称です。
CurlやFlashのようにプラグインをベースにしたものや、GWTのような最終的にHTML+JSに変換されるものまで様々ですが共通するのは「素のJSやHTMLを直接書かない」という事です。
広義にはHTML5を含むこともありますし、上記の定義でもVue.js + TypeScriptなんかはRIAの定義に一応はまる気もしますが、ここでは考えないことにします。

最終的にはHTML5になり表現力が向上したこと、後述するJSのエコシステムや言語の進化の結果として廃れましたが、WASMを使ったWebフロントエンドを考える上では大きな参考になる存在でしょう。

また重要な点はRIAは数多く登場し流行ってはいたものの一瞬たりともWebのUIの王座には立っていないのです。個別の製品、サイトでの成功はあれど主流になっていないという点でいずれも失敗しています。

Flashベースの本命RIA - Adobe Flex

Flexは当時圧倒来なシェアを誇っていたFlashをベースとして、2004年にRIAとして本格的なビジネスアプリケーション向けのUIを作れるようにしたAdobeのプラットフォームです。
従来のFlashはアニメーションやゲーム的なインタラクションを作るためのものなので通常のアプリケーションを記述するのには向きません。
そのためAdobeはMXMLというXMLをベースにした独自のUI記述言語と、JavaScript2 (ECMAScript4)に準拠したActionScript3というバージョン迷子な言語を引っ提げてRIAプラットフォームとして登場させました。
ECMAScript4は現在あるいは当時のJavaScriptとは異なり型や本格的なクラス、そしてなによりモジュールと名前空間をもったよりJavaのような書き味の言語でした。型を持つといってもTypeScriptのようなJSのスパーセットではなく完全に別物でした。今ならワンチャン流行るかもしれませんが、当時は言語仕様が違い過ぎて受け入れらえずJS2の実行エンジンとしてTamarinをOSSとして公開したにも関わらず滅びました。

Adobe Airというデスクトップ環境まで作ってましたが普及することなく終わりました。Flash自体が最終的に廃れたこともあり復活は無いでしょう。

特筆すべきは「Flashプラグイン」という実質100%シェアのプラグインを持ち、プラグイン型RIAの弱点である導入障壁のないFlexも普及しなかったという事です。

Microsoftの肝入り - Silverlight

Silverlightは2007年にマイクロソフトが開発したRIAです。
Windowsのデスクトップ向け技術であるWPF (Windows Presentation Foundation)のサブセットになります。
UI記述言語としてはWPFと同様にXAMLをサポートし、.NETがそのまま利用できるのでC#はもちろんJavaScript(JScript .NET)、Ruby(IronRuby)、Python(IronPython)なといった主要なLLも動かすこともでき、MVVMなど強力なアーキテクチャパターンもサポートしていました。

機能的にもDRMや動画再生機能などを強力にサポートしていて、動画プレイヤー的な位置づけでは結構長く生きてた気もします。IE以外にも、Chrome、Firefox、Operaなど当時の主要ブラウザにはプラグインを提供していたはずです。スマホは未対応だった気がしますが、それは結果的に流行らなかったからでしょう。HTML5にMS自身が注力していったこともあって滅びました。

本筋とは全く関係ありませんが、なぜか台湾マイクロソフトにより擬人化されています。まあ、MSだし多少はね?

特筆すべきは「.NET Framework」というマルチ言語をサポートする強力なエコシステムを持ってしても勝てなかったのです。

AJAXは俺が作った - Google Web Toolkit (GWT)

GWTは2006年にGoogleが作ったRIA環境です。
最大の特徴は、上記の2つとは異なりプラグイン型ではありません。

GoogleといえばGogole MapやGMailでAJAXを効果的に使い世に広めた立役者ですが、同時にJSでAJAXを開発する大変さも骨身に染みていたのではないでしょうか?
なので、GWTではJavaをJavaScriptに変換しかつSPAとしての体裁も整えます。今でいうAltJS的な発想ですね。SPAを支援するという点も含めてTypeScript + Vue.jsのような構成にとても近いといえるでしょう。

独自の言語ではなく、JavaなのでNetBeansやEclipseで使えるという事もありそれなりに注目はされていたと思いますが、当時のJavaがそこまでモダンではなかった事もありあまり普及したとは言えないかと思います。

シンプルにRPCが書けますし、強力なIDEやUTなどもJUnitを使って書けるのでJSのエコシステムが整ってない状態では強力な選択肢であったと思います。

当時としてはJSにトランスパイルする、トランスパイル時に最適化をするという思想は珍しかったと思うので、おそらくこのあたりの成果はGoogle Closure Toolsに引き継がれていると思います。

さて、そんなGWTもHTML + JSの打倒には至らなかったわけです。

HTML5の前身? Google Gearsの登場

RIAはHTML5によって駆逐されるのですが、そのHTML5に至る手前の存在として生まれたのが2007年に登場したGoogle Gearsです。

Google GearsはWebアプリケーションのオフライン動作機能やGeolocationのサポートといったブラウザ自体の機能強化とそのAPIをJSから呼べるようにしたことが特徴です。以下のような機能を追加しています。

  • Database モジュール(SQLiteを使用)。データをローカルに格納できる
  • WorkerPool モジュール。JavaScriptコードの並列実行を提供する
  • LocalServer モジュール。アプリケーションのリソース(HTML、JavaScript、画像など)をキャッシュし提供する
  • Desktop モジュール。Webアプリケーションがデスクトップとより自然にやり取りできるようにする
  • Geolocation モジュール。Webアプリケーションがユーザーの地理的位置を検出できるようにする

どこかで見たことがあると思った人は勘が鋭いですね。はい、これらの機能はすでにHTML5に取り込まれています。そのため、HTML5に移行するという意味でGearsも適切に終了しました。その意味では、Gearsは本流に取り込まれたのであり「廃れた」というのとは少し立ち位置が違いますね。

当時、JavaScriptやHTML自体の進化が滞っていた冬の時代だったのですが、Google Gearsがそこに風穴を開けた感じです。GMailやGoogleDocsを筆頭としたGoogleプロダクトはもちろんそれ以外のアプリケーションでもれらの機能は使われていました。広く普及していたというほどでは無いですがGoogleのみの仕様でもなかったのです。Chrome以外にもプラグインが提供されていましたしね。

GoogleはChromeを手に入れて以来、こういった「自社サービスに必要なAPIをChromeに独自で先行実装してその後標準に取り込む」といったプロセスを好んで使います。SPDY => HTTP2しかり、QUIC => HTTP3しかりですね。この辺は主要なプロダクトを持たないMozillaとかとは性格の違うところです。

かつてのIEの独自拡張と何が違うんだと非難されたらコメントに困りますが、時代の違いやちゃんと標準化に持ってくという姿勢とかですかね。たぶん。MSの有名な独自拡張と言えばActiveXをベースにしたXHTTPRequestでこれがなければAJAXは登場しませんでしたが標準化したわけではなく、むしろIEとそれ以外になってしまいましたしね。。。あれはもったいない。

※ @tadsanさんに指摘されてGearsの存在を思い出しました。ありがとうございます!

スマホの普及、HTML5、nodejs - エコシステムの完成

RIAが流行りそうで流行らないという状態の間、JS側に大きな変革が起こります。
それはスマホの普及とHTML5のリリースとnode.jsの普及です。

まず、スマホの普及によりAndroidアプリ/iOSアプリという「クライアントアプリケーション」が大量に増えます。
これによりWebベースのアプリケーションの時代からクラサバの時代に戻ったわけです。そのためサーバ側の最終アウトプットがHTMLテンプレートではなく、XMLやJSONというAPI主体に切り替わってきました。元々サーバ間通信やAJAX向けにAPIのI/Fはありましたがこれが補助ではなくメインになったわけです。
そうして来ると、Web向けにテンプレートエンジンを用意するとサーバ側が二つのパラダイムをサポートしなければならずややこしくなります。そこでいっそのことフロントを全部静的ページで作って、動的な機能はAjaxだけで呼び出そうという思想がSPAですね。
これによってフロントエンドとバックエンドの責務が明確になりますし、サーバサイドの技術がスマホと共通化できて簡素化されます。
同時にサーバサイドでも「マイクロサービス」という形でAPI主体でシステムを組む流れがムーブメントととなったため、サーバの最終I/FをAPIにしたいというニーズと合致したのです。

次に、HTML5の登場です。これによりHTMLの表現力は大幅に向上しました。今まではFlashなどの外部プラグインが必要だと言われていたような機能もHTMLの標準機能で出来るようになったわけです。同時にECMAScriptも進化を再開し、特にES6では様々なモダンな機能が組み込まれたので言語自体の機能の弱さという点が大きく改善しました。

そして最後に重要なのがnodejsの普及です。これはフロントエンドとしてのJavaScriptには直接関係しませんが、JSエコシステムを加速させたという点では非常に大きいと思います。npmとか。nodejsによりJSも他言語と同様に業務用途に足るエコシステムが構築され先ほどの言語そのものの進化と合わせて高い生産性を出せるようになりました。
このHTML5による表現力とnodejs普及による生産性の向上で、各種RIAを完全に打倒したのです。

早過ぎたMeteor

Meteorというフレームワークをご存じでしょうか? Isomorphic JavaScript web frameworkを標榜したクライアントサイド、サーバサイド、そしてDBを一体として開発する統合FWです。SPA + BFF + mBaaSですね。

2012年という極めて早い時代に登場していますが当時はFirebaseのようなクライアントサイドからリアクティブに使えるサーバサイドのDBという点が強調されていたように思います。Fireabase Real-time Databaseも2012年公開ですから恐るべき先進性です。

最近は名前聞きませんでしたが、今も普通に生きていました。
まあ、これはJS + HTMLそのものなので現在の流れと特に競合しないですが、Next.js/Nuxt.jsの「Universal」と大きく影響すると思ったので触れておきました。詳細を見てないので当時から方向性は変わってるかは分かりませんが、いったん2012-2014年当時のMeteorのイメージで話します。

SPAの普及、そしてサーバサイドへの進出

サーバサイドからフロントエンドの地位を完全に奪いとったJSですが、今度は逆にサーバサイドに攻め込みます。
まあ、攻め込むというか必要に駆られて。。。という感じですが。

パフォーマンスやSEO (含むOGPタグ最適化)のためにSSRやSSGが必要になりそれを実行するプラットフォームとしてBFF (Backend for Frontend)が求められるようになりました。
BFFに関しては以下の解説がわかりやすかったです。

また、Nuxt.jsやNext.jsのようにSSRのためにサーバサイドもカバーするFWも登場しているようです。それを「universal」とか「isomorphic」って呼ぶみたいですね。

「isomorphic」というとMeteorが思い浮かびますが、私は少し目指してる方向が違うと考えます。
Meteorは完全にAll in Oneでモノリスの極致です。同じサーバサイドにクライアントサイドから手を伸ばしているといっても、そこが違います。Meteorはプレゼンテーション以外のビジネスロジックもMeteorで書くのが基本的なアプローチのはずです。

一方で、Nuxt.jsなどはまだ使ってないので断言はできませんが、あくまでSPAの制約を補う補助としてBFFが存在しているかと思います。つまりシステム全体から見ればBFFはSSRが責務のサービスでありこれは極めてマイクロサービス的です。もうちょっというと単にスマートなCDNです。そのためそこにビジネスロジックは無いはずです。あくまでビジネスロジックはサーバサイドに書かれてそれをAPIで呼ぶのが基本構成になるはずです。

まあクライアント層が厚くなってる現代なら小さなというかセキュリティが重要では無ければビジネスロジックもクライアントに書くかもだけどそれはそれ。

とにもかくにも、HTML+JSがフロントエンドのポジションを得てからおよそ20年。RIA勢とかをすべて薙ぎ倒して今HTML+JSがフロントエンドの覇者となっているわけです。

WASMってなんだっけ?

JSとフロントエンドの歴史が終わったところで次はWASMです。
WASMとはなんでしょうか? ブラウザで実行可能なバイナリフォーマット。Webの低水準言語。そんな立ち位置なのですが、ちゃんと知るためにはやはり少し歴史のお勉強が必要です。ITはいつから文系科目になったんだ。。。

ActiveX、NaCl、asm.js、そしてWASMへ

まず登場するのは95-96年に登場したActiveXコントロールです。こちらはマイクロソフトが作成した仕様でObject Linking and Embedding (OLE)を基礎にしています。極めて雑に言うとJS以外のC言語などで書いたコードをネイティブ実行でき、ブラウザの制限を超えてファイルシステムやハードウェアが叩けるので高機能で高速なものが作れた。しかしブラウザがサンドボックスにならないのでセキュリティ上の問題が増え廃れました。

そして、2009年にGoogleが開発したのがNaCl。これはGoogle版のActiveXでCなどをコンパイルしたネイティブコードが実行できる。と同時にActiveXの問題点として挙げられていたセキュリティを強化してハードウェアやフィルシステムに直接アクセスできなくしたサンドボックスを提供しました。今はWASMがあるので開発終了しています。

一方で、MozillaはGoogleのアプローチを非難してasm.jsを開発しました。こちらはネイティブコードの実行基盤ではなく高速に実装できC言語などと互換性を保ちやすいJSのサブセット。最大の成果はEmscriptenというC/C++から生成されたLLVMバイナリをasm.jsに変換して実行するというもの。
こいつでゲームエンジンとかが結構移植されたりしています。しかし、あくまで本質的にはalt.jsなのでもっと根本的な解決策が欲しいと言われていました。

そこで生まれたのが2017年に登場したWebassembly (WASM)です。
asm.jsとNaClをベースに開発されJSなどの高級言語とは異なりバイナリをベースとした低級言語です。

ref: https://ukyo.github.io/wasm-usui-book/webroot/what-is-webassembly.html

つまり、WASMはブラウザをOS/仮想マシンに見立ててブラウザによって実行されるネイティブ(のような)コードという事が出来ます。
各種言語実装はx86のLinux向けにコンパイルするのと同様にWASM向けにコンパイルすることであらゆるコードを実行できます。WASMをサポートする言語としては、Rust/C++(LLVM)/Go/Kotlinが有名ですが理屈上はほかの言語も対応すれば問題なく動きます。

JavaScriptとWASM

JavaScriptとWASMの関係ですが基本的にはJSがメインで、WASMが性能が必要なところに部分的に使うと今のところ位置付けられています。
特にDOMのアクセスにWASMは制限があるので単純に置き換える事ができません。また、JSはブラウザ戦争の結果としてLLの中でもダントツにチューニングされた言語なので、常にWASMの方が高速とも言えないようです。このあたりはWASMの処理系が成熟してくれば解決するでしょうけど。

AltJSとWASM

ブラウザでJavaScript以外の言語を実行するという試みは長年行われていますが、その多くはAltJSというトランスパイラです。まれにJSでVMを書いて言語処理するタイプもあります。

もっとも有名なのがTypeScriptで、最初に有名にしたのがCoffeeScriptですかね?
これらはあくまでJSなので単純にシンタックスシュガーレベルのものであれば問題ないですが、JSの機能を大きく超えるものは実装をかなり作りこんだ理場合によってはVMをJSで実装する必要が出てくるはずです。たぶん、OpalとかScala.jsはVMを実装してるんじゃないかな? コードとかドキュメントを読んでないので確証は無いですが。 Opal(Ruby)もScala.js(Scala)もトランスパイラのようですね。todeskingさんにコメントで指摘いただきました。

低水準言語なのでこのあたりが対応しやすいのがWASMです。通常のVMやコンパイラ作成のノウハウを応用して比較的簡単に作れるので、JSと互換性のない言語も作りやすいです。

Webassembly (WASM)はWeb UIの夢を見るのか?

さて、予定に反して歴史の部分が長くなりましたが、表題にも入れているWASM + Rustについて考えていきましょう。
ここまで気合で読んでくれた方なら、歴史的経緯もばっちり把握しているでしょう。

そもそもRIAは何故死んだのか?

まずは方向性が近い話になるRIAの失敗から学びましょう。いろんな理由が重なってるとは思いますが、たまたまという時代背景を抜くと以下の2点が大きいと考えます。

  • 独自のエコシステムを普及させるむずかしさ
  • 標準Web技術とのインテグレーション

普及度という点では十分な点をクリアしていたFlexも死にました。これは色々ありますが、当時のAdobeといえど独自のエコシステムを新規に作るのはやはり難しいのです。単に開発言語やIDEを作るだけでは足りません。OSSを含めた多くのライブラリやコミュニティ。そして既存のプラットフォームから移行させるだけの魅力。このすべてを作るのは容易ではないと想像します。

Silverlightの場合は開発エコシステムという意味では.NETという大きなものがあるのですが、当時のMSはだいぶクローズな感じでしたし企業色が強すぎてMS関連以外で使おうという感じもしなかったのかな、と思います。当時流行ってたLAMP環境やRailsと組み合わせて使う的な雰囲気はなくMS製品で固めるときのパーツという風に見えていたのが普及を阻害したのではないでしょうか。

また、重要な点としてプラグイン型のRIAは既存のWebとは完全に別物なのでデータのやり取りはもちろんレイアウトを上手く統合したりWebの部品をRIA側に取り込んだりその逆ができないのでそういったシームレスな移行ができないことも死んだ理由でしょう。こうした標準Web技術とのインテグレーションが課題になりがちです。少なくとも私はそれで使いづらいと思いました。

GWTはその意味でいうと筋は良さそうなんですが、単純に当時今よりもJavaが嫌われてたりとか、AJAXに変換後のコードをやっぱり弄りずらくて独自ワールドになりがちとかその辺が原因な気がする。あと別に死ぬ条件に当てはまらないから流行るというわけじゃないしね。

この点に関してはWASMの場合は既存言語のエコシステムを取り込めますし、そもそもWeb標準の一員なので別な世界観にならないというのは大きなメリットです。

スマホも含めてほとんどの環境でサポートされており、かつてのRIAの失敗を繰り返さない「土壌」はあると思います。

WASM + 非JS言語の利点

これは究極的には「JS以外の言語が使える事」という一点のみですが、それが何が嬉しいかというとサーバサイドの言語と同じものが使えるとかですかね。あとはNext.jsのようなBFFの方向性ではなく、MeteorやGWTのようなIsomorphicでモノリスなWeb開発をしたい時。

前者はスタートアップや個人プロジェクトなどエンジニアが少ない時には役立ちますね。Webだと今までだとサーバサイドがnode.jsの時だけ取れたモデルですが、この制約が取っ払われると楽になる部分は大きいと思います。

この場合重要なのはJSやHTMLなど既存の仕組みと上手く統合出来る事でしょう。ほどんどの言語でWebフロント向けのライブラリは充実してませんから、そこはJSを使いたいはずです。Webで探したものが使えるのマジで重要。と同時に既存言語、例えばRubyであればGemや自分が過去に作ったライブラリをさらりと使えると移行しても良いかなという気分になります。
これを実現する絶対条件としてはコンポーネントは取り込むにしてもHTMLを維持する事ですね。XAMLやFXMLのような独自の構文を今更入れるにはすでにフロントエンドのエコシステムが成熟しすぎていると思うので。

ついでIsomorphicでモノリスなWeb開発ですが、これは今のマイクロサービスの流れに反していますが、何でもかんでもマイクロサービスにすればいいわけでは無いです。SPAっぽいアプリがSEOもバッチりで単一言語/単一フレームワークで作れるならプロトタイプ開発やスタートアップには最強です。
この辺はビジネス的にはNoCode/LowCodeに吸収される気もしますが、個人的には欲しい方向性ですねー。

WASM対応フロントエンドフレームワーク

WASM対応のWebフレームワークをいくつか見ていきたいと思います。

Yew

元記事でも紹介されていたRustベースのYewです。

コンポーネントベースでJavaScript interoperabilityを標榜しています。JSとの相互運用を謳ってるのは良いですね。
サンプルコードはこんな感じ。パッと見Reactっぽい感じですね。
他のサンプルはこちらから。

use js_sys::Date;
use yew::services::ConsoleService;
use yew::{html, Component, ComponentLink, Html, ShouldRender};

pub enum Msg {
    Increment,
    Decrement,
}

pub struct Model {
    link: ComponentLink<Self>,
    value: i64,
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_props: Self::Properties, link: ComponentLink<Self>) -> Self {
        Self { link, value: 0 }
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::Increment => {
                self.value += 1;
                ConsoleService::log("plus one");
                true
            }
            Msg::Decrement => {
                self.value -= 1;
                ConsoleService::log("minus one");
                true
            }
        }
    }

    fn change(&mut self, _props: Self::Properties) -> ShouldRender {
        false
    }

    fn view(&self) -> Html {
        html! {
            <div>
                <nav class="menu">
                    <button onclick=self.link.callback(|_| Msg::Increment)>
                        { "Increment" }
                    </button>
                    <button onclick=self.link.callback(|_| Msg::Decrement)>
                        { "Decrement" }
                    </button>
                    <button onclick=self.link.batch_callback(|_| vec![Msg::Increment, Msg::Increment])>
                        { "Increment Twice" }
                    </button>
                </nav>
                <p>
                    <b>{ "Current value: " }</b>
                    { self.value }
                </p>
                <p>
                    <b>{ "Rendered at: " }</b>
                    { String::from(Date::new_0().to_string()) }
                </p>
            </div>
        }
    }
}

fn main() {
    yew::start_app::<Model>();
}

Blazor WebAssembly

マイクロソフトのBlazor WebAssemblyです。ASP.NETにもめげず毎度毎度ちゃんと作ってるのは偉いですね。元々サーバ側で実行するBlazorが先にリリースされていますがBlazor WebAssemblyが最近リリースされこれはWASMなのでCDNにだってデプロイできます。

MSのカンファレンスなんか行くと会場満員な感じでMS系エンジニアは今かなり注目してる感じじゃないでしょうか?

C#などで開発が出来るのですがアーキテクチャ的になかなか面白くてC#をWASMに変換してるのではなくWASMで実装した.NET Coreをブラウザの上で実行しそこでC#やRazorコンポーネントを動かしてるんですよね。マジかよ。

コードはこんな感じで書けてVue.jsっぽい感じがしますね。ぱっと見。

@page "/todo"

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private IList<TodoItem> todos = new List<TodoItem>();
    private string newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}

以下の記事も参考になるので読んでみると良いかもです。

TeaVM

Java製のWASMフロントエンドです。

厳密にはWASMだけじゃなくてJSにも変換してむしろ今はそっちがメインっぽい。GWTと違いJavaのバイトコードを変換するのでScalaやKotlinにも対応できらしい。

@BindTemplate("templates/fibonacci.html")
public class Fibonacci {
    private List<Integer> values = new ArrayList<>();
    public Fibonacci() {
        values.add(0);
        values.add(1);
    }
    public List<Integer> getValues() {
        return values;
    }
    public void next() {
        values.add(values.get(values.size() - 2) + values.get(values.size() - 1));
    }
}
<ul>
  <std:foreach var="fib" in="values">
    <li>
      <html:text value="fib"/>
    </li>
  </std:foreach>
  <li>
    <button type="button" event:click="next()">Show next</button>
  </li>
</ul>

Vugu

Goでフロントエンドを書くためのフレームワーク。

サンプルコードは以下の通り。普通にHTMLを書いてる感じでおもむろにGoが書けるのは楽しそう。コードを見た感じではサーバサイドも含まれているし純粋なSPAというよりユニバーサル系なのかな?

<div>
  <main role="main" class="container text-center">
    <div class="mt-5">
      <h1>Welcome to Vugu</h1>
      <p class="lead">This page is being rendered via 
        <a @click='event.PreventDefault();c.ShowWasm=!c.ShowWasm' 
           href="https://webassembly.org/">WebAssembly</a>...
      </p>
      <div vg-if='c.ShowWasm' class="alert 
           alert-primary" role="alert">
        <strong>WebAssembly</strong> (abbreviated Wasm) is a 
        binary instruction format...
      </div>
    </div>
  </main>
</div>

<script type="application/x-go">
type Root struct {
    ShowWasm bool `vugu:"data"`
}
</script>
package main

import (
	"log"
	"net/http"

	"github.com/vugu/vugu/devutil"
)

func main() {
	l := "127.0.0.1:8844"
	log.Printf("Starting HTTP Server at %q", l)

	wc := devutil.NewWasmCompiler().SetDir(".")
	mux := devutil.NewMux()
	mux.Match(devutil.NoFileExt, devutil.DefaultAutoReloadIndex.Replace(
		`<!-- styles -->`,
		`<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">`))
	mux.Exact("/main.wasm", devutil.NewMainWasmHandler(wc))
	mux.Exact("/wasm_exec.js", devutil.NewWasmExecJSHandler(wc))
	mux.Default(devutil.NewFileServer().SetDir("."))

	log.Fatal(http.ListenAndServe(l, mux))
}

まとめ

Typescriptの次はRustかもしれない」という記事でWASMなフロントエンドの話があったので当時のRIAと比較してみたくて書いた記事なのだけど、当時のRIAを説明するための前置きがとても長くなってしまった。

まあ、結果としてWebの歴史みたいなのを掘り起こして自分の中で整理できたので良いかな。

で本題のWASMなフロントエンドをいくつか探してピックアップしてみたけど、RIAの反省やなによりReact/Vue.jsをお手本にしている、という性質上筋は悪くないというか方向性は良さそうなプロダクトが多い印象。

現時点の完成度という意味ではMSが頑張ってるBlazor WebAssembly以外は今一つな雰囲気を感じるし、何より流行る流行らないは時の運的な要素も強いけど、より便利なツールを目指してこの辺が進化していくのは楽しみ。主流にはたぶんならないけど存在感のあるサブくらいの立ち位置が出来れば十分に実用できるしね。

それではHappy Hacking!

この記事に贈られたバッジ

0 コメント:

コメントを投稿