brotli-dec-wasm
v2.3.2
Published
Brotli decompressor for browsers and web workers with WASM, in about 200KB
Downloads
35,662
Maintainers
Readme
brotli-dec-wasm
Brotli decompressor for browsers and web workers with WASM, in about 200KB.
For compressors, see Alternatives.
Features
- Optimized for size, suitable for browsers and web workers.
- Streaming decompression.
- Drop-in replacement for brotli-wasm.
Get Started
Install the package:
npm install brotli-dec-wasmThe default export is a promise that resolves to the WASM module:
import brotliPromise from "brotli-dec-wasm";
const brotli = await brotliPromise;
const compressedData = new Uint8Array(/* ... */);
const decompressed = brotli.decompress(compressedData);Streaming decompression
Use DecompressStream to decompress data in chunks. Call decompress(input, outputSize) in a loop, handling three result codes:
NeedsMoreOutput: the current input chunk produced more output thanoutputSizebytes. Call again with the remaining input (sliced byinput_offset).NeedsMoreInput: the current input chunk is fully consumed. Feed the next chunk.ResultSuccess: decompression is complete.
import brotliPromise from "brotli-dec-wasm";
const brotli = await brotliPromise;
const stream = new brotli.DecompressStream();
const chunks = [];
const compressedChunks = [new Uint8Array(/* ... */) /* ... */];
for (const chunk of compressedChunks) {
let resultCode;
let inputOffset = 0;
do {
const input = chunk.slice(inputOffset);
const result = stream.decompress(input, 1024);
chunks.push(result.buf);
resultCode = result.code;
inputOffset += result.input_offset;
} while (resultCode === brotli.BrotliStreamResultCode.NeedsMoreOutput);
}Using with TransformStream
DecompressStream works with the browser TransformStream API for piped workflows:
import brotliPromise from "brotli-dec-wasm";
const brotli = await brotliPromise;
const decompressStream = new brotli.DecompressStream();
const decompressionStream = new TransformStream({
transform(chunk, controller) {
let resultCode;
let inputOffset = 0;
do {
const input = chunk.slice(inputOffset);
const result = decompressStream.decompress(input, 1024);
controller.enqueue(result.buf);
resultCode = result.code;
inputOffset += result.input_offset;
} while (resultCode === brotli.BrotliStreamResultCode.NeedsMoreOutput);
if (
resultCode !== brotli.BrotliStreamResultCode.NeedsMoreInput &&
resultCode !== brotli.BrotliStreamResultCode.ResultSuccess
) {
controller.error(`Brotli decompression failed with code ${resultCode}`);
}
},
});
await compressedReadableStream.pipeThrough(decompressionStream).pipeTo(outputWritableStream);Using with a Web Worker
Decompression runs synchronously on the calling thread. For large payloads this can freeze the UI. To avoid that, run the decompression in a Web Worker:
// worker.js
import brotliPromise from "brotli-dec-wasm";
const brotli = await brotliPromise;
self.onmessage = (e) => {
try {
const result = brotli.decompress(new Uint8Array(e.data));
self.postMessage(result, [result.buffer]);
} catch (err) {
self.postMessage({ error: err.message });
}
};// main.js
const worker = new Worker(new URL("./worker.js", import.meta.url), { type: "module" });
function decompress(data) {
return new Promise((resolve, reject) => {
worker.onmessage = (e) => {
if (e.data.error) reject(new Error(e.data.error));
else resolve(e.data);
};
const buf = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
worker.postMessage(buf, [buf]);
});
}
const result = await decompress(compressedData);Using the WASM module directly
The JS API generated by wasm-pack and the WASM binary file are also exported for cases where you need to instantiate the WASM module with a URL:
import init from "brotli-dec-wasm/web";
import wasmUrl from "brotli-dec-wasm/web/bg.wasm";Check *.asset.* files in example/webpack for examples.
Webpack 5
Set experiments.asyncWebAssembly: true (or experiments.syncWebAssembly: true for legacy code) in your webpack config. Without this, webpack 5 will not enable WebAssembly support.
Benchmark
Decompressing 1MB data in headless Chromium (vitest + playwright):
| Input | ops/s | mean | | ------------------------------------------------------------ | ----- | ------ | | 1MB random data (incompressible, ~1MB compressed) | ~480 | ~2.1ms | | 1MB repeated data (highly compressible, 41 bytes compressed) | ~440 | ~2.3ms |
Environment: AMD Ryzen 7 5800H, performance governor, Linux 6.19.6.
Run pnpm run bench to reproduce. Fixtures are generated by node test/gen_fixture.js.
Alternatives
- brotli-wasm: A compressor and decompressor for Brotli, supporting Node and browsers via WASM. If you need a compressor, use it.
Security
Use version >= 1.3.3. Earlier versions depend on the unmaintained Rust crate wee_alloc, which has open serious issues.
License
Copyright (C) 2026 Yulong Ming [email protected].
Apache License, Version 2.0 or MIT License, at your option.
