はじめに
Elixir をブラウザで動かしてみました。サーバー不要、インストール不要です。
遅ればせながら、AtomVMにようやく触れてみました。
デモ: https://elixir-browser-eval.torifuku-kaiou.app/
たとえば、以下のコードを打ち込んでEvaluateしてみてください。
Enum.map(1..10, & &1 * 2)
この記事では、WebAssembly (Wasm)、AtomVM、Popcorn という3つの技術を紹介し、実際に Cloudflare Pages にデプロイするまでの過程をまとめます。
WebAssembly (Wasm) とは
WebAssembly は、モダンブラウザで動作するコンパクトなバイナリフォーマットです。JavaScript 以外の言語を「Wasm にコンパイルして」ブラウザ内で実行できるようにします。
特徴:
- 高速: ネイティブに近い速度で実行
- 安全: サンドボックス内で動作
- ポータブル: どのブラウザでも同じように動く
AtomVM とは
AtomVM は、軽量な Erlang VM です。
通常の BEAM VM は数十MBのメモリを必要としますが、AtomVM は構成によって数百KB〜数MB程度のフットプリントで動作します。主なターゲットは:
- マイクロコントローラー: ESP32、STM32 など
- WebAssembly: ブラウザ内で BEAM バイトコードを実行
AtomVM は Erlang/Elixir のサブセットをサポートしており、Code.eval_string/3 も動作します。
Popcorn とは
Popcorn は、Software Mansion が開発した Elixir を WebAssembly で動かすためのライブラリです。
Popcorn がやってくれること:
- ビルド時に Elixir コードを BEAM バイトコードにコンパイル(
mix popcorn.cook) - AtomVM (Wasm版) と一緒に
bundle.avmとしてパッケージング - ブラウザ側の JavaScript ブリッジを提供(
popcorn.js)
手元で動かしてみる
Popcorn のサンプル eval_in_wasm を動かします。
git clone https://github.com/software-mansion/popcorn.git
cd popcorn
# mise で OTP と Elixir のバージョンを合わせる
mise trust
mise install
cd examples/eval_in_wasm
mix deps.get
mix popcorn.cook
mix popcorn.cook を実行すると、static/ ディレクトリに成果物が生成されます:
static/
├── index.html
├── script.js
├── style.css
└── wasm/
├── AtomVM.mjs
├── AtomVM.wasm
├── bundle.avm # BEAM バイトコード
├── popcorn.js
└── popcorn_iframe.js
ローカルサーバーを起動:
elixir server.exs
# http://localhost:4000 でアクセス
eval_in_wasm.ex
Elixir側の主要な実装です。美しいです。感動です。
Cloudflare Pages にデプロイ
ハマりポイント:ヘッダー設定
Wasm を動かすには、ページが Cross-Origin Isolated になる必要があります。これを満たすために COOP/COEP が必須です。さらに、.avm と .wasm を正しい MIME で配信するために Content-Type を明示しておくと安全です。
| ヘッダー | 値 | 理由 |
|---|---|---|
Cross-Origin-Opener-Policy |
same-origin |
Cross-Origin Isolated を有効化 |
Cross-Origin-Embedder-Policy |
require-corp |
Cross-Origin Isolated を有効化 |
Content-Type |
application/octet-stream |
.avm をバイナリとして配信 |
Content-Type |
application/wasm |
.wasm の正しい MIME |
Cloudflare Pages では _headers ファイルで設定します:
/*
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
/wasm/*.avm
Content-Type: application/octet-stream
/wasm/*.wasm
Content-Type: application/wasm
※ 同一オリジン配信だけなら Access-Control-Allow-Origin は不要です。別オリジンのリソースを読み込む場合は、CORS / CORP の設定が追加で必要になります。
デプロイ手順
- GitHub にリポジトリを作成し、
static/の中身と_headersを push - Cloudflare Pages でプロジェクトを作成
- GitHub リポジトリを連携
- ビルド設定は不要(静的ファイルをそのまま配信)
リポジトリ
まとめ
- WebAssembly: ブラウザで JavaScript 以外の言語を動かす技術
- AtomVM: 軽量 Erlang VM、Wasm にもコンパイル可能
- Popcorn: Elixir を Wasm で動かすためのライブラリ
-
Cloudflare Pages:
_headersファイルで COOP/COEP ヘッダーを設定
Elixir がブラウザで動く時代が来ました。来ていました。ぜひ試してみてください。
