A complete image optimization toolkit for Vue 3 — lazy loading, format switching, responsive art direction, a CLI, CDN URL builders, and a Nuxt module.

An image is almost always the heaviest thing on a page — and almost always what determines LCP, the metric Google and real users judge loading speed by. vue-image-kit bundles the whole set of techniques usually applied one at a time by hand: the right format, lazy loading, placeholders, priority for the one image that matters most.
A banner or product photo visible the moment the page opens gets priority and starts loading ahead of every other image — otherwise it's that image, not some small icon near the bottom, that decides how fast the page feels.
A feed of fifty photos doesn't pull all fifty files the moment the page opens — images far from the viewport only start loading once the user has scrolled nearly to them.
One project keeps images in Cloudinary, another in its own cloud, and each service builds the URL for a given size and format its own way — that URL gets assembled automatically for whichever provider is in use, instead of by hand for each one.
An empty box that suddenly turns into a picture makes the page jump and feels unpolished — the spot where an image hasn't loaded yet shows a blurred or color placeholder prepared ahead of time instead.

One component replaces a whole set of utilities: lazy loading via IntersectionObserver, placeholders (HazeHash, Blurhash, ThumbHash, LQIP, color, shimmer), automatic srcset, WebP/AVIF, art direction, retries with exponential backoff, and smooth CSS transitions. Supports focal point, fetchpriority, decoding, and a priority mode for LCP.

The CLI processes images at build time: resize, convert to WebP/AVIF, generate LQIP and HazeHash/BlurHash/ThumbHash, write a TypeScript manifest. The Vite plugin runs processing on build and in dev mode. The Nuxt module auto‑registers the component and all composables, integrating with runtime config.

Ready‑to‑use URL builders for 12 providers (Cloudinary, imgix, Bunny, Sanity, Storyblok, Contentful, Vercel, Cloudflare, ImageKit, TwicPics, Netlify, Gumlet) with a unified .url() and .srcset() interface. The autoLoader() function detects the CDN by host and applies the adapter automatically, and VImage with the cdn prop does it right in the template.

useImage provides headless loading state management and attributes for custom markup. v-lazy-img loads background images on viewport entry with placeholder support. useBackgroundImage adds lazy + responsive via CSS image-set(). useImagePreloader preloads images before navigation.

Built‑in mechanisms: priority loading (fetchpriority), decoding (decoding), Network Information API (saveData), preloading via generatePreloadLink and useImagePreloader. A shared IntersectionObserver pool saves resources. All components and utilities are SSR‑safe — the server renders a plain <img>, and all client logic activates after hydration.

Don’t want to depend on an external CDN? Run the package’s own image‑processing server as a dedicated entry point, with the same resize and format‑conversion API as the CLI. In development, the Vite plugin processes images on demand, on first request, speeding up cold starts.
The blurhash string decodes to a CSS gradient in microseconds — the placeholder shows up before the image's first byte arrives, and width/height reserve its space right away.
<template>
<VImage
src="/photo.jpg"
alt="Mountain landscape"
:width="1200"
:height="600"
blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
/>
</template>sources swaps in a genuinely different image — different crop, different composition — per breakpoint. Real art direction through <picture>, not a stretched resize of the same photo.
<template>
<VImage
src="/hero-desktop.jpg"
alt="Hero"
:sources="{
sm: '/hero-mobile.jpg',
md: '/hero-tablet.jpg',
}"
/>
</template>
<!-- Generates a real <picture> with one <source media="..."> per
breakpoint, sorted automatically, plus the fallback <img>. -->respect-save-data downgrades src to the lightest candidate it can find and drops priority loading while the visitor has data-saving mode on — their phone decides, not the developer.
<template>
<VImage
src="/photo.jpg"
alt="Photo"
priority
respect-save-data
:densities="{ 1: '/photo.jpg', 2: '/photo@2x.jpg' }"
/>
</template>
<!-- While the visitor has Save-Data on: priority is neutralized (stays
lazy instead of eager), and src downgrades to the lightest candidate
it can find — the lowest density here, @1x instead of @2x. -->