【直書き！】AssemblyScriptの(ほぼ)最小構成を作る(環境構築)

[AssemblyScript](https://github.com/AssemblyScript/assemblyscript)は、[TypeScript](https://ja.wikipedia.org/wiki/TypeScript)的な文法でWebAssemblyの `.wasm` ファイルを出力できるツールです。

GolangやRustでWebAssemblyを作成する時と違い、Runtimeなどがなく、極めてシンプルです。(言い返せば、必要最小限の機能しか備えていません...)

# TL;DL
下記URLはDemoソースコードです。(node.js v8以上が必須)
https://github.com/jerrywdlee/assemblyscript-minimum

# Hands On
## プロジェクトの初期化
AssemblyScriptは[Binaryen](https://github.com/WebAssembly/binaryen)を使ってバイナリーファイルをコンパイルしているので、環境によってインストールが時間かかる場合があります。

```sh
$ npm init
$ npm i -D AssemblyScript/assemblyscript
$ npx asinit .
```

ここまではおまじないみたいなものです。

成功すれば、プロジェクト配下はこんな感じになります。

```sh
assemblyscript-minimum
|--README.md
|--assembly
|  |--index.ts
|  |--tsconfig.json
|--build
|  |--.gitignore
|--index.js
|--node_modules
|--package-lock.json
|--package.json
```
## コンパイル
プロジェクトが初期化された時、`assembly/index.ts`というサンプルファイルが作成されて、一応コンパイルしてみましょう。

```sh
$ npm run asbuild
```

コンパイルをすると、`build/` 配下で下記ファイルが生成されます。

```diff
|--build
|  |--.gitignore
+|  |--optimized.wasm
+|  |--optimized.wasm.map
+|  |--optimized.wat
+|  |--untouched.wasm
+|  |--untouched.wasm.map
+|  |--untouched.wat
```

簡単にいうと、`untouched.*`シリーズはコンパイルのみ行って圧縮されていないもので、`optimized.*`シリーズは変数名などを圧縮しました(実行するには両方とも一緒)。
`*.wasm`はWebAssemblyバイナリーファイルで、`*.wat`はS式ベースのテキスト表現らしいです。

## ブラウザで実行
### `index.html`を作成して、`optimized.wasm`をロード

```index.html
<h1>It works!</h1>
<script>
  async function loadWasm(url, opt = {}) {
    const wasmRaw = await fetch(url).then(res => res.arrayBuffer());
    const wasmObj = await WebAssembly.instantiate(wasmRaw, opt);
    return wasmObj;
  }

  loadWasm('build/optimized.wasm', {}).then(wasm => {
    console.log(wasm);
  });
</script>
```

### ブラウザで確認
プロジェクト配下で何らかの手段でサーバーを立てて、`index.html`を確認しましょう。
例えば下記のコマンドのどれかを使えば、localhost:8080にてサーバーが立てられます。

```sh
# Python2の場合
$ python -m SimpleHTTPServer 8080

# Python3の場合
$ python3 -m http.server 8080

# Rubyの場合
$ ruby -run -e httpd . -p 8080

# node.jsの場合
$ npx http-server -p 8080
```

localhost:8080にアクセスして、consoleを確認すると、こんなものがみれます。
![lvh_me_4242.png](https://qiita-image-store.s3.amazonaws.com/0/87438/8e1bb728-b937-2dab-d6bb-f7d36071006b.png)
矢印のところの関数は `assembly/index.ts` の下記関数です。

```assembly/index.ts
export function add(a: i32, b: i32): i32 {
  return a + b;
}
```

コンソルに下記コマンドを入れば確認できます。

```js
loadWasm('build/optimized.wasm').then(wasm => {console.log(wasm.instance.exports.add(42, 24))})
```

![lvh_me_4242.png](https://qiita-image-store.s3.amazonaws.com/0/87438/0eedef76-da73-7b8d-df6c-9adde2c7c9d4.png)


### 軽く解説
`fetch`で `build/optimized.wasm`をArrayBufferとしてロードし、`WebAssembly.instantiate()`で実行可能状態にインスタンス化しています。Exportされた関数は`WASM_OBJECT.instance.exports.FUNCTION_NAME`よりアクセスできます。
`WebAssembly.instantiateStreaming()`というメソッドについての紹介は散在していますが、おすすめできません。何故なら`instantiateStreaming()`はサーバー側が `application/wasm` というMIME typeの提供が必要である上、実装されたブラウザも少ないです(少なくとも2018年12月時点でiPhoneのSafariでは該当メソッドは未実装)。

## Node.jsで実行
`npx asinit .`で自動生成された`index.js`はnode.jsモジュールとしてWebAssemblyを動かす方法を示してくれました。

```sh
$ node
> const wasm = require('./index.js');
undefined
> wasm
{ memory: Memory {}, table: Table {}, add: [Function: 0] }
> wasm.add(42, 24)
66
>
```

とても簡単です。

*PS: 続編は近日公開予定です*