WebAssembly 対応
NagiScript を WebAssembly にコンパイルし、ブラウザで実行する方法を学びます。
基本的な Wasm コンパイル
Wasm 出力のコマンドは
nagiscript wasm main.ngs [-o PATH] です(-o PATH
は省略可能)。出力は .wat(可能であれば
.wasm + .d.ts)です。
# 実行例: main.ngs を Wasm へ
nagiscript wasm main.ngs -o output.wasm
生成されるファイル:
output.wasm— Wasm バイナリoutput.d.ts— TypeScript 型定義
エクスポートする関数
Wasm / C へ公開する関数は
export "C" fn で宣言し、-> 型 と明示的な return
を使います(export fn ... は誤りです)。
export "C" fn add(a: i32, b: i32) -> i32 {
return a + b
}
export "C" fn process(n: i32) -> i32 {
return n * 2
}
ブラウザでの利用
HTML ファイル
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>NagiScript Wasm</title>
</head>
<body>
<div id="output"></div>
<script>
async function loadWasm() {
const response = await fetch('output.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes, {
env: {
memory: new WebAssembly.Memory({ initial: 256 })
}
});
// 関数を呼び出す
const result = instance.exports.add(10, 20);
document.getElementById('output').textContent = result;
}
loadWasm();
</script>
</body>
</html>
React との連携
JSX(.ngsx)用のランタイムには props
基盤が存在しますが、ドキュメント化は保留です。以下の
React 側サンプル(TypeScript の JSX)は参考用です。
コンポーネント例
import React, { useEffect, useState } from 'react';
function WasmComponent() {
const [result, setResult] = useState<number | null>(null);
useEffect(() => {
async function loadWasm() {
const response = await fetch('/output.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes);
const result = instance.exports.process(42);
setResult(result);
}
loadWasm();
}, []);
return (
<div>
<h1>NagiScript Wasm Result</h1>
<p>Result: {result}</p>
</div>
);
}
export default WasmComponent;
型定義ファイル (.d.ts)
コンパイル時に自動生成される型定義:
// output.d.ts
export function add(a: number, b: number): number;
export function process(input: string): string;
メモリ操作
JS 側からのメモリアクセス
const memory = new WebAssembly.Memory({ initial: 256 });
const { instance } = await WebAssembly.instantiate(bytes, {
env: { memory }
});
// メモリに文字列を書き込む
const encoder = new TextEncoder();
const str = encoder.encode("Hello, Wasm!");
const ptr = instance.exports.malloc(str.length);
new Uint8Array(memory.buffer, ptr, str.length).set(str);
// Wasm 関数を呼び出す
instance.exports.process_string(ptr, str.length);
ビルド設定
プロジェクト設定ファイル(project.toml)によるビルド設定は将来仕様です。現行は
nagiscript wasm main.ngs [-o PATH] の CLI
で出力先を指定します。
project.toml
[build]
target = "wasm"
output = "dist/"
[build.wasm]
memory_initial = 256
memory_maximum = 512
パフォーマンスのヒント
- 関数エクスポートを最小限に: 必要な関数のみエクスポート
- バッチ処理: 大量のデータは一度に渡す
-
TypedArray の活用: メモリ操作には
Uint8Arrayを使用
