top of page
Writer's pictureThe Tech Platform

Running JavaScript in WebAssembly with WasmEdge


Running JavaScript in WebAssembly with WasmEdge 3

JavaScript WebAssembly

WebAssembly was initially conceived as a "JavaScript alternative for browsers" with the aim of enabling the execution of high-performance applications compiled from languages like C/C++ or Rust within web browsers. It operates alongside JavaScript, running in parallel to deliver enhanced performance.

running javascript in web-assembly with wasmedge

In recent times, WebAssembly has evolved into a universal runtime for cloud-native applications. It offers superior performance and consumes fewer resources compared to Docker-like application containers.


Its versatility has led to various use cases in the cloud, including

  1. Serving as a runtime for serverless function-as-a-service (FaaS)

  2. Incorporating user-defined functions into SaaS apps or databases

  3. Powering sidecar applications within a service mesh, and enabling programmable plug-ins for web proxies.

  4. Serves as a sandbox runtime for edge devices, such as software-defined vehicles and smart factories.

Despite the increasing adoption of WebAssembly in cloud-native scenarios, developers often desire the ability to use JavaScript for writing business applications. This necessitates the support for JavaScript within WebAssembly. Moreover, there is a need to enable the invocation of C/C++ or Rust functions from JavaScript within a WebAssembly runtime to harness the computational efficiency of WebAssembly. This is where the WasmEdge WebAssembly runtime comes into play, as it allows developers to achieve exactly that level of interoperability and flexibility.


Running JavaScript in WebAssembly with WasmEdge 2

WasmEdge

WasmEdge is a powerful tool that allows you to run WebAssembly code in a cloud-native environment. It is highly regarded and is hosted by reputable organizations like the CNCF and Linux Foundation. In fact, it is currently the fastest WebAssembly runtime available.


WasmEdge supports various extensions, both standard ones and proprietary ones. These extensions enable capabilities such as Tensorflow inference, key-value storage, and image processing. Additionally, WasmEdge's compiler toolchain supports multiple programming languages, including C/C++, Rust, Swift, Kotlin, AssemblyScript, and even regular JavaScript.


You can embed WasmEdge applications into different types of programs, such as C, Go, Rust, and JavaScript. You can even run WasmEdge applications from the command line of your operating system. WasmEdge can be managed using popular tools like Docker (e.g., CRI-O), orchestration tools (e.g., K8s), serverless platforms (e.g., Vercel, Netlify, AWS Lambda, Tencent SCF), and data streaming frameworks (e.g., YoMo and Zenoh).


With WasmEdge, you can execute JavaScript programs in serverless functions, microservices, and AIoT (Artificial Intelligence of Things) applications. WasmEdge not only supports running regular JavaScript code, but it also allows developers to create new JavaScript APIs using Rust and C/C++. This provides a safe and secure environment through the sandboxing capabilities of WebAssembly.


Building a JavaScript engine in WasmEdge

To build a JavaScript engine in WasmEdge, run JavaScript programs, and incorporate JavaScript into Rust, follow the detailed instructions provided below.


STEP 1: Install Rust

Visit the official Rust website at https://www.rust-lang.org/.

Follow the instructions to install Rust on your system.


STEP 2: Install WasmEdge

Visit the WasmEdge GitHub repository at https://github.com/second-state/wasmedge.

Follow the installation instructions provided for your specific platform.


STEP 3: Clone the WasmEdge QuickJS repository

In this step, you'll clone the WasmEdge QuickJS repository from GitHub. Open a terminal or command prompt and execute the git clone command followed by the repository's URL. This will create a local copy of the repository on your machine.


Open a terminal or command prompt and execute the following command to clone the repository

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

STEP 4: Build the JavaScript interpreter

Change into the cloned repository directory using 'cd' command:

cd wasmedge-quickjs 

This step ensures that you're in the correct directory to build the JavaScript interpreter.


Add the WebAssembly target for Rust using the rustup target add command.

rustup target add wasm32-wasi 

