🐙

DartとWebAssembly

2023/12/20に公開

この記事はWebAssembly Advent Calendar 2023の20日目の記事です.

Wasm I/O 2023

今年3月の Wasm I/O 2023 にて,Flutter, Dart and Wasm-GC: A new model for Web applicationsというセッションがありました.

https://youtu.be/Nkjc9r0WDNo?si=ePCNbApsLPVSyV6y

今回話したいところをかい摘むと次のような内容でした.

  1. Wasm-GCの登場によって,DartがWasmをサポートするようになる(dart2wasm).
  2. DartがWasmをサポートするようになると,Flutter(for Web)のロジックが全てWasm製になる.
  3. 速くて軽量🤘

Wasm-GCはガベージコレクタを持つ多くの現代言語がよりWasmをサポートしやすくするという目的から発したプロポーザルで,今年の10月頃にChromeやFirefoxの最新版でサポートされるようになりました.
Dartのコミュニティはこのプロポーザルを受けてWasmのサポートに取り組んでいます.

実際, Flutter の master(main) channel [1]ではビルドオプションに --wasm が追加されており,このオプションを用いてビルドするとmain.dart.jsの代わりにmain.dart.wasmmain.dart.mjsが生成されることが確認できます.

$ flutter build web --release --web-renderer=canvaskit --wasm

Dart

さて,現行のDart 3.2ではdart2wasmがDartのコンパイルコマンドには組み込まれていませんが,Dart 3.2 の告知にはdart2wasm はほぼ完成しているとの言及がありました.

https://medium.com/dartlang/dart-3-2-c8de8fe1b91f

そしてなんと,Dart3.3(開発版)にはdart2wasmがコンパイルコマンドに組み込まれているようです.

$ dart --version
Dart SDK version: 3.3.0-241.0.dev (dev) (Mon Dec 18 12:02:16 2023 -0800) on "macos_arm64"
$ dart compile wasm -h
Compile Dart to a WebAssembly/WasmGC module (EXPERIMENTAL).

Usage: dart compile wasm [arguments] <dart entry point>
-h, --help              Print this usage information.
-o, --output            Write the output to <file name>.
                        This can be an absolute or relative path.
    --[no-]optimize     Optimize wasm output using Binaryen wasm-opt.
                        (defaults to on)
-v, --verbose           Print debug output during compilation
    --enable-asserts    Enable assert statements.

Run "dart help" to see global options.

実際に次のmain.dartをビルドしてみると,main.wasmmain.mjsが生成されます.

void main() => print('Hello, Dart!');
$ dart compile wasm -o main.wasm main.dart 
*NOTE*: Compilation to WasmGC is experimental.
The support may change, or be removed, with no advance notice.

Generated wasm module 'main.wasm', and JS init file 'main.mjs'.

生成されたWasmを実行するには,次のようなコードを書きます.

import { instantiate, invoke } from "./main.mjs";
invoke(
  await instantiate(
    WebAssembly.compileStreaming(fetch(new URL("main.wasm", import.meta.url))),
  ),
);

これをDenoで実行すると次のような結果を得られます.

$ deno run --allow-read index.js
WebAssembly.String is undefined, adding polyfill
Hello, Dart!

(もちろんブラウザ上でも動作します)

まとめ

DartのWasmサポートが来るぞ...🎉

参考記事

https://zenn.dev/askua/articles/afe3a3b43b82cb
https://zenn.dev/tanishiking/articles/learn-wasm-gc

脚注
  1. コントリビューター向けの開発用ブランチ(flutter channel -hを参照) ↩︎

Discussion