Skip to content

CLI — Generate Images ​

Resize images, convert to WebP/AVIF, generate LQIP and HazeHash/BlurHash, write a TypeScript manifest — all in one command.

generate is the CLI's default command. The CLI also has scan — a report of how images are used across the project — and placeholders, which fills in placeholders for <VImage> usages already in your templates. npx vue-image-kit --help lists all three; each takes --help for its own options.

Requires sharp as a dev dependency:

bash
npm install sharp --save-dev

Basic usage:

bash
npx vue-image-kit generate \
  --input ./src/images \
  --output ./public/images \
  --widths 400,800,1200 \
  --formats jpg,webp,avif \
  --manifest ./src/assets/images.ts

Prints a per-image report as it works — source path/format/dimensions/size, then every output variant with its own path/format/dimensions/size ((existing) for a file --skip-existing kept, (dry-run — not written) under --dry-run) — followed by a batch total: images/files processed, total input vs. output size, and how much the smallest available format saves vs. the original on average (deliberately not "total output vs. total input" — with several widths × formats generated per image, total output is naturally many times one original's size, which would misleadingly read as "this made it worse"):

[vue-image-kit] Processing 1 image(s)…
[vue-image-kit] photo1
  Input   ./src/images/photo1.jpg
          jpg · 1200×800 · 245.3 KB
  Output
    ./public/images/photo1-400.jpg   jpg   400×267   52.1 KB
    ./public/images/photo1-800.jpg   jpg   800×533  118.4 KB
    ./public/images/photo1.jpg       jpg  1200×800  198.2 KB
    ./public/images/photo1.webp      webp 1200×800  112.9 KB
    ./public/images/photo1.avif      avif 1200×800   79.6 KB
[vue-image-kit] Done. 1 image(s) → 5 file(s).
  Input:  1 image(s), 245.3 KB total
  Output: 5 file(s), 561.2 KB total
  Smallest available format saves ~79% vs. original, on average
[vue-image-kit] Manifest written to ./src/assets/images.ts

All options:

  • --input <dir> · default: ./src/images. Source directory.
  • --output <dir> · default: ./public/images. Output directory.
  • --widths <list> · default: 400,800,1200. Comma-separated output widths.
  • --formats <list> · default: jpg,webp,avif. Output formats.
  • --quality <json> · default: {"jpg":85,"webp":80,"avif":65}. Quality per format.
  • --template <str> · default: {name}-{width}.{ext}. Filename template ({name}, {width}, {ext}).
  • --manifest <path> — write images.ts manifest to this path.
  • --public-path <str> · default: /images. URL prefix used in manifest paths.
  • --lqip / --no-lqip · default: enabled. Generate base64 LQIP placeholder.
  • --hazehash / --no-hazehash · default: enabled when the hazehash package is installed, disabled otherwise. Generate a HazeHash string (the preferred placeholder; requires the hazehash package).
  • --blurhash / --no-blurhash · default: enabled. Generate BlurHash string.
  • --thumbhash / --no-thumbhash · default: disabled. Generate ThumbHash string (requires thumbhash dev dep).
  • --clean — remove output dir before generating.
  • --dry-run — preview without writing files.
  • --skip-existing — skip already-generated files.
  • --concurrency <n> · default: 4. Parallel workers.
  • --watch — watch input dir and regenerate on change.
  • --incremental / --no-incremental · default: auto. Skip reprocessing a source whose mtime (or, if that changed, content hash) matches the last run. Auto-enabled under --watch (and by the Vite plugin during vite dev) unless set explicitly either way — a one-shot generate stays off by default. See Incremental generation below.

Config file — create vue-image-kit.config.js in your project root to avoid repeating flags:

js
// vue-image-kit.config.js
export default {
  input: './photos',
  output: './public/images',
  widths: [480, 960, 1440],
  formats: ['jpg', 'webp'],
  manifest: './src/assets/images.ts',
  publicPath: '/images',
}

SVG and animated GIF are handled differently from raster formats — they're detected by input extension, not by --formats:

  • SVG is copied through untouched (no rasterizing — it's already resolution-independent). The manifest entry gets src pointing at the copy; webp/avif/placeholder/hazehash/blurhash/thumbhash are empty strings.
  • Animated GIF is copied through as the guaranteed-compatible fallback (src), and — when webp is in --formats — re-encoded to animated WebP (webp field) for a real size win. AVIF is skipped: animated-AVIF support across sharp/libavif builds is too inconsistent to promise. LQIP/BlurHash/ThumbHash placeholders are still generated from the first frame.

Incremental generation ​

--watch and the Vite plugin's buildStart/handleHotUpdate both call the same generate() the CLI does — by default, every single-file change means re-scanning and reprocessing every source image, not just the one that changed. incremental mode fixes that:

bash
npx vue-image-kit generate --watch --incremental   # already the default under --watch

For each source, it checks a persisted record from the previous run: mtime unchanged → skip entirely, no read, no sharp call. Mtime changed (e.g. a git checkout touched every file) → falls back to a content hash before deciding — an unmodified file survives a checkout without triggering a needless reprocess. The record — a JSON manifest at <output>/.vik-incremental.json — also stores each skipped image's full metadata, so the batch report/--manifest output stays complete even for images that weren't touched this run.

Changing widths/formats/quality/template/publicPath/lqip/ hazehash/blurhash/thumbhash between runs invalidates everything at once (logged as Config changed since last run) — not per-file diffing, since a config change can affect any or all outputs. --clean also invalidates everything, naturally: it deletes output, and the manifest lives inside it. No effect under --dry-run (nothing is written, so there's nothing valid to compare against next time).

Defaults: off for a one-shot generate (a single run gains nothing from caching), on automatically under --watch and during vite dev (vite build stays off — a production artifact shouldn't risk a stale cache). An explicit --incremental/--no-incremental (CLI flag, config file, or Vite plugin option) always overrides the automatic default either way.