Skip to main content

Rust + Boa

In a production application, it is strongly recommended to use a binding for a more performant engine like v8

Boa is a JavaScript engine written in Rust.

SheetJS is a JavaScript library for reading and writing data from spreadsheets.

The "Complete Example" section creates a command-line tool for reading data from spreadsheets and generating CSV rows.

Integration Details​

Initialize Boa​

A JS context can be constructed in one line:

use boa_engine::Context;

/* initialize */
let context = &mut Context::default();

The following helper function evaluates strings as JS code:

use std::string::String;
use boa_engine::{Context, Source, JsError};

/* simple wrapper to evaluate code snippets */
fn eval_code(c: &mut Context, code: &str) -> Result<String, JsError> {
let src = Source::from_bytes(code);
match c.eval(src) {
Ok(res) => { return Ok(res.to_string(c).unwrap().to_std_string_escaped()); }
Err(e) => { return Err(e); }
};
}

Load SheetJS Scripts​

The SheetJS Standalone scripts can be parsed and evaluated in a Boa context.

Boa provides a special helper to read source code from a path:

use std::path::Path;
use std::string::String;
use boa_engine::{js_string, Context, Source, JsError};

/* simple wrapper to evaluate an entire script file */
fn eval_file(c: &mut Context, path: &str) -> Result<String, JsError> {
let src = Source::from_filepath(Path::new(path)).unwrap();
match c.eval(src) {
Ok(res) => { return Ok(res.to_string(c).unwrap().to_std_string_escaped()); }
Err(e) => { return Err(e); }
};
}

// ...
/* load library */
match eval_file(context, "./xlsx.full.min.js") {
Ok(_res) => {}
Err(e) => { return eprintln!("Uncaught {e}"); }
}

To confirm the library is loaded, XLSX.version can be inspected:

  /* get version string */
match eval_code(context, "XLSX.version") {
Ok(res) => { println!( "SheetJS library version {}", res); }
Err(e) => { return eprintln!("Uncaught {e}"); }
}

Reading Files​

Boa supports ArrayBuffer natively. This snippet reads data from a file into Vec<u8> and stores the data as an ArrayBuffer in global scope:

  /* read file */
let data: Vec<u8> = fs::read("pres.xlsx").unwrap();
let array: JsArrayBuffer = JsArrayBuffer::from_byte_block(data, context).unwrap();
let attrs = Attribute::WRITABLE | Attribute::ENUMERABLE | Attribute::CONFIGURABLE;
context.register_global_property(js_string!("buf"), array, attrs);

/* parse with SheetJS */
match eval_code(context, "void (globalThis.wb = XLSX.read(buf))") {
Ok(_res) => { }
Err(e) => { return eprintln!("Uncaught {e}"); }
}

wb will be a variable in the JS environment that can be inspected using the various SheetJS API functions.

Complete Example​

Tested Deployments

This demo was tested in the following deployments:

ArchitectureBoaDate
darwin-x640.18.02024-04-25
darwin-arm0.18.02024-05-23
win10-x640.18.02024-04-25
win11-arm0.18.02024-05-25
linux-x640.18.02024-03-21
linux-arm0.18.02024-05-25
  1. Install Rust.

Boa 0.18.0 requires Rust version 1.67 or later.

Debian 12 (Bullseye) ships with Rust version 1.63.0.

It is strongly recommended to install Rust from the official distribution.

  1. Create a new project:
cargo new sheetjs-boa
cd sheetjs-boa
cargo run
  1. Add the boa_engine crate:
cargo add boa_engine
  1. Download the SheetJS Standalone script and test file. Save both files in the project directory:
curl -LO https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js
curl -LO https://docs.sheetjs.com/pres.xlsx
  1. Download main.rs and replace src/main.rs:
curl -L -o src/main.rs https://docs.sheetjs.com/boa/main.rs
  1. Build and run the app in release mode:
cargo run --release

After a short wait, the contents will be displayed in CSV form.

The default debug build is not optimized and can elicit stack overflow errors. It is strongly encouraged to use --release when possible.