Deno 是一个用 Rust 编写的现代化、零配置的 JavaScript 运行时。其核心是 Rusty V8,一个为 V8 的 C++ API 提供高质量、零开销 Rust 绑定的库。在过去的五年里,Rusty V8 经历了近 150 次发布,在 crates.io 上积累了超过 310 万次下载。今天,我们很高兴宣布一个重要的里程碑:Rusty V8 现已稳定并可用于生产环境。
虽然我们很想用“1.0”版本来纪念这一刻,但 Rusty V8 将完全跳过 1.0 版本。相反,我们正在与 Chrome 的版本控制方案对齐,以与 V8 保持同步。Rusty V8 的第一个稳定版本将是 129.0.0,与 Chrome 129 保持一致。此版本保证了 API 的稳定性,使我们摆脱了多年的 0.x 版本,并巩固了 Rusty V8 作为基于 V8 构建的开发人员的可靠工具的地位。
Rusty V8 有何特别之处?
Rusty V8 赋予 Rust 开发者对 V8 的 C++ API 的直接、零开销访问。它以其完整性以及与高性能环境的无缝集成而脱颖而出。一个关键特性是 Rusty V8 自动将 V8 复杂的构建系统集成到 Cargo 中,使开发人员无需手动设置即可轻松将 V8 嵌入到 Rust 项目中。使用 Rusty V8,您可以
- 构建自定义 JavaScript 运行时: Rusty V8 是构建您自己的 JavaScript 运行时的理想选择,无论是用于嵌入式设备、无服务器环境还是插件系统。
- 运行 WebAssembly 模块: Rusty V8 无缝执行 WebAssembly (Wasm) 模块,使您能够与 JavaScript 一起运行高性能代码。
- 利用 V8 Inspector: 使用 V8 Inspector 为您的 JavaScript 运行时添加调试功能,如断点和性能分析。
- 使用 V8 Fast API: Rusty V8 允许您以最小开销从 JavaScript 调用 Rust 函数,非常适合高性能应用程序。
- 自动内存管理: V8 的
cppgc
垃圾收集器有助于高效管理内存,减少复杂应用程序中手动内存处理的需求。
起源故事
Rusty V8 的旅程始于 2015 年,当时我正在尝试使用名为 v8worker 的库在 Go 中构建 JavaScript 运行时。最终,v8worker 被用于第一个 Deno 演示。然而,随着 Deno 的发展,很明显 Go 不适合该项目,因为担心 Go 自身的 GC 会与 V8 的 GC 产生不良冲突。
2019 年底,Deno 联合创始人 Bert Belder 主导了为 V8 创建直接 Rust 绑定的工作。挑战在于在不牺牲性能或安全性的前提下,将 V8 复杂的 C++ API 绑定到 Rust。经过大量努力,Rusty V8 应运而生——它是一个对 V8 的零开销 Rust 绑定,提供了对 V8 的完全控制,同时通过 Rust 的所有权模型确保了内存安全。
使用 Rusty V8
以下是一个使用 Rusty V8 将 JavaScript 嵌入 Rust 程序的简单示例
fn main() {
// Initialize V8.
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
// Create a new Isolate and make it the current one.
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
// Create a stack-allocated handle scope.
let handle_scope = &mut v8::HandleScope::new(isolate);
// Create a new context.
let context = v8::Context::new(handle_scope, Default::default());
// Enter the context for compiling and running the hello world script.
let scope = &mut v8::ContextScope::new(handle_scope, context);
// Create a string containing the JavaScript source code.
let code = v8::String::new(scope, "'Hello' + ' World!'").unwrap();
// Compile the source code.
let script = v8::Script::compile(scope, code, None).unwrap();
// Run the script to get the result.
let result = script.run(scope).unwrap();
// Convert the result to a string and print it.
let result = result.to_string(scope).unwrap();
println!("{}", result.to_rust_string_lossy(scope));
}
Rusty V8 的内存安全特性相对于 C++ API 是一个核心优势。例如,在 Rust 中,像 Local<T>
这样的句柄与特定作用域绑定,并在编译时强制执行。这可以防止因使用或返回无效句柄而导致的错误——而 C++ 开发者必须手动管理这些。在 Rust 中,如果您尝试在 Local<T>
的作用域之外使用它,编译器将捕获此错误。
以下是一个 Rust 防止无效句柄使用的快速示例
let isolate = &mut v8::Isolate::new(Default::default());
{
let scope1 = &mut v8::HandleScope::new(isolate);
let local = v8::Integer::new(scope1, 123);
// Attempting to use 'local' outside the scope will fail at compile time
let invalid_local = {
let scope2 = &mut v8::HandleScope::new(scope1);
v8::Integer::new(scope2, 456) // Safe to use in this scope
};
// Rust will not allow 'invalid_local' to be accessed here.
}
版本控制
为了与 V8 保持同步,Rusty V8 将遵循 Chrome 的版本控制方案。第一个稳定版本是 129.0.0,对应于 Chrome 129。尽管 V8 不遵循语义化版本(semver),并且即使在次要版本中也可能引入破坏性更改,但 Rusty V8 将遵循 semver,以确保 Rust 开发人员的兼容性和稳定性。
每 4 周,Rusty V8 将升级其 V8 依赖项并提升其主版本号。这意味着 Rusty V8 API 的破坏性更改只会在 V8 升级时发生,并且版本将始终反映底层的 V8 版本。
可用于生产环境
Rusty V8 现已成为一个稳定、可用于生产的库,用于在 Rust 中构建高性能 JavaScript 和 WebAssembly 运行时。无论您是创建自定义 JavaScript 运行时、在 Rust 支持的应用程序中嵌入 JS,还是探索服务器端 JavaScript 应用程序,Rusty V8 都将 V8 的灵活性与 Rust 的安全性和性能保证相结合。
通过访问 docs.rs/v8 上的完整文档深入了解。