はじめに
現在、Webフロントエンド開発においては、ページ構造を表すHTML、スタイルを表すCSSとともに、挙動を実装するためにJavaScriptが利用されます。JavaScriptの登場当初はWebページに動きをつける程度の扱いでしたが、その後の言語仕様の拡張や、WebブラウザーでのJavaScript実行速度の向上、Node.jsなどWebブラウザー以外でJavaScriptを動作させる環境の登場などにより、本格的なプログラミング言語としてその地位を確立しています。一方でJavaScriptはスクリプト言語ということもあり、実行速度のさらなる向上やファイルサイズの縮小が常に求められています。
本連載で取り上げるWebAssemblyは、そのような要求にこたえることができるバイナリフォーマットです。ソースコードからコンパイルして生成されたWebAssemblyのコードは、WebブラウザーやCPUの種類を問わず実行できるバイナリファイルになります。速度やサイズが重要になる実装をWebAssemblyで作成して、JavaScriptから実行することができます。
WebAssemblyを作成するプログラミング言語としては、C/C++やC#など、さまざまなものが利用できます。その中でも特に注目されているのがRustです。RustはMozillaが開発を主導するプログラミング言語で、C/C++と同様、コンパイルでネイティブコードを生成できます。ランタイムやガベージコレクタを必要としない高いパフォーマンスと、言語レベルでメモリリークやスレッド競合を防ぐ高い信頼性に特徴があり、GoogleがLinuxカーネルやAndroidに、マイクロソフトがWindowsの開発に、それぞれ採用することで話題となりました。パフォーマンスと信頼性を両立できることから、RustはWebAssemblyの開発言語としても高い人気があります。
本連載では、RustでWebAssemblyを実装して活用する方法を、順を追って説明していきます。初回となる今回は、WebAssemblyが生まれるまでの背景を説明するとともに、WebAssemblyの利用例として、C#と.NETのサンプルを紹介します。次に、RustでWebAssemblyを実装する流れを、簡単なサンプルで説明します。次回以降、Rustの開発環境や文法の説明、WebAssemblyのより詳細な実装方法を紹介する予定です。
対象読者
- 動的なWebページにさらなる速度を求める方
- JavaScriptやAltJS以外のスキルを求めるフロントエンドエンジニアの方
- 話題のRustについて学びたい方
必要な環境
本記事のサンプルコードは、以下の環境で動作を確認しています。
-
OS環境
- Windows 10 64bit版
- Microsoft Edge 91.0.864.67
-
C#と.NETの開発環境(p002-blazor-wasm)
- Visual Studio Community 2019 10.16.3
-
Rustの開発環境(p003-rust-wasm)
- rustup 1.24.3
- cargo 1.53.0
- wasm-pack 0.10.0
-
生成したWebページプロジェクトの実行環境
- Node.js v14.17.3 64bit版
サンプルコードには、ソースコードのビルド結果をNode.jsで実行可能にしたプロジェクト(p002-blazor-wasm-web、p003-rust-wasm-web)が含まれます。これらを実行するには、サンプルのフォルダーで「npm install」コマンドを実行後、「npm run start」コマンドを実行して、Webブラウザーで「http://localhost:8080」を表示します。後述するasm.jsのサンプル(p001-asmjs)の実行方法も同様です。
ソースコードプロジェクト(p002-blazor-wasm、p003-rust-wasm)をビルドする方法は後述します。
WebフロントエンドがたどったWebAssemblyまでの道のり
冒頭でも少し説明しましたが、ここではWebAssemblyが登場することになった背景と道のりを少し振り返ってみます。
JavaScriptはWebブラウザーで動作するプログラミング言語として、1995年に「Netscape Navigator 2.0」ブラウザーで導入されました。現在ではフロントエンド開発になくてはならない言語となったJavaScriptですが、当初は動作が遅く、できることも限られていたため、Webページ上でプラグインとして別のプログラムを動作させる方法がしばしば利用されました。プラグインとして、以下のような技術が存在しました。
- Java(Javaアプレット)
- Internet Explorerで利用できるActiveXコントロール
- Macromedia Shockwave(のちにAdobeが買収)
- Adobe Flash
- Microsoft Silverlight
これらのプラグインは、しばしばセキュリティが問題となり、AppleがiPhoneでFlashをサポートしないと宣言したり、いわゆる「HTML5」としてHTMLが多機能化したりしたこともあって、次第に使われなくなっていきました。
一方、JavaScriptの実行速度は、スクリプトを実行中にコンパイルするJIT(Just-In-Time)コンパイラ技術などにより高速化していきました。さらに、JavaScriptの数値型(Number)は全て浮動小数点型ですが、JavaScriptと互換性のある記法で整数型などを導入して数値計算の速度を上げる「asm.js」が2013年に登場しました。asm.jsでは手動でスクリプトを記述するほかに、C言語などからコンパイルしてasm.js対応スクリプトを生成する環境も提供されました。
asm.jsで2整数の加算処理を実装した例をリスト1に示します。本記事ではasm.jsの細かい実装方法は説明しませんが、(1)や(2)の記法で、引数や戻り値が整数であることを表しています。リスト1はJavaScriptとしても動作しますが、asm.js対応のWebブラウザーでは実行前にAOT(Ahead-Of-Time)コンパイルが行われ、より高速に動作します。
function AsmFunc() { 'use asm'; // 加算処理 function asmAdd(param1, param2) { param1 = param1 | 0; // 「| 0」は引数が整数であることを表す ...(1) param2 = param2 | 0; var result = 0; // 「= 0」で関数の戻り値が整数であることを表す ...(2) result = (param1 + param2) | 0; return result | 0; } return { asmAdd: asmAdd } }
なお、リスト1は、Web画面上で数値を加算する図4のサンプル(p001-asmjs)に含まれています。実装全体の詳細はサンプルコードを参照してください。
リスト1の通り、asm.jsのコードはあくまでJavaScriptなので、スクリプトのロード・解釈にかかる時間やコードのサイズが問題として残りました。そこで登場したのがWebAssemblyです。スクリプトの形式を脱してバイナリファイルとすることで、ロード時間の短縮やコードサイズの縮小を実現しました。