使用Rust增强Javascript
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
模块。
#![allow(unused)] fn main() { 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
应用。
#![allow(unused)] fn main() { 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
模块进行更好的交互。
#![allow(unused)] fn main() { 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
构建的贪食蛇游戏。