15 个版本
0.2.3 | 2024年8月1日 |
---|---|
0.2.2 | 2024年7月22日 |
0.2.1-alpha.1 | 2024年6月24日 |
0.1.12 | 2024年6月3日 |
0.1.10 | 2024年5月21日 |
#253 in Web编程
每月303次下载
1.5MB
35K SLoC
Rust-JSC
Rust-JSC 是一个Rust库,它为JavaScriptCore引擎提供了一个高级绑定。它允许您从Rust应用程序中与JavaScript代码进行交互。
功能
- JavaScriptCore引擎的高级绑定
- 扩展API以与JavaScriptCore交互
- 支持ES模块
- 支持rust原生模块(合成模块)
安装
将以下行添加到您的 Cargo.toml
文件中
[dependencies]
rust_jsc = { version = "0.2.2" }
使用方法
评估脚本
use rust_jsc::JSContext;
let ctx = JSContext::new();
let result = ctx.evaluate_script("console.log('Hello, world!'); 'kedojs'", Some(0));
assert!(result.is_ok());
评估模块
use rust_jsc::JSContext;
let filename = "/path/filename.js";
let ctx = JSContext::new();
let result = ctx.evaluate_module(filename);
assert!(result.is_ok());
类型数组
use crate::{JSArrayBuffer, JSContext, JSTypedArray, JSTypedArrayType};
fn main() {
let ctx = JSContext::new();
let array = ctx
.evaluate_script("const array = new Uint8Array([5, 4, 4, 5]); array", None)
.unwrap();
let array = JSTypedArray::from_value(array).unwrap();
assert_eq!(array.array_type().unwrap(), JSTypedArrayType::Uint8Array);
assert_eq!(array.len().unwrap(), 4);
assert_eq!(array.byte_offset().unwrap(), 0);
assert_eq!(array.byte_len().unwrap(), 4);
assert_eq!(array.as_vec::<u8>().unwrap(), &[5, 4, 4, 5]);
}
数组
use rust_jsc::{JSArray, JSContext, JSValue};
let ctx = JSContext::new();
let array = JSArray::new_array(
&ctx,
&[
JSValue::number(&ctx, 1.0),
JSValue::number(&ctx, 2.0),
JSValue::number(&ctx, 3.0),
]
).unwrap();
assert_eq!(array.as_string().unwrap(), "1,2,3");
回调
use rust_jsc::{JSContext, JSFunction, JSObject, JSValue};
#[callback]
fn log_info(
ctx: JSContext,
_function: JSObject,
_this: JSObject,
arguments: &[JSValue],
) -> JSResult<JSValue> {
let message = arguments.get(0).unwrap().as_string().unwrap();
println!("INFO: {}", message);
Ok(JSValue::undefined(&ctx))
}
let ctx = JSContext::new();
let global_object = ctx.global_object();
let object = JSObject::new(&ctx);
let attributes = PropertyDescriptorBuilder::new()
.writable(true)
.configurable(true)
.enumerable(true)
.build();
let function = JSFunction::callback(&ctx, Some("log"), Some(log_info));
object
.set_property("log", &function, attributes)
.unwrap();
global_object
.set_property("console", &object, attributes)
.unwrap();
let result = ctx.evaluate_script("console.log('Hello, World!')", None);
assert!(result.is_ok());
合成模块
use rust_jsc::{
callback, module_evaluate, module_fetch, module_import_meta, module_resolve,
JSContext, JSFunction, JSObject, JSResult, JSString, JSStringRetain, JSValue, JSPromise,
PropertyDescriptorBuilder, JSModuleLoader, PropertyDescriptor,
};
#[module_resolve]
fn module_loader_resolve(
ctx: JSContext,
key: JSValue,
referrer: JSValue,
script_fetcher: JSValue,
) -> JSStringRetain {
JSStringRetain::from("@rust-jsc")
}
#[module_evaluate]
fn module_loader_evaluate(
ctx: JSContext,
key: JSValue,
) -> JSValue {
// Module Loader Evaluate
// is called only when evaluating Synthetic Modules
let object = JSObject::new(&ctx);
let keydata = JSValue::string(&ctx, "name");
let value = JSValue::string(&ctx, "John Doe");
object.set(&keydata, &value, PropertyDescriptor::default()).unwrap();
object.into()
}
#[module_fetch]
fn module_loader_fetch(
ctx: JSContext,
key: JSValue,
attributes_value: JSValue,
script_fetcher: JSValue,
) -> JSStringRetain {
// Module Loader Fetch
// fetch the content from file or network
JSStringRetain::from("let name = 'Kedojs'; export default name;")
}
#[module_import_meta]
fn module_loader_create_import_meta_properties(
ctx: JSContext,
key: JSValue,
script_fetcher: JSValue,
) -> JSObject {
let key_value = key.as_string().unwrap();
let object = JSObject::new(&ctx);
object.set_property("url", &key, Default::default()).unwrap();
object
}
fn main() {
let ctx = JSContext::new();
let global_object = ctx.global_object();
let module_loader = JSAPIModuleLoader {
// Disable the builtin file system loader
disableBuiltinFileSystemLoader: true,
moduleLoaderResolve: Some(module_loader_resolve),
moduleLoaderEvaluate: Some(module_loader_evaluate),
moduleLoaderFetch: Some(module_loader_fetch),
moduleLoaderCreateImportMetaProperties: Some(
module_loader_create_import_meta_properties,
),
};
ctx.set_module_loader(module_loader);
let result = ctx.evaluate_module("./test.js");
assert!(result.is_ok());
}
支持的平台
下表显示了支持的平台
平台 | 架构 | 目标 | 支持 |
---|---|---|---|
macOS | x86_64 | x86_64-apple-darwin | ✅ |
macOS | aarch64 | aarch64-apple-darwin | ✅ |
Linux | x86_64 | x86_64-unknown-linux-gnu | ✅ |
Linux | aarch64 | aarch64-unknown-linux-gnu | 即将推出.. |
Linux | x86_64 | x86_64-unknown-linux-musl | 即将推出.. |
Linux | aarch64 | aarch64-unknown-linux-musl | 即将推出.. |
Windows | x86_64 | x86_64-pc-windows-msvc | ❌ |
常见问题解答
如何构建静态库?
默认情况下,此库将尝试从GitHub镜像下载静态库。如果您想自己构建静态库,可以克隆rust-jsc仓库并从Dockerfile构建Docker镜像。它将为您构建静态库并将它们复制到提供的路径。
DOCKER_BUILDKIT=1 docker build -o ./.libs -t $(IMAGE_NAME) .
此命令仅在Linux上有效。对于macOS,您应从Makefile运行以下命令来构建JavaScriptCore的静态库
make build-jsc
然后设置环境变量RUST_JSC_CUSTOM_BUILD_PATH
为静态库的路径。
⚠️ 请注意,此库使用自定义版本的WebKit来生成绑定。这个版本的WebKit是原始WebKit的一个分支,包含一些补丁以支持esmodules和其他功能。
如何解决链接问题?
如果您遇到链接静态库的问题,请尝试设置以下环境变量
# For macOS
# Example path to the JavaScriptCore static libraries
DYLD_LIBRARY_PATH=/Users/${user}/Documents/Projects/WebKit/WebKitBuild/JSCOnly/Release/lib:$DYLD_LIBRARY_PATH
# For Linux
# Example path to the JavaScriptCore static libraries
LD_LIBRARY_PATH=/Users/${user}/Documents/Projects/WebKit/WebKitBuild/JSCOnly/Release/lib:$LD_LIBRARY_PATH
许可协议
本项目采用MIT许可协议 - 请参阅LICENSE文件以获取详细信息。
依赖项
~270-720KB
~17K SLoC