Skip to content

WASM Office Library — Quick Start

The office-oxide-wasm package ships office_oxide compiled to WebAssembly. Zero native dependencies, a single Rust-core binary, and three subpath entry points so it runs anywhere JavaScript does — browsers, Node.js, and bundlers like Vite, Webpack, and Rollup.

For Node.js without the WASM overhead, use the native office-oxide package instead.

Install

npm install office-oxide-wasm

No postinstall step. Works on Node 18+, modern browsers with WebAssembly support, and anything with an ES-module / CommonJS loader.

Subpath exports

Import path Target Format
office-oxide-wasm (default) bundler-friendly ESM (Vite, Webpack, Rollup) ESM
office-oxide-wasm/node Node.js CommonJS
office-oxide-wasm/web Browsers via <script type="module"> or import ESM, needs init()

Pick the variant that matches your runtime.

Read a document

Bundler (ESM)

import { WasmDocument } from 'office-oxide-wasm';

const res = await fetch('/report.docx');
const data = new Uint8Array(await res.arrayBuffer());
const doc = new WasmDocument(data, 'docx');
try {
  console.log(doc.plainText());
} finally {
  doc.free();
}

Node.js (CJS)

const { readFileSync } = require('node:fs');
const { WasmDocument } = require('office-oxide-wasm/node');

const data = readFileSync('report.docx');
const doc = new WasmDocument(data, 'docx');
try {
  console.log(doc.plainText());
} finally {
  doc.free();
}

Browser (raw, no bundler)

<script type="module">
  import init, { WasmDocument } from 'https://cdn.jsdelivr.net/npm/office-oxide-wasm/web/office_oxide.js';
  await init();

  const res = await fetch('/report.docx');
  const data = new Uint8Array(await res.arrayBuffer());
  const doc = new WasmDocument(data, 'docx');
  try {
    document.body.textContent = doc.plainText();
  } finally {
    doc.free();
  }
</script>

Browser only: you must await init() before constructing WasmDocument. The Node and bundler entry points handle initialization internally.

Core API

WasmDocument is the single handle — there’s no separate Document / EditableDocument split (editing lives in the native bindings).

import { WasmDocument } from 'office-oxide-wasm';

const doc = new WasmDocument(bytes, 'xlsx');
try {
  console.log(doc.formatName());   // "xlsx"
  console.log(doc.plainText());
  console.log(doc.toMarkdown());
  console.log(doc.toHtml());
  const ir = doc.toIr();           // parsed object
} finally {
  doc.free();   // required — WASM memory is not GC-managed
}

All methods are camelCase: plainText, toMarkdown, toHtml, toIr, formatName. bytes must be a Uint8Array. format must be one of 'docx' | 'xlsx' | 'pptx' | 'doc' | 'xls' | 'ppt'.

The legacy binary formats (doc, xls, ppt) are parsed in WASM too.

Editing (not in WASM)

EditableDocument — text replacement and cell writes — is not exposed through the WASM build. For editing, use:

For read-only text / Markdown / HTML / IR workflows, WASM is fully featured.

Format-agnostic IR

const doc = new WasmDocument(bytes, 'docx');
const ir = doc.toIr();
doc.free();

for (const section of ir.sections) {
  console.log(section.title);
  for (const el of section.elements) {
    // el.kind: "Heading" | "Paragraph" | "Table" | "List" | "Image" | ...
  }
}

The IR schema matches the Rust DocumentIR exactly, so server-side and client-side pipelines can share a single processor.

Bytes in, bytes out

The WASM build is bytes-in only — no file I/O surface.

// From <input type="file">
const file = inputEl.files[0];
const data = new Uint8Array(await file.arrayBuffer());
const doc = new WasmDocument(data, file.name.split('.').pop().toLowerCase());

// From fetch
const res = await fetch(url);
const data = new Uint8Array(await res.arrayBuffer());

// In Node
const data = new Uint8Array(require('node:fs').readFileSync('file.docx'));

Bundlers

// Vite — usually zero-config
import { WasmDocument } from 'office-oxide-wasm';

// Webpack 5 — add to module.rules:
//   { test: /\.wasm$/, type: 'asset/resource' }

TypeScript

Type definitions (office_oxide.d.ts) ship alongside the JS glue for every subpath export. Importing from the root picks up the bundler types automatically; import type { WasmDocument } from 'office-oxide-wasm/node' works too.

Memory management

const doc = new WasmDocument(bytes, 'docx');
try {
  // ... work
} finally {
  doc.free();
}

Forgetting free() leaks the backing WASM memory until the instance is torn down.

Errors

Failures surface as regular Error instances with a descriptive message. Because the WASM build uses JsValue::from_str, error codes aren’t exposed numerically — check the message string.

Troubleshooting

Symptom Fix
ReferenceError: WebAssembly is not defined Target doesn’t support WASM. Use the native office-oxide package instead.
Browser: TypeError: ... before init() Forgot to await init() when using office-oxide-wasm/web.
Bundler complains about .wasm Add a WASM asset rule or switch your bundler target to esnext.
unsupported format: pdf Only six formats are accepted: docx, xlsx, pptx, doc, xls, ppt.
Memory grows unboundedly in a hot loop You’re not calling doc.free() between iterations.

See also