TypeScriptでWebAssemblyに入門する
はじめに
みなさん、WebAssemblyってご存知ですか?
MozillaではWebAssemblyのように説明されています。
WebAssembly は最近のウェブブラウザーで動作し、新たな機能と大幅なパフォーマンス向上を提供する新しい種類のコードです。基本的に直接記述ではなく、C、C++、Rust 等の低水準の言語にとって効果的なコンパイル対象となるように設計されています。
JavaScriptでは処理速度が遅くてUXを大きく損なうような計算処理などを高速化したいといった動機から生まれたもののようです。
主要ブラウザーはWebAssemblyをサポートしていますので、このブラウザーだと動かないんじゃない?みたいな心配をしなくても大丈夫です。
ではブラウザ上でどのようにWebAssemblyが動いているのかを簡単に説明していきたいと思います。
WebAssemblyがブラウザ上で動く仕組み
ブラウザーにはWebAssemblyインスタンスとWebAssembly仮想マシン、そしてWebAssemblyJavascriptAPIが用意されています。
WebAssembly実行ファイル
バイナリ形式の実行ファイルです。拡張子は .wasm
で、プログラミング言語のコードを変換するなどして生成します。
WebAssembly実行ファイルは、HTMLなどと同様にWebサーバーから配信します。
WebAssemblyインスタンス
WebAssembly実行ファイルをダウンロードして、起動したインスタンスです。
このインスタンスはWebAssembly専用の仮想マシン上で実行されます。
WebAssembly仮想マシン
WebAssembly専用の仮想マシンです。
この仮想マシンはWebAssemblyをサポートしているブラウザ位に組み込まれています。
WebAssemblyJavaScriptAPI
JavaScriptからWebAssemblyを制御するためのAPIです。
下記のようなAPIが提供されています。
まとめると
- WebサーバーからHTMLなどと一緒にWebAssembly実行ファイルがダウンロードされる
- WebAssemblyJavaScriptAPIを使って、WebAssembly実行ファイルを読み込み、WebAssembly仮想マシンの上でWebAssemblyインスタンスを生成する
- WebAssemblyインスタンスに生えている関数をブラウザ上で実行する
という仕組みになっています。
また2のところで実際にJSファイルを書く必要があります。下記にその一例を記述します。
// WebAssemblyのインスタンス化
const wasmInstance = await WebAssembly.instantiateStreaming(
fetch("hoge.wasm")
);
// WebAssemblyの関数取得
const { add } = wasmInstance.instance.exports;
このようなwasmをimportするためのコードをグルーコードと呼んだりします。
ここまでWebAssemblyの説明を簡単にしてきましたが、フロントエンドエンジニアである私が引っかかったのはここです。
C、C++、Rust 等の低水準の言語にとって効果的なコンパイル対象となるように設計されています。
「CもC++もRustもやったことなんだよな…入門するのに新しい言語の習得がいるのか…」
といった感じでWebAssembly入門したくても腰がなかなか上がらない日々を送っていました。
そんな時に見つけたのが AssemblyScript でした!
なんとTypeScriptでwasmを生成できるというではありませんか!
というわけでフロントエンドエンジニアでWebAssembly入門したいという方に、AssemblyScriptを推したいと思います。
AssemblyScript
AssemblyScriptについてMozillaではWebAssemblyのように説明されています。
C や Rust の詳細を学ぶ必要なく、 TypeScript のような慣れ親しんだ言語の快適さの中で WebAssembly を試したいウェブ開発者にとって、 AssemblyScript は最良の選択肢になるでしょう。 AssemblyScript は TypeScript の厳密なバージョンを WebAssembly にコンパイルし、ウェブ開発者は Prettier、ESLint、VS Code IntelliSense など、使い慣れた TypeScript 互換のツールを引き続き使用することができます。
実際にAssemblyScriptを使ってみての感想は、AssemblyScriptはまさしくフロントエンドエンジニアにとっては最良の選択肢といっても過言ではないと感じています。
CやC++、Rustといった言語はフロントエンドエンジニアにはあまり馴染みのない言語ですが、TypeScriptなら普段から書いている方の方が多いんじゃないでしょうか?
ESLintやVSCodeの設定なども今まで使えるので、開発体験を落とすことなくAssemblyScriptを触ることができます。
AssemblyScriptの始め方はドキュメントに書かれていますのでそちらを参照してください。
サンプルコード
ちょっとしたサンプルコードを用意しておきました。
サンプルコードを見ながら、TypeScriptとの違いを少しだけ紹介していきます。
// 引数の数字を加算する
export function add(a: i32, b: i32): i32 {
return a + b;
}
// 引数の2つの文字列をセパレーターで組み合わせる
class JoinTextProps {
str1!: string;
str2!: string;
separator!: string;
}
export function joinText(props: JoinTextProps): string {
const str1 = props.str1;
const str2 = props.str2;
const separator = props.separator;
return `${str1}${separator}${str2}`;
}
TypeScriptとの違い
扱える型が違う
AssemblyScriptで扱える型が異なります。
例えば number
は扱うことができなくて u32
や i32
といったビット数を意識した型になります。
基本的にanyやundefinedはない
anyやundefinedになるものは許容されていません。
コンパイルするときに怒られてしまいます。
引数の型にObjectが使えない
関数の引数の方にObjectが使えません。
// ↓この定義ができない
type Props = {
foo: string;
fuga: i32;
}
function hoge(props: Props) {
// doing something
}
こういう場合はClassを使う方法があります。
// Classで宣言する
class Props {
foo!: string;
fuga!: i32;
}
function hoge(props: Props) {
// doing something
}
AssemblyScriptでコンパイルしたwasmの使い方
デフォルトの設定でコンパイルをかけると /build/release.js
というJSファイルが生成されます。
これをimportしてwasmでコンパイルされている処理を利用することができます。
import { hoge } from './build/release';
const result = hoge();
型補完が効くように型宣言ファイルも合わせて生成されているので、とても使いやすいと思います。
まとめ
フロントエンドエンジニアがwasmを入門する時におすすめのAssemblyScriptを紹介してきました。
WebAssemblyの機能をどこまでサポートしているかは下記のページにまとめられています。
WebAssemblyは少しづつ熱が高まってきている分野だと思うので、今のうちから基本を押さえておいて損はないと思います。
まずはAssemblyScriptでWebAssemblyの基本を学んでいきましょう!
ではまた!!
Discussion