npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nitra/minify-image

v4.0.0

Published

minify images (PNG, JPEG, SVG)

Readme

Minify images (PNG, JPEG, GIF, SVG)

view on npm npm module downloads license

Minify images in directory, if compressed size lower than 15%

Architecture / system context: see docs/ci4/ (C4 model — context, container, component levels).

Example run

npx @nitra/minify-image --src=.

Options

--write           If not set, only estimate size difference
--src directory   The directory to process.
--avif            With --write, create <name>.<ext>.avif (quality 40) next
                  to each raster image (PNG/JPEG/GIF) before compressing the
                  original. AVIF generation is skipped inside build/wrapper/cache
                  directories (dist, build, android, ios, .output, .nuxt, .cache,
                  src-tauri/icons), and per-package when the nearest package.json
                  contains `{ "@nitra/minify-image": { "disable-avif": true } }`.
--ignore=<glob>   Extra glob to exclude (repeatable). Always-on defaults
                  (node_modules, vendor, test, dist, src-tauri/icons,
                  **/.*/**) залишаються активними.
-h, --help        Print this usage guide.

AVIF companion files

With --write --avif, each raster image (.png/.jpg/.jpeg/.gif) gets a sibling <name>.<ext>.avif (e.g. hero.pnghero.png.avif) encoded from the original bytes (quality 40) before the original is compressed in place. The full source extension is kept in the AVIF filename so two images that share a basename (hero.png and hero.jpg) do not collide on the same hero.avif. SVG is skipped (vector → AVIF is pointless).

The AVIF companion is regenerated whenever any of the following holds:

  1. <source>.avif is missing on disk.
  2. The current SHA-1 of <source> does not match the entry in .n-minify-image.tsv (a previous run processed a different version of the file — i.e. the source has been edited since).
  3. There is no entry for <source> in .n-minify-image.tsv yet (first run on this file, or upgrade from a cache-less version).

When the source is unchanged and <source>.avif already exists, both files are left untouched.

.avif companions are not created inside build-output, wrapper, or cache directories — dist/, build/, android/, ios/, .output/, .nuxt/, .cache/. Mostly these dirs are already excluded from minification globally; the --avif filter additionally covers build/, android/, ios/, where images may exist (Capacitor wrappers, custom build outputs) but native runtimes do not consume AVIF and the files would be wiped on the next sync/build anyway. Match is by path segment, so a project named dist-doc/ is not affected.

Per-package opt-out

Workspaces that should not get .avif companions can opt out by adding the flag to their package.json:

{
  "name": "site",
  "@nitra/minify-image": {
    "disable-avif": true
  }
}

For each image the CLI walks up the directory tree until it finds the nearest package.json; if that file has "@nitra/minify-image": { "disable-avif": true }, no .avif companion is generated for that image (the original is still compressed in place — opt-out applies to AVIF only). The walk stops at the first package.json found, so a flag on the workspace package.json does not need to be repeated on the root one.

This mirrors the cleanup contract on the @nitra/cursor side (rule image-avif): both tools read the same flag, so AVIF generation and orphan-AVIF cleanup stay in sync. After flipping disable-avif to true, existing .avif files inside the package have to be removed once by hand — they will not be regenerated:

find <pkg> -name "*.avif" -delete

Tauri / icon assets

Tauri's tauri::generate_context! proc-macro embeds icons from src-tauri/icons/ into the binary and validates that their PNGs are RGBA — if any is palette-quantized (8-bit indexed, color-type 3), the build panics with icon … is not RGBA. To stay safe by construction, **/src-tauri/icons/** is in the always-on glob ignore list (alongside node_modules, vendor, test, dist, **/.*/**). Files there are not touched at all — neither the original PNG nor a sibling .avif is written. This is the canonical Tauri layout (generated by tauri icon), so the false-positive risk is near zero.

If your icons live somewhere else, exclude that path explicitly with --ignore=<glob>:

npx @nitra/minify-image --src=. --write --ignore='app-icons/**'

Cache

When run with --write, the CLI maintains two TSV files with different roles and locations:

<src>/.n-minify-image.tsv — committed source of truth

Per line: <relative-path>\t<sha1-hex>\t<originalSize>\t<size>.

This file is the slow-path cache and the source for Project lifetime savings. Commit it. Lines are sorted alphabetically; the SHA-1 column changes only when content actually changes — diffs stay minimal.

After git clone or git checkout (which reset file mtime to checkout time), the CLI reads each file, computes its SHA-1, compares to the cached hash; on match the local mtime cache is warmed and no reprocessing happens. originalSize records the size BEFORE the first compression, fed to Project lifetime savings: X (Y% across N files) printed at the end of each --write run.

<src>/node_modules/.cache/@nitra/minify-image/mtime.tsv — local fast path

Per line: <relative-path>\t<mtime>\t<size>.

When (size, mtime) match the cached tuple, the file is skipped without reading — constant time per file, ideal for the warm dev-loop on a single machine. Lives under node_modules/ so it is automatically gitignored (matches the convention used by ESLint, Babel, webpack, Turbo, etc.). rm -rf node_modules wipes it; the next run rebuilds it via the slow path against .n-minify-image.tsv — no images are reprocessed.

Migration from versions < 3.2

Earlier versions kept a single <src>/.minify-image-cache.tsv (4 columns: path\tmtime\toriginalSize\tsize), usually gitignored. On first run after upgrade:

  1. The new files are created — <src>/.n-minify-image.tsv is seeded with originalSize/size from the old TSV (with empty hash placeholder), so Project lifetime savings does not reset.

  2. Each file goes through the slow path (empty hash means cache miss); SHA-1 is computed and stored. No reprocessing happens unless a file's content actually changed.

  3. The old .minify-image-cache.tsv is left in place — remove it manually:

    git rm --cached .minify-image-cache.tsv 2>/dev/null || true
    rm -f .minify-image-cache.tsv

    Add .n-minify-image.tsv to git, ensure node_modules/ covers the local cache (it usually already does).