@rivus/svgo
v0.3.1
Published
SVG optimizer written in MoonBit: a wasm-gc library and the svgo-mbt command line tool
Maintainers
Readme
@rivus/svgo
WebAssembly build of svgo.mbt, an
SVG optimizer written in MoonBit: all 34 plugins in svgo's preset-default, in its order and with its semantics.
One 188 KB wasm-gc file plus a 2 KB loader, no other dependencies; 3.6× faster than svgo at the
median, with output within 1.3% of svgo's size on the benchmark corpus and 0 px render
difference.
npm i @rivus/svgo # the library
npx @rivus/svgo in.svg -o out.svg # the command line tool, no install (installed: `svgo-mbt`)import { optimize, plugins } from "@rivus/svgo";
const r = await optimize(svgText, {
precision: 3, // decimal places (default 3)
multipass: true, // repeat until stable (default true)
pretty: false, // indent output (default false)
// plugins: ["removeComments", "convertPathData", ...] // explicit list, in order
});
r.data; // optimized SVG
r.originalSize; // bytes in
r.size; // bytes out
r.passes; // pipeline passes
r.applied; // plugins that changed something
await plugins(); // [{ name, description, enabled }]Plugin entries may also be objects, for example:
await optimize(svg, {
plugins: [{ name: "cleanupIds", params: { preserve: ["logo"], minify: false } }],
});Top-level params: { cleanupIds: { preserve: ["logo"] } } works with either
the default preset or an explicit plugin list. An entry's params object takes
precedence over the top-level object for that plugin. Missing parameters use
plugin defaults. removeComments.preservePatterns supports literal substrings
and ^-prefixed literal prefixes, not full regular expressions.
Only the built-in plugins run. JavaScript functions cannot run inside the wasm
module, so do project-specific rewrites on the SVG string before or after
optimize; the MoonBit library accepts custom plugins through Config::custom.
Command line
The bin is the same optimizer compiled for node, so it needs no toolchain:
npx @rivus/svgo in.svg -o out.svg # size report on stderr
cat in.svg | npx @rivus/svgo > out.svg # stdin, or pass "-" as the input
npx @rivus/svgo icons -r -o dist # a directory, recursively
npx @rivus/svgo in.svg --stats # SVG on stdout, size report on stderr
npx @rivus/svgo in.svg --json # {data, originalSize, size, passes, applied}
npx @rivus/svgo --list # available pluginsWriting files prints one row per file on stderr, with a totals line for
several; -q silences it:
$ npx @rivus/svgo icons/close.svg icons/logo.svg -o dist
icons/close.svg 836 B → 276 B −67%
icons/logo.svg 1.1 KB → 528 B −54%
2 files 2.0 KB → 804 B −59% 1.9 msExit codes: 0 on success, 1 for a usage error, 2 when a file could not be read, parsed, optimized or written, with the failing names on stderr.
In a browser the module is fetched relative to the loader; pass your own URL
to init(url) before the first optimize call if you host it elsewhere.
Requires WebAssembly GC and JS String Builtins: Node 24+, Bun 1.4+, Deno 2, Chrome 130+, Firefox 134+, Safari 18.4+. CI runs the fixture suite under Node, Bun and Deno; details in the repository README under "Runtime compatibility".
Same-process timings against svgo 4.1 (ms per call, both multipass): a Sketch icon 0.10 vs 0.29, the 50 KB Tux drawing 5.7 vs 12.8, the 68 KB Ghostscript Tiger 10.1 vs 41.1. Playground and details: https://perfectpan.github.io/svgo.mbt/.
MIT.
