Embed JavaScript in Rust and run it in WebAssembly

WasmEdge combines the power of Rust with the simplicity of JavaScript

Running JavaScript programs in WasmEdge, a four-part series:

In my previous article, I discussed how to run JavaScript programs in the WebAssembly sandbox. The WasmEdge runtime provides a lightweight, high-performance, OCI-compliant "container" for cloud-native JavaScript applications.

However, JavaScript is a "slow" language. The reason for using JavaScript is mainly because of its ease of use and high developer productivity, especially for beginners. On the other hand, WebAssembly is capable of running high-performance applications written in languages ​​like Rust. Is there a solution that combines JavaScript and Rust? WasmEdge gives the best of both worlds.

With WasmEdge and QuickJS , developers can create applications with the perfect combination of the two most powerful languages. Like the following:

  • The application itself is written in Rust and compiled to WebAssembly. It can be compiled and deployed as a single wasm bytecode file. It can be managed by OCI compliant container tools such as Docker Hub, CRI-O and k8s.
  • JavaScript programs are embedded in Rust applications. Rust programs can include JavaScript source code at compile time, or they can include JS at runtime via files, STDIN, network requests, or even function calls. This allows JavaScript programs to be written by different developers than Rust programs.
  • Rust programs can handle computationally intensive tasks in an application, while JavaScript programs can handle "business logic". For example, Rust programs can prepare data for JavaScript programs.

Next, let's look at a few examples. All examples are in the fork of the wasmedge-quickjsembed_in_rust repo .

$ git clone https://github.com/second-state/wasmedge-quickjs
$ git checkout embed_in_rust

Make sure you have Rust and WasmEdge installed in order to build and run the examples in this article.

Hello WasmEdge

The following Rust program in main.rs embeds a JavaScript program at compile time.

pub mod quickjs_sys;

... ...

fn main() {
    use quickjs_sys as q;
    let mut ctx = q::Context::new();
    // include js code
    let code = include_str!("../example_js/demo.js");
    // get args and set into quickjs
    let mut res_args = args_parse();
    res_args.insert(0, "<embedded_no_filename>".to_string());
    ctx.put_args(res_args);
    // run js code
    ctx.eval_str(code, "");
}

The example_js/demo.js code is as follows.

import * as std from 'std';

print('hello')
print('args:',...args)

//write fs
let wf = std.open('demo.txt','w')
wf.puts('hello quickjs')
wf.close()

//read fs
let rf = std.open('demo.txt','r')
let r = rf.getline()
print(r)
rf.close()

You can build Rust + JavaScript applications into a single WebAssembly bytecode program.

$ cargo build --target wasm32-wasi --release

Run it and see the result printed to the console.

$ cd example_js
$ wasmedge --dir .:. ../target/wasm32-wasi/release/quickjs-rs-wasi.wasm

That's it. Rust code can pass data into JavaScript code by passing parameters or even directly modifying the included JavaScript source. JavaScript code can also return values ​​by writing to a temporary file.

Image recognition using embedded JavaScript

You can modify the Rust program in main.rs to embed a different JavaScript program. In the example below, let's change to

`pub mod quickjs_sys;

... ...

fn main() {
    ... ...
    let code = include_str!("../example_js/tensorflow_lite_demo/main.js");
    ... ...
    ctx.eval_str(code, "");
}`

The main.js code uses the JavaScript API of the WasmEdge Tensorflow extension to call ImageNet to read and recognize the image model.

import {TensorflowLiteSession} from 'tensorflow_lite'
import {Image} from 'image'

let img = new Image('./example_js/tensorflow_lite_demo/food.jpg')
let img_rgb = img.to_rgb().resize(192,192)
let rgb_pix = img_rgb.pixels()

let session = new TensorflowLiteSession('./example_js/tensorflow_lite_demo/lite-model_aiy_vision_classifier_food_V1_1.tflite')
session.add_input('input',rgb_pix)
session.run()
let output = session.get_output('MobilenetV1/Predictions/Softmax');
let output_view = new Uint8Array(output)
let max = 0;
let max_idx = 0;
for (var i in output_view){
    let v = output_view[i]
    if(v>max){
        max = v;
        max_idx = i;
    }
}
print('label index:',max_idx,'\nconfidence:',max/255)

You can build Rust + JavaScript applications into a single WebAssembly bytecode program. Note the --features=tensorflowflag , which requires the Rust compiler to use the WasmEdge TensorFlow extension API.

$ cargo build --target wasm32-wasi --release --features=tensorflow

Run it and see the results printed to the console.

$ cd example_js/tensorflow_lite_demo
$ wasmedge --dir .:. ../../target/wasm32-wasi/release/quickjs-rs-wasi.wasm

run faster

Running the Tensorflow inference example above takes 1-2 seconds. This is acceptable in a web application scenario, but could be improved. In the last article, we mentioned that WasmEdge is currently the fastest WebAssembly runtime due to its AOT (Ahead of Time Compiler) optimization. WasmEdge provides a wasmedgecutility to wasmcompile files into native soshared libraries. You can use wasmedgeto run sofile instead of wasmfile for faster performance.

The example below wasmedgeuses wasmedgecextended versions of and to support the WasmEdge Tensorflow extension.

$ cd example_js/tensorflow_lite_demo
$ wasmedgec-tensorflow ../../target/wasm32-wasi/release/quickjs-rs-wasi.wasm quickjs-rs-wasi.so
$ wasmedge-tensorflow-lite --dir .:. quickjs-rs-wasi.so

You can see that the image classification task can be done in 0.1 seconds. This is at least a 10x improvement!

soShared libraries are not portable across machines and operating systems. You must be running wasmedecand wasmedec-tensorflow.

Next step

Embedding JavaScript in Rust is a powerful way to create high-performance cloud-native applications. In the next article, we'll look at another technical approach: embedding native libraries in JavaScript.

JavaScript in cloud-native WebAssembly is an emerging field in next-generation cloud and edge computing infrastructure. We are just getting started! If you're also interested, please join our WasmEdge project or let us know what you need by filing a feature request issue.

{{o.name}}
{{m.name}}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324069842&siteId=291194637