TypeScriptでWebAssemblyを開発できるAssemblyScriptというのを見つけたので試してみる。
AssemblyScriptとは?
- AssemblyScriptとは、TypeScriptからWebAssemblyにコンパイルする言語とそのコンパイラのこと。
- Microsoftによって開発されている。
- 厳密にはTypeScript風な言語であって、TypeScriptではない。
- 様々な制約と仕様上の違いがある。
- any型やunion型が無かったり、
Array<number>#sort
がArray<string>#sort
として実行されたり、細かい違いがある。 - AssemblyScript is not a subset of TypeScript - DEV Community 👩💻👨💻
- まだまだ開発途上(2019-11-21現在)
- クロージャーがまだ無かったり、例外のthrowがプログラムの停止だったりする。
- Limitations - The AssemblyScript Book
AssemblyScriptを試してみよう
必要な環境
Node.jsの9が必要なので、nodenvでその環境を用意しておく。
AssemblyScriptのインストール
まず、AssemblyScriptを試すプロジェクトを作る:
mkdir assemblyscript-playground
cd assemblyscript-playground
npm init
AssemblyScriptはnpmパッケージとして公開されていないので、GitHubから直接インストールする:
npm install --save-dev github:AssemblyScript/assemblyscript#v0.8.0
プロジェクトの雛形の生成
[asinit]を使って、WebAssemblyのコンパイルに必要なファイル群と設定を生成する:
npx asinit .
これを実行すると、package.jsonに次のようなNPMスクリプトが追加される:
{
"scripts": {
"asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug",
"asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize",
"asbuild": "npm run asbuild:untouched && npm run asbuild:optimized"
}
}
トップレベルに生成されたindex.jsは下記のようになっている:
const fs = require("fs");
const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm"));
const imports = {
env: {
abort(_msg, _file, line, column) {
console.error("abort called at index.ts:" + line + ":" + column);
}
}
};
Object.defineProperty(module, "exports", {
get: () => new WebAssembly.Instance(compiled, imports).exports
});
これは、普通のJavaScriptモジュールと同様に、WebAssemblyモジュールをrequire
で読み込めるようにする仕掛けだ。便利。
assemblyディレクトリには、AssemblyScriptのソースコードが配置される。コード生成時には、次のような足し算をするサンプルが生成されている:
// The entry file of your WebAssembly module.
export function add(a: i32, b: i32): i32 {
return a + b;
}
ここで気になるのが、i32
という型だ。普段TypeScriptを書いているなら、number
型を使うところだが、AssemblyScriptではWebAssemblyの型を用いるようである。ちなみに、number
型も使えるが、AssemblyScriptではf64
のエイリアスになる。
ビルドしてみよう
プロジェクトの雛形を生成しただけでも、WebAssemblyをビルドしてみることができるので、下記のコマンドを実行してビルドしてみよう。
npm run asbuild
ビルドが成功すると、buildディレクトリに下記のファイルが生成される:
optimized.wasm
optimized.wasm.map
optimized.wat
untouched.wasm
untouched.wasm.map
untouched.wat
.wasm
はバイナリで、.wsm.map
はそのソースマップ。
.wat
は人が読むためのテキスト表現になる。バイナリの読み下し文のようなもの。.wat
をじっくり読めば、どういうふうな命令になっているかを理解することができるが、今は読んで理解する必要はない。
WebAssemblyを動かしてみる
ビルドしたWebAssemblyをNode.jsで実行してみよう。
$ node
> const add = require('./index').add
undefined
> add(1, 2)
3
所感
安定性はまだまだ
Nightlyをインストールしたらビルドできなかったりと、まだまだ開発途上感は否めない。今後に期待。
TSerにとっては学習しやすいツールになるかもしれない
WebAssemblyを使うシナリオのひとつに「JavaScriptのチューニングではもう限界なので、WebAssemblyで部分的にチューニングしよう」ということが想定される。WebAssemblyの開発言語というとRustをよく耳にするが、今までJavaScript/TypeScriptで作ってきた現場からすると、新しい言語の学習に対する負担は小さくないだろう。TS風の文法で書けるAssemblyScriptが実用的になってくれば、そうした学習コストを捻出しにくい場面でもWebAssemblyに挑戦しやくなり、いいかもしれない。