This step adds the necessary target to Rust for building WebAssembly binaries.


Build the JavaScript interpreter by executing the cargo build command with appropriate options. The --target wasm32-wasi flag specifies the WebAssembly target, and the --release flag builds an optimized release version of the interpreter.

cargo build --target wasm32-wasi --release

STEP 5: Run a JavaScript networking example

To run the JavaScript networking example, you need to build the interpreter with the HTTP feature. Execute the following command to build with the HTTP feature

cargo build --target wasm32-wasi --release --features=http 

The above code enables the HTTP feature during the build process.


Run the JavaScript networking example using the wasmedge command followed by the path to the built interpreter and the path to the JavaScript file you want to execute.

wasmedge --dir .:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/http_demo.js 

This command launches the WasmEdge runtime with the specified JavaScript file.


STEP 6: Run a JavaScript Tensorflow inference example

Download the WasmEdge-TensorFlow tools

wget https://github.com/second-state/WasmEdge-tensorflow-tools/releases/download/0.8.1/WasmEdge-tensorflow-tools-0.8.1-manylinux2014_x86_64.tar.gz 
tar -xzf WasmEdge-tensorflow-tools-0.8.1-manylinux2014_x86_64.tar.gz 

This step downloads the necessary tools for running TensorFlow inference in JavaScript.


Now, extract the downloaded tools using the tar -xzf command. This extracts the tools from the downloaded archive.


Download dependencies

./download_dependencies_all.sh 

This step ensures that all required dependencies for TensorFlow are downloaded.


Set the LD_LIBRARY_PATH environment variable to point to the build directory of the WasmEdge-TensorFlow tools.

export LD_LIBRARY_PATH=$(pwd)/build 

This step ensures that the necessary libraries are found during runtime.


Build the JavaScript interpreter with the TensorFlow feature enabled by executing the cargo build command with the --features=tensorflow flag.

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

Run the JavaScript TensorFlow inference example using the wasmedge command, similar to Step 5.

wasmedge --dir .:. target/wasm32-wasi/release/quickjs-rs-wasi.wasm example_js/tensorflow_lite_demo/main.js 

STEP 7: Incorporate JavaScript into Rust:

Now, embed JavaScript code within Rust or accept JavaScript code as input in a Rust application. or create a new Rust project or use an existing one where you want to incorporate JavaScript.


Add the quickjs-sys dependency to your Cargo.toml file. This dependency provides the necessary Rust bindings for the QuickJS JavaScript engine.

[dependencies]
quickjs-sys = "0.2"

Import the required modules from the quickjs-sys crate in your main.rs file.

use quickjs_sys as q; 

Implement your Rust code to embed JavaScript as a string variable or accept JavaScript code as input, using the q::Context and related functions from the quickjs-sys crate.


By following these steps, you should be able to recreate the process described in the text using the WasmEdge runtime and the QuickJS JavaScript interpreter. Remember to adjust the commands and paths as needed based on your system configuration.


Why did we choose QuickJS as JavaScript Engine?

QuickJS is chosen as the JavaScript engine in WasmEdge, even though it may raise concerns about its performance compared to engines like v8 that have JIT support. However, QuickJS has its advantages:

  1. QuickJS is much smaller than v8, consuming only 1/40 (or 2.5%) of the runtime resources. This means that a single physical machine can handle a lot more QuickJS functions compared to v8 functions.

  2. In most business logic applications, raw performance is not the primary concern. For tasks that require high computational power, such as on-the-fly AI inference, WasmEdge allows QuickJS applications to utilize high-performance WebAssembly. Adding such extension modules to v8 is not as straightforward.

  3. JavaScript security issues often stem from JIT. In a cloud-native environment, disabling JIT may actually be a good idea to mitigate these security risks.

JavaScript in cloud-native WebAssembly is an emerging field in cloud and edge computing infrastructure. The WasmEdge project is at the forefront of this development. If you're interested, you can join the project or contribute by raising feature request issues. This area is still evolving, and we're just getting started!

0 comments

Comments


bottom of page