💭

SvelteでWebAssemblyでTypeScriptでRollupで: Rustが征く(5)

2021/09/14に公開

要素多過ぎ問題

関連記事:

Rustが征くシリーズ過去記事

前回の記事でTypeScriptrollup.jsWebAssemblyを繋いだ。
次はフロンドエンドフレームワークと繋いでみよう。

フロントエンドはYewって手もあったが、
ちまちま調整が必要なフロントエンドと、
ちょっと動かすだけでも大変なRustは相性が悪い。
なのでJavaScriptフレームワークを選択。
けど、VueやReactはもううんざりなので、
最近話題のSvelteを使う。

Svelte is a tool for building fast web applications.
It is similar to JavaScript frameworks such as React and Vue, which share a goal of making it easy to build slick interactive user interfaces.
But there's a crucial difference: Svelte converts your app into ideal JavaScript at build time, rather than interpreting your application code at run time. This means you don't pay the performance cost of the framework's abstractions, and you don't incur a penalty when your app first loads.
You can build your entire app with Svelte, or you can add it incrementally to an existing codebase. You can also ship components as standalone packages that work anywhere, without the overhead of a dependency on a conventional framework.
Svelte

VueからVirtual DOMの概念を撤去したもの。
コード量は他の二つに比べて少なくなるとのこと。

一から記述すると本編が長くなりすぎるので、
今回はテンプレートを使用する。

ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪

------------------- ↓ 本題はここから ↓-------------------

事前準備

Rust, Node.jsが稼働することが前提。
過去記事を参照のこと
以下のコマンドが実行できればOk。

cargo --version
npm --verion
rustup target add wasm32-unknown-unknown
cargo install cargo-edit

Svelteのテンプレートからプロジェクトを作成

Svelteのビルドをrollup.jsで実行するテンプレートを使用する

デフォルトではJavaScriptで構成されているのだが、
TypeScriptに置換するスクリプトが用意されている。
使用するパッケージのバージョンも古いので、
それらを新しいものに設定し直す。

npx degit sveltejs/template svelte-wasm
cd svelte-wasm
node ./scripts/setupTypeScript.js
npx npm-check-updates -u
npm i -D @wesley-clements/rollup-plugin-raw-wasm
npm run dev

(・∀・) 簡単ですね!!

rollup.jsの設定を調整

WebAssemblyをビルドする前にrollup.jsの設定を調整しておく。
npmでインストールしたwasmローダーを設定に加える。

./rollup.config.js
import css from 'rollup-plugin-css-only';
+ import { rawWasm } from "@wesley-clements/rollup-plugin-raw-wasm"

const production = !process.env.ROLLUP_WATCH;
・・・
typescript({
  sourceMap: !production,
  inlineSources: !production
}),
+ rawWasm({
+   publicPath: '/build/'
+ }),

// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),

WebAssemblyモジュールを用意

cargoコマンドでRustのソースを設置する

cargo init --lib
printf '[lib]\ncrate-type = ["cdylib", "rlib"]' | tee -a ./Cargo.toml
cargo add wasm-bindgen js-sys

実装

./src/lib.rs
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn sum_numbers(numbers: &[i32]) -> i32 {
    numbers.iter().sum()
}

ビルド

wasm-pack build --target web --release --out-name svelte-wasm

Svelte側にWebAssemblyを実装

ソースコード

WebAssemblyは基本的に非同期処理で呼び出す必要があるので、
全体的に非同期に変えておく。

./src/main.ts
import App from './App.svelte'
import init, {sum_numbers} from "../pkg/svelte-wasm.js"
import path from "../pkg/svelte-wasm_bg.wasm"

const app = (async () => {
  await init(path)
  const app = new App({
    target: document.body,
    props: {
      name: 'world',
      sum_numbers,
    }
  })
})()
export default app;

ビュー側

./src/App.svelte
<script lang="ts">
  export let name: string;
+ export let sum_numbers: Function;
+ const sum = sum_numbers(new Int32Array([5,60,300]))

</script>

<main>
-  <h1>Hello {name}!</h1>
+  <h1>Hello {name} {sum}!</h1>
  <p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
</main>

実行

npm run dev

(・∀・)(・∀・)Yeah!!!!

フロントエンドの構成が固まった。

------------------- ↓ 後書はここから ↓-------------------

esbuild使わないの?

時系列ではこちらの記事が先だったが、
以下の記事を先に公開している。

https://zenn.dev/dozo/articles/54f697ff41f100

要素が増えすぎると煩雑になるので、
この記事ではesbuildに関する記述は抜いた。

Discussion