Skip to main content

Rusty Sheets with 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:

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

The following helper function evaluates strings as JS code:

/* simple wrapper to evaluate code snippets */
fn eval_code(c: &mut boa_engine::Context, code: &str) -> Result<std::string::String, boa_engine::JsError> {
let src = boa_engine::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 boa_engine::Source::from_filepath to read source code from a path, but it is recommended to inline the SheetJS standalone script using the include_str! macro:

  /* load library */
match eval_code(context, include_str!("../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> = std::fs::read("pres.xlsx").unwrap();
let array: boa_engine::object::builtins::JsArrayBuffer = boa_engine::object::builtins::JsArrayBuffer::from_byte_block(file, context).unwrap();
let attrs = boa_engine::property::Attribute::WRITABLE | boa_engine::property::Attribute::ENUMERABLE | boa_engine::property::Attribute::CONFIGURABLE;
let _ = context.register_global_property(boa_engine::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.20.02025-03-31
darwin-arm0.20.02025-02-13
win11-x640.20.02024-12-19
win11-arm0.20.02025-02-23
linux-x640.20.02024-12-31
linux-arm0.20.02025-02-15
  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 pres.xlsx

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.