Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Vite + Rust で Wasm を ES Modulesとして使う

Avatar for hacusk hacusk
October 18, 2026

Vite + Rust で Wasm を ES Modulesとして使う

千歳ゆるい勉強会vol.8にて発表した内容です

Avatar for hacusk

hacusk

October 18, 2026

More Decks by hacusk

Other Decks in Programming

Transcript

  1. Vite + Rust で Wasm を ES Modulesとして 使う import

    { add } from './main.wasm' HakataYusuke(@hacusk) 千歳ゆるい勉強会 vol.8 2026.10.18(Sun.) @公立千歳科学技術大学 1
  2. $ whoami Name: はくすけ(@hacusk) / HakataYusuke Job: 株式会社モニクル SWE Language:TypeScript,

    Go, PHP… FavoriteTech: MultiPlatformなもの, OSS, ネ ットワーク Love: 声優, 旅行, ライブ, アイドル, 車, モータ ースポーツ, ガジェット, 飛行機, 麻雀 Community: 函館本線沿線勉強会, フロントエ ンドカンファレンス北海道実行委員会, OSC北 海道実行委員会, 一般社団法人LOCAL Website: https://hacusk.net/ 2
  3. WebAssembly(Wasm)ってなに? 普通のコンパイル C / Rust / Go → その CPU

    向けの機械語 x86 用バイナリは ARM では動かない OS・アーキテクチャに依存する Wasm → 仮想マシン向けのバイナリ ブラウザ(や WASI)が実行してくれる 一度作れば、環境が違っても同じファイル が動く JVM(Java のバイトコード)に近い発想。 違いは、最初から Web ブラウザで速く・安全に動かすことを狙って設計されている点(W3C 標準)。 3
  4. Wasm をブラウザで使う従来の方法 const res = await fetch('./add.wasm') const { instance

    } = await WebAssembly.instantiateStreaming(res) const add = instance.exports.add 手動でフェッチ・インスタンス化が必要 普通の JS インポートとまったく異なる体験 5
  5. Vite の Wasm サポート — 2 段階 アプローチ 構文 特徴

    ?init import init from './add.wasm?init' init 関数を呼び、exports を取り出す ESM 統合 import { add } from './add.wasm' 通常の named import と同じ ESM 統合は WebAssembly/ES Module Integration 提案 に準拠 Vite 8.1〜 コアでサポート(追加プラグイン不要) 6
  6. 言語の選択 — TinyGo vs Rust TinyGo Rust ( wasm32-unknown-unknown )

    500 B 不要 ゼロ Wasm サイズ 21 KB JS ランタイム wasm_exec.js 必須 Wasm imports go.* 多数 ?init 呼び出し await init(go.importObject) await init() Rust はランタイムを含まない 純粋な Wasm を出力 → ESM 統合と相性が良い 7
  7. Rust 側のコード // wasm/src/lib.rs #[unsafe(no_mangle)] // edition 2024 では unsafe

    が必要 pub fn add(a: i32, b: i32) -> i32 { a + b } #[unsafe(no_mangle)] pub fn fibonacci(n: u32) -> u64 { /* ... */ } // → JS では BigInt # Cargo.toml [lib] crate-type = ["cdylib"] # C 互換の動的ライブラリとして出力 8
  8. Vue コンポーネントでの使用 <script setup lang="ts"> import { add, fibonacci }

    from '../assets/main.wasm' // 非同期モジュール — 親で <Suspense> が必要 </script> <template> <output>{{ add(3, 4) }}</output> </template> 普通の JS モジュールと 完全に同じ感覚 でインポートできる 9
  9. ハマりどころ(Vite 8.1+) 型は手書き .d.wasm.ts + allowArbitraryExtensions // main.d.wasm.ts export declare

    function add(a: number, b: number): number 出典: Vite — ESM 統合 / TSConfig — allowArbitraryExtensions 非同期モジュール は TLA 相当の async module → Vue では親に <Suspense> .wasm <Suspense> <WasmDemo /> </Suspense> 出典: Vite — ESM 統合 11
  10. まとめ Rust (edition 2024) └─ cargo wasm └─ main.wasm (500B、imports

    ゼロ) └─ Vite 8.1+(コアの ESM 統合) └─ import { add } from './main.wasm' └─ Vue コンポーネントで直接呼び出し Rust × wasm32-unknown-unknown が ESM 統合に最も相性が良い Vite 8.1〜 は import { add } from './x.wasm' が標準サポート 型は .d.wasm.ts + allowArbitraryExtensions で解決 コード: https://github.com/hacusk/vite-wasm-esm-integration-example 12