使用Rust增强Javascript

Javascript是目前全世界使用最广的语言(TIOBE排行榜比较迷,JS并没有排在第一位,我个人并不认同它的排名)。在过去这么多年中,围绕着Javascript已经建立了庞大的基础设施生态:例如使用webpack来将多个js文件打包成一个;使用Babel允许你用现代化的js语法编写兼容旧浏览器的代码;使用Eslint帮助开发找出代码中潜在的问题,类似cargo clippy

以上的种种都在帮助js成为更好的语言和工具,它们是Web应用程序得以顺利、高效的开发和运行的基石。这些工具往往使用Javascript语言编写,一般来说,是没有问题的,但是在某些时候,可能会存在性能上的瓶颈或者安全隐患,因此阴差阳错、机缘巧合下,Rust成为了一个搅局者。

Javascript基建库

deno

首先出场的自然是咖位最重的之一,可以说正是因为denoswc的横空出世,才让一堆观望的大神对于Rust实现Javascript基建有了更强的信心。

denonode半逆转后的字序,从此可以看出denoNode.js的替代,它的目标是为Typescript/Javascript提供一个更现代化、更安全、更强大 的运行时,同时内置了很多强大的工具,可以用于打包、编译成可执行文件、文档、测试、lint等。

值得一提的是,deno的不少工具都使用了swc进行建造,包括代码审查、格式化、文档生成等。

通过包引入的方式来对比下denonode,大家可以自己品味下。

// 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

swcTypescript/Javascript编译器,它可以用来编译、压缩和打包JS,同时支持使用插件进行扩展,例如做代码变换等。

swc目前正在被一些知名项目所使用,包括Next.js,ParcelDeno,还有些著名的公司也在使用它,例如Vercel、字节跳动、腾讯等。

它的性能非常非常高,官方号称,在单线程下比Babel快20倍,在4核心下比Babel快70倍!

几个使用案例:

  • nextjs 12, 通过使用swc获得了更好的扩展性、性能以及wasm的支持,其中性能方面提升了3倍刷新速度、5倍打包速度
  • Parcel,通过使用swc改善了10倍的性能
parcel screenshot

官方还提供了一个在线运行的demo,功能齐全,可以试试。

swc screenshot

Rome

Rome可以用来对JavaScriptTypeScriptHTMLJSONMarkdownCSS 进行lint、编译、打包等功能,它的目标是替代BabelESLintwebpackPrettierJest等。

一开始Rome是使用Typescript开发,目前正在用Rust进行重写。有趣的是: Rome的作者也是Babel的作者, 后者还是他在学习编译原理时做的。

fnm

fnm是一个简单易用、高性能的Node版本管理工具,还支持.nvmrc文件(nvmnode版本描述文件)

fnm screenshot

boa

boa是一个高性能的javascript词法分析器,解析器和解释器,目前还是实验性质的。

boa screenshot

napi

napi可以用于构建基于Node APINodejs插件,目前由nextjs主导开发。

volt

volt是一个现代化的、高性能、安全可靠的Javascript包管理工具。目前该库正处于活跃开发阶段,只供学习使用。

volt screenshot

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实现(羞~~~):

resvg screenshot

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_v8v8的Rust语言绑定,底层封装了c++ API

用WASM增强JS

wasm

wasm(web assembly)是一种低级语言,它运行在浏览器中,可以和javascript相互调用,几乎所有浏览器都支持, 而且目前有多种高级语言都可以直接编译成wasm,更是大大增强了它的地位。

目前来说Rust可以编译成wasm,虽然还不够完美,但是它正在以肉眼可见的速度快速发展中。因此同时使用RustJavascript成为了一种可能:将Rust编译成wasm,再跟js进行交互,两者共生共存,各自解决擅长的场景(wasm性能高,js开发速度快)。

yew

yew是一个正在活跃开发的Rust/Wasm框架,用于构建Web客户端应用。

yew screenshot

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进行交互。

wasm-pack screenshot

wasmer

wasmer是业界领先的WASM运行时,支持WASIEmscripten

$ 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开发,也可以作为一个库被你的后台程序所使用。

photon screenshot

tinysearch

tinysearch是一个搜索工具,用于静态网站中的内容搜索,使用RustWASM构建。优点是体积小(适用于浏览器)、性能高、全文索引。

tinysearch screenshot

wasm-pdf

wasm-pdf通过JavascriptWASM来生成PDF,可以直接在浏览器中使用。

makepad

makepad是一个充满创意的Rust开发平台,支持编译成wasm,并使用webGL进行渲染。

makepad screenshot

Rust + Javascript学习教程

wasm-book

wasm-book是一本讲述Rustwasm的书,篇幅不算长,但是值得学习,还包含了几个很酷的例子。

wasm-learning

wasm-learning是一个英文教程,用于学习Rust, wasmNode.js,你可以学会如何使用Rust来为Nodejs构建函数,可以同时利用Rust的性能、wasm的安全性和可移植性、js的易用性。

rust-js-snake-game

rust-js-snake-game是一个用rust + js + wasm构建的贪食蛇游戏。