🕌
LLRTからロードできるネイティブなESMモジュールを追加する
LLRT only support a fraction of the Node.js APIsなので既存のNode.jsのモジュールを動かすためには自分でランタイムにサポートを入れる必要がある
これには動作時にshimを指し込むとかビルド時にコードを書き換えるなどの方法があるが、LLRTはrquickjsのAPIに沿って設計されているので自分でRustで書いて拡張するのも結構敷居が低い
ビルド環境はBuilding from sourceのとおり行えば当方aarch64-apple-darwinだが問題なく構築できた
注意点としてはLLRTは内部バイナリ表現としてfacebook/zstdを使っていて、それのビルドにzigコンパイラが必要になったりする
あとrustcの新しめのnightlyを使った方が問題が起きなさそう。我が家ではrustc 1.76.0 (07dca489a 2024-02-04)
が動いていた
makeが済んだら以下コマンドが実行できれば環境は整っている
❯ ./target/debug/llrt --version
LLRT (darwin arm64) 0.1.6-beta
全体の流れとしては以下
-
src/
以下のmodでrquickjsの独自ModuleDefを実装 -
src/main.rs
に上記を追加 -
src/vm.rs
にJS(ESM)とのマッピングを定義
src/hello/mod.rs
を追加して以下のように書く
src/hello/mod.rs
use rquickjs::{module::{Declarations, Exports, ModuleDef}, prelude::{Func}, Ctx, Result};
use crate::module::export_default;
pub struct HelloModule;
impl HelloModule {
/*
呼び出される関数本体コード
*/
pub fn greet(_ctx: Ctx, name: String) -> String {
format!("Hello, {}!", name)
}
}
impl ModuleDef for HelloModule {
fn declare(declare: &mut Declarations) -> Result<()> {
declare.declare("greet")?;
declare.declare("default")?;
Ok(())
}
fn evaluate<'js>(ctx: &Ctx<'js>, exports: &mut Exports<'js>) -> Result<()> {
/*
export_default: LLRTが用意するヘルパー関数 Default import空間で設定する
*/
export_default(ctx, exports, |default| {
default.set("greet", Func::from(Self::greet))?;
Ok(())
})?;
Ok(())
}
}
main.rsに下位モジュールとして定義する
src/main.rs
@@ -34,6 +34,8 @@ mod uuid;
mod vm;
mod xml;
+mod hello;
+
use minimal_tracer::MinimalTracer;
use rquickjs::{AsyncContext, Module};
use std::{
vm.rsは重要ファイルでLLRTのJavaScruipt VMの実装
ESMの"hello"とHelloModuleを対応付けする
src/vm.rs
@@ -59,6 +59,7 @@ use crate::{
},
uuid::UuidModule,
xml::XmlModule,
+ hello::HelloModule,
};
macro_rules! create_modules {
@@ -99,7 +100,8 @@ create_modules!(
"buffer" => BufferModule,
"child_process" => ChildProcessModule,
"util" => UtilModule,
"uuid" => UuidModule,
+ "hello" => HelloModule
);
これをテストするためのJSコードも用意
test.mjs
import {greet} from "hello";
console.log(greet("LLRT"));
Hello Worldに必要なのはこれだけだが、Rustコードを編集しながらデバッグしたくなる
以下のように呼び出す
❯ cargo run -- test.mjs
Compiling llrt v0.1.6-beta (/src/llrt)
Finished dev [unoptimized + debuginfo] target(s) in 4.33s
Running `target/debug/llrt test.mjs`
Hello, LLRT!
Hello, LLRT!
が表示されたのでhelloモジュールが動作していることが分かる
Discussion