Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

AssemblyScriptは、TypeScript的な文法でWebAssemblyの .wasm ファイルを出力できるツールです。

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

TL;DL

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

Hands On

プロジェクトの初期化

AssemblyScriptはBinaryenを使ってバイナリーファイルをコンパイルしているので、環境によってインストールが時間かかる場合があります。

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

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

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

assemblyscript-minimum
|--README.md
|--assembly
|  |--index.ts
|  |--tsconfig.json
|--build
|  |--.gitignore
|--index.js
|--node_modules
|--package-lock.json
|--package.json

コンパイル

プロジェクトが初期化された時、assembly/index.tsというサンプルファイルが作成されて、一応コンパイルしてみましょう。

$ npm run asbuild

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

|--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にてサーバーが立てられます。

# 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
矢印のところの関数は assembly/index.ts の下記関数です。

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

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

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

lvh_me_4242.png

軽く解説

fetchbuild/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を動かす方法を示してくれました。

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

とても簡単です。

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした