📦
Rust で初めての npm package 開発
はじめに
筆者は最近 Rust の学習を始めました。
その中で、実際に何か動くものを作ってみたいと思い npm package 作ってみました。
作ったもの
日付を表示するライブラリです。
<script setup lang="ts">
import { today } from 'date-rs-t6'
</script>
<template>
<!--Today: 2024/11/11(月) -->
<p>Today: {{ today() }}</p>
</template>
ながれ
全体的なながれは以下のようになっています。
- Rust のコードをコンパイルし、WebAssembly や TS, JS, package.json を生成
- それらを npm に publish
- 実際に、Vite + Vue のプロジェクトで publish したパッケージをインストールして使用
詳細
WebAssembly
- ウェブブラウザで実行できるコード
- HTML, CSS, JavaScript, WebAssembly
-
.wasm
という拡張子のバイナリファイル - C, C++, Rust などのコンパイル先とすることが可能
プロジェクトの作成
- cargo を使ってプロジェクトを作成
- cargo は Rust のビルドシステム兼パッケージマネージャ
- 今回はライブラリを作るため、
cargo new --lib
を実行 - 初期のディレクトリ構成は以下
Cargo.toml
-
src
配下にlib.rs
$ cargo new --lib sample-project
.
├── Cargo.toml
└── src
└── lib.rs
クレート
chrono
- グレゴリオ暦の日付、時刻を操作するクレート
- 今回はこちらを使って日付や曜日を取得
src/lib.rs
use chrono::prelude::*;
fn today() -> String {
let now: DateTime<Local> = Local::now();
let day_of_week = match now.weekday() {
Weekday::Mon => "月",
Weekday::Tue => "火",
Weekday::Wed => "水",
Weekday::Thu => "木",
Weekday::Fri => "金",
Weekday::Sat => "土",
Weekday::Sun => "日",
};
format!("{}({})", now.format("%Y/%m/%d").to_string(), day_of_week)
}
wasm-bindgen
- Rust で実装した関数を JS が呼び出したり、Rust が JS の API を実行できる
-
#[wasm_bindgen]
という属性を付与して使う
src/lib.rs
use chrono::prelude::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn today() -> String {
let now: DateTime<Local> = Local::now();
let day_of_week = match now.weekday() {
Weekday::Mon => "月",
Weekday::Tue => "火",
Weekday::Wed => "水",
Weekday::Thu => "木",
Weekday::Fri => "金",
Weekday::Sat => "土",
Weekday::Sun => "日",
};
format!("{}({})", now.format("%Y/%m/%d").to_string(), day_of_week)
}
wasm-pack
- WebAssembly をパッケージとして、npm レジストリに公開可能
- 今回は、
build
,login
,publish
しか使っていないが、他にも以下のようなコマンドがある - より詳細な内容は以下の記事を参照
- build は、target オプションで bundler を指定
Commands:
build 🏗️ build your npm package!
pack 🍱 create a tar of your npm package but don't publish!
new 🐑 create a new project with a template
publish 🎆 pack up your npm package and publish!
login 👤 Add an npm registry user account! (aliases: adduser, add-user)
test 👩🔬 test your wasm!
help Print this message or the help of the given subcommand(s)
$ wasm-pack build --target bundler
pkg
├── README.md
├── sample-project.d.ts
├── sample-project.js
├── sample-project_bg.js
├── sample-project_bg.wasm
├── sample-project_bg.wasm.d.ts
└── package.json
$ wasm-pack publish
Vite + Vue のプロジェクトで使用する
- create vite で作成したプロジェクトで実際に動作確認を行う
- 動作確認環境は以下
-
"vue"
:"3.5.12"
-
"typescript"
:"5.6.2"
-
"vite"
:"5.4.9"
-
$ npm i sample-project
$ npm run dev
実際に開発サーバーを起動すると以下のようなエラーになってしまいました。
これは公式のドキュメントにも記載があり、エラーを解決するには別途プラグインの導入が必要でした。
WebAssembly の ES モジュール統合の提案は現時点ではサポートしていません。 vite-plugin-wasm か、もしくは他のコミュニティーのプラグインを使用して対処してください。
よって、最終的な vite.config.ts
は以下のようになります。
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import wasm from 'vite-plugin-wasm'
import topLevelAwait from "vite-plugin-top-level-await";
export default defineConfig({
plugins: [
vue(),
wasm(),
topLevelAwait()
]
})
これらの対応をすることで画面が正常に表示されました。
Discussion