Universal Zopfli

A WebAssembly build of Google's Zopfli compressor, usable from both Node.js and browsers with no native build step.

Library
npm
v1.0.15
81stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
23/100Needs Attention
Development Activity0
Maintenance0
Community20
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
58/100Fair
Architecture62
Code Quality55
Innovation58
Learning Curve55

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, and deflate compression 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’s gzip signature, 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 algorithm function for webpack’s compression-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-zopfli in 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.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search