使用Rust增强JS
使用Rust增强JS
Javascript
是目前全世界使用最广的语言(TIOBE排行榜比较迷,JS并没有排在第一位,我个人并不认同它的排名)。在过去这么多年中,围绕着Javascript
已经建立了庞大的基础设施生态:例如:
- 使用
webpack
来将多个js
文件打包成一个 - 使用
Babel
允许你用现代化的js
语法编写兼容旧浏览器的代码 - 使用
Eslint
帮助开发找出代码中潜在的问题,类似cargo clippy
。
以上的种种都在帮助js
成为更好的语言和工具,它们是Web
应用程序得以顺利、高效的开发和运行的基石。这些工具往往使用Javascript
语言编写,一般来说,是没有问题的,但是在某些时候,可能会存在性能上的瓶颈或者安全隐患,因此阴差阳错、机缘巧合下,Rust
成为了一个搅局者。
Javascript基建库
deno
首先出场的自然是咖位最重的之一,可以说正是因为deno
和swc
的横空出世,才让一堆观望的大神对于Rust实现Javascript
基建有了更强的信心。
deno
是node
半逆转后的字序,从此可以看出deno
是Node.js
的替代,它的目标是为Typescript/Javascript
提供一个更现代化、更安全、更强大 的运行时,同时内置了很多强大的工具,可以用于打包、编译成可执行文件、文档、测试、lint等。
值得一提的是,deno
的不少工具都使用了swc
进行建造,包括代码审查、格式化、文档生成等。
通过包引入的方式来对比下deno
和node
,大家可以自己品味下。
// node
const koa = require("koa");
const logger = require("@adesso/logger")
// deno
import { Application } from "https://deno.land/x/oak/mod.ts";
import { Logger } from "https://adesso.de/lib/logger.ts"
swc
swc
是Typescript/Javascript
编译器,它可以用来编译、压缩和打包JS,同时支持使用插件进行扩展,例如做代码变换等。
swc
目前正在被一些知名项目所使用,包括Next.js
,Parcel
和Deno
,还有些著名的公司也在使用它,例如Vercel
、字节跳动、腾讯等。
它的性能非常非常高,官方号称,在单线程下比Babel
快20倍,在4核心下比Babel
快70倍!
几个使用案例:
官方还提供了一个在线运行的demo,功能齐全,可以试试。
Rome
Rome
可以用来对JavaScript
、TypeScript
、HTML
、JSON
、Markdown
和 CSS
进行lint、编译、打包等功能,它的目标是替代Babel
、ESLint
、webpack
、Prettier
、Jest
等。
一开始Rome
是使用Typescript
开发,目前正在用Rust
进行重写。有趣的是: Rome
的作者也是Babel
的作者, 后者还是他在学习编译原理时做的。
fnm
fnm
是一个简单易用、高性能的Node
版本管理工具,还支持.nvmrc
文件(nvm
的node
版本描述文件)
boa
boa
是一个高性能的javascript
词法分析器,解析器和解释器,目前还是实验性质的。
napi
napi
可以用于构建基于Node API
的Nodejs
插件,目前由nextjs
主导开发。
volt
volt
是一个现代化的、高性能、安全可靠的Javascript
包管理工具。目前该库正处于活跃开发阶段,只供学习使用。
neon
neon
可以用于写安全、高性能的原生Nodejs
模块。
fn make_an_array(mut cx: FunctionContext) -> JsResult<JsArray> { // 创建一些值: let n = cx.number(9000); let s = cx.string("hello"); let b = cx.boolean(true); // 创建一个新数组: let array: Handle<JsArray> = cx.empty_array(); // 将值推入数组中 array.set(&mut cx, 0, n)?; array.set(&mut cx, 1, s)?; array.set(&mut cx, 2, b)?; // 返回数组 Ok(array) } register_module!(mut cx, { cx.export_function("makeAnArray", make_an_array) })
resvg-js
resvg-js是一个高性能svg
渲染库,使用Rust + Typescript实现。下面的图片通过svg
实现(羞~~~):
deno_lint
deno_lint, 由deno
团队出品的lint
工具,支持Javascript/Typescript
,支持Deno
也支持Node
。
优点之一就是极致的快:
[
{
"name": "deno_lint",
"totalMs": 105.3750100000002,
"runsCount": 5,
"measuredRunsAvgMs": 21.07500200000004,
"measuredRunsMs": [
24.79783199999997,
19.563640000000078,
20.759051999999883,
]
},
{
"name": "eslint",
"totalMs": 11845.073306000002,
"runsCount": 5,
"measuredRunsAvgMs": 2369.0146612000003,
"measuredRunsMs": [
2686.1039550000005,
2281.501061,
2298.6185210000003,
]
}
]
rslint
rslint是一个高性能、可定制性强、简单易用的Javascript/Typescript
lint分析工具。
$ echo "let a = foo.hasOwnProperty('bar');" > foo.js
$ rslint ./foo.js
error[no-prototype-builtins]: do not access the object property `hasOwnProperty` directly from `foo`
┌─ ./foo.js:1:9
│
1 │ let a = foo.hasOwnProperty('bar');
│ ^^^^^^^^^^^^^^^^^^^^^^^^^
│
help: get the function from the prototype of `Object` and call it
│
1 │ let a = Object.prototype.hasOwnProperty.call(foo, 'bar');
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
│
╧ note: the method may be shadowed and cause random bugs and denial of service vulnerabilities
Outcome: 1 fail, 0 warn, 0 success
help: for more information about the errors try the explain command: `rslint explain <rules>`
rusty_v8
rusty_v8是v8
的Rust语言绑定,底层封装了c++ API
。
用WASM增强JS
wasm
wasm(web assembly) 是一种低级语言,它运行在浏览器中,可以和javascript
相互调用,几乎所有浏览器都支持, 而且目前有多种高级语言都可以直接编译成wasm
,更是大大增强了它的地位。
目前来说Rust可以编译成wasm
,虽然还不够完美,但是它正在以肉眼可见的速度快速发展中。因此同时使用Rust
和Javascript
成为了一种可能:将Rust
编译成wasm
,再跟js
进行交互,两者共生共存,各自解决擅长的场景(wasm
性能高,js
开发速度快)。
yew
yew
是一个正在活跃开发的Rust/Wasm
框架,用于构建Web
客户端应用。
gloo
[gloo]是一个模块化的工具,使用Rust/WASM
构建快速、可靠的Web
应用。
use gloo::{events::EventListener, timers::callback::Timeout};
use wasm_bindgen::prelude::*;
pub struct DelayedHelloButton {
button: web_sys::Element,
on_click: events::EventListener,
}
impl DelayedHelloButton {
pub fn new(document: &web_sys::Document) -> Result<DelayedHelloButton, JsValue> {
// 创建 `<button>` 元素.
let button = document.create_element("button")?;
// 监听button上的`click`事件
let button2 = button.clone();
let on_click = EventListener::new(&button, "click", move |_event| {
// 一秒后,更新button中的文本
let button3 = button2.clone();
Timeout::new(1_000, move || {
button3.set_text_content(Some("Hello from one second ago!"));
})
.forget();
});
Ok(DelayedHelloButton { button, on_click })
}
}
wasm-bindgen
wasm-bindgen可以让WASM
模块和Javascript
模块进行更好的交互。
use wasm_bindgen::prelude::*;
// 从Web导入 `window.alert` 函数
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
// 从Rust导出一个`greet`函数到Javascript,该函数会`alert`一条欢迎信息
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
wasm-pack
wasm-pack是一站式的解决方案,用于构建和使用Rust生成的WASM,支持在浏览器中或后台的Node.js
中与Javascript
进行交互。
wasmer
wasmer是业界领先的WASM
运行时,支持WASI
和Emscripten
。
$ wasmer qjs.wasm
QuickJS - Type "\h" for help
qjs > const i = 1 + 2;
qjs > console.log("hello " + i);
hello 3
wasmtime
wasmtime是一个为WASM
设计的JIT
风格的独立运行时。
fn main() {
println!("Hello, world!");
}
$ rustup target add wasm32-wasi
$ rustc hello.rs --target wasm32-wasi
$ wasmtime hello.wasm
Hello, world!
trunk
trunk是一个WASM
构建、打包、Web发布工具。
photon
photon是高性能的、跨平台的图片处理库,使用Rust
开发,编译成WASM
运行,为你的Web应用和Node.js
应用提供无与伦比的图片处理速度,当然,它既然使用Rust
开发,也可以作为一个库被你的后台程序所使用。
tinysearch
tinysearch是一个搜索工具,用于静态网站中的内容搜索,使用Rust
和WASM
构建。优点是体积小(适用于浏览器)、性能高、全文索引。
wasm-pdf
wasm-pdf通过Javascript
和WASM
来生成PDF
,可以直接在浏览器中使用。
makepad
makepad是一个充满创意的Rust开发平台,支持编译成wasm
,并使用webGL
进行渲染。
Rust + Javascript学习教程
wasm-book
wasm-book是一本讲述Rust
和wasm
的书,篇幅不算长,但是值得学习,还包含了几个很酷的例子。
wasm-learning
wasm-learning
是一个英文教程,用于学习Rust
, wasm
和Node.js
,你可以学会如何使用Rust
来为Nodejs
构建函数,可以同时利用Rust
的性能、wasm
的安全性和可移植性、js
的易用性。
rust-js-snake-game
rust-js-snake-game
是一个用rust + js + wasm
构建的贪食蛇游戏。