Universal Zopfli
A WebAssembly build of Google's Zopfli compressor, usable from both Node.js and browsers with no native build step.
Repository Health
Technical Analysis
Universal Zopfli is a JavaScript binding to Google’s Zopfli compression algorithm, compiled to WebAssembly with Emscripten. Zopfli trades compression speed for a smaller output than standard zlib/gzip implementations, typically producing files several percent smaller — useful for anything shipped once and downloaded many times, such as static assets, npm package tarballs, or CDN-hosted files.
Because the compressor is compiled to a portable .wasm binary rather than a native Node addon, installation has no compiler toolchain requirement: no node-gyp, no prebuilt binaries per platform/ABI, and the same package works unmodified in Node.js and in the browser. This trades some raw throughput (roughly 50-75% of the native node-zopfli binding’s speed) for that portability.
The API exposes gzip, zlib, and deflate functions with both callback and Promise-returning (*Async) variants, and is designed to be a drop-in replacement for node-zopfli’s gzip call signature — including direct use as the algorithm option in webpack’s CompressionPlugin for producing pre-compressed static assets at build time.
What You Get
gzip,zlib, anddeflatecompression functions with matching callback and*Async(Promise) variants- A portable WebAssembly binary — no
node-gyp, no per-platform prebuilt binaries, works in Node.js and browsers alike - API compatibility with
node-zopfli’sgzipsignature, so it can substitute for it with minimal changes - Tunable
ZopfliOptions(numiterations,blocksplitting,blocksplittingmax) to trade compression time for ratio - Direct drop-in use as the
algorithmfunction for webpack’scompression-webpack-plugin
Common Use Cases
- Pre-compressing static assets (JS/CSS/HTML) at build time for smaller CDN payloads
- Producing smaller gzip tarballs for npm package publishing or file distribution
- Running Zopfli compression in environments where native addons can’t be installed (serverless, restrictive CI images, browser-side tooling)
- Swapping in for
node-zopfliin an existing pipeline without a native-binding dependency
Under The Hood
Architecture
The package is a thin two-layer binding: src/binding.c exposes a handful of EMSCRIPTEN_KEEPALIVE functions (compress, createZopfliJsOutput, getBuffer/getBufferSize, deallocate) around the vendored Zopfli C library (included as a git submodule), and src/index.ts is the JavaScript-facing layer that manages the WebAssembly module’s async initialization (queuing calls until onRuntimeInitialized fires), copies input strings/buffers into the WASM heap via allocate/intArrayFromString, invokes _compress, reads the result back out of HEAPU8, and frees the WASM-side buffers. There is no framework or dependency-injection layer — it’s a narrow compression primitive with a queue for pre-init calls and a synchronous-looking API on top of an inherently async WASM boot sequence.
Tech Stack
Built with Emscripten (emcc) compiling the vendored Zopfli C sources plus a small C binding into a WebAssembly module, wrapped in TypeScript for the public API and compiled with tsc. The WASM binary is base64-encoded into a JS module (libzopfli-wasm) at build time via a custom tools/binary-to-json.js script and decoded at runtime with the base64-js dependency — avoiding a filesystem read so the module works in browsers. The Makefile drives the whole native-to-WASM build and a Dockerfile pins the Emscripten toolchain version for reproducible builds.
Code Quality
Tests use the ava test runner (test/gzip_test.ts) and assert compressed output against known-good byte sequences produced by the reference zopfli CLI, plus round-trip tests (compress then zlib.gunzip) for short strings, emoji-containing strings, a large string (the README itself), Node Buffers, and Uint8Arrays. Coverage is narrow but targeted at the actual risk surface (encoding correctness across input types) rather than exhaustive; there’s no linter config beyond a Prettier formatting config, and the C binding relies on assert() for precondition checks rather than typed error handling.
What Makes It Unique Most Zopfli JavaScript bindings are either native Node addons (faster, but require a working native build toolchain and per-platform prebuilds) or pure-JS ports (portable, but slower and without access to the optimized C implementation). This package’s WebAssembly approach sits between the two: it ships the real Zopfli C implementation, but compiled to a format that installs and runs identically across Node.js versions, operating systems, and browsers, at a moderate speed cost relative to the native binding.