Skip to content

vue-image-kit

Полный набор инструментов оптимизации изображений для Vue 3. Один компонент <VImage> берёт на себя ленивую загрузку, переключение форматов WebP/AVIF, адаптивную арт-дирекцию, плейсхолдеры Blurhash и LQIP, автоматическую генерацию srcset, повтор при ошибке с экспоненциальной задержкой и плавные CSS-переходы — с нулевыми внешними runtime-зависимостями и небольшим, tree-shakeable весом (см. Размер бандла и peer-зависимости).

Помимо компонента включено всё необходимое: CLI, обрабатывающий изображения на этапе сборки (изменение размера, конвертация, генерация LQIP и BlurHash, запись TypeScript-манифеста), билдеры URL для CDN для 12 провайдеров (Cloudinary, imgix, Bunny, Sanity, Storyblok, Contentful, Vercel, Cloudflare, ImageKit, TwicPics, Netlify, Gumlet) с автоопределением по хосту, модуль Nuxt 3 с автоимпортами, плагин Vite (включая обслуживание по запросу в dev-режиме), самостоятельно размещаемый сервер изображений по запросу на случай отсутствия CDN, и headless-composables для полностью кастомной разметки.

Полностью типизирован через TypeScript. Tree-shakeable (sideEffects: false). SSR-безопасен — на сервере рендерит нативный <img loading="lazy">, активирует IntersectionObserver и canvas после гидратации.

Возможности

Плейсхолдеры

  • Плейсхолдер Blurhash — собственный декодер (без внешних пакетов); рендерится в <canvas> внутри onMounted; на SSR рендерится сайзированный <div>, сохраняющий aspect-ratio
  • Плейсхолдер ThumbHash — проп thumbhash на VImage автоматически декодируется в PNG data URL; поддерживает альфа-канал; качество лучше, чем у BlurHash; флаг --thumbhash в CLI генерирует хэши на этапе сборки
  • LQIP blur-up — строка data:image/…;base64,… в качестве placeholder; размытый превью через filter: blur(); кросс-фейд через CSS-переход opacity
  • Плейсхолдер среднего цветаplaceholderMode="color" выводит сплошной средний цвет из заголовка ThumbHash (0 байт, без canvas); либо задайте placeholderColor напрямую
  • Плейсхолдер shimmerplaceholderMode="shimmer" показывает анимированный CSS-скелетон (хэш не нужен); учитывает prefers-reduced-motion
  • Клиентские кодировщикиencodeThumbHash() / encodeBlurhash() строят хэш из File/Canvas/ImageData прямо в браузере, для мгновенных превью пользовательского контента; без зависимостей

Компонент — VImage

  • Автогенерация srcset — передайте widths: [400, 800, 1200]; строка srcset строится автоматически; проп sizes пробрасывается
  • Дескрипторы плотностиdensities: [1, 2, 3] (переиспользует src) или { 1: …, 2: … } (отдельные файлы на плотность) для 1x/2x/3x srcset на изображениях фиксированного размера
  • Фокальная точкаfocal: { x, y } отображается в object-position, чтобы объект оставался в кадре при обрезке через fit="cover"
  • Переключение WebP / AVIFsrc как { avif?, webp?, fallback } рендерит <picture> с типизированными элементами <source>
  • Адаптивная арт-дирекция — именованные брейкпоинты отображаются в элементы <source media="...">; запросы max-width и min-width сортируются корректно
  • Проп fetchpriorityhigh для LCP-изображений, low для находящихся ниже первого экрана; отображается в нативный HTML-атрибут
  • Проп decodingasync (по умолчанию) / sync / auto; передаётся напрямую в <img>
  • Повтор при ошибке — проп maxRetries с экспоненциальной задержкой; автоматически повторяет неудачные загрузки без ручного вмешательства
  • Состояние ошибки — слот #error для кастомного UI; встроенный вариант по умолчанию (серый прямоугольник + иконка); событие @error

Загрузка

  • Ленивая загрузка через IntersectionObserver — IO вместо loading="lazy" для точного контроля; настраиваемые rootMargin и threshold; SSR-безопасно
  • Пулинг IO — компоненты с одинаковой конфигурацией rootMargin+threshold делят один инстанс IntersectionObserver; никаких накладных расходов при 50+ изображениях
  • Директива фонового изображенияv-lazy-img устанавливает background-image на любой элемент после появления во вьюпорте; плейсхолдер LQIP; настраиваемый transition; колбэки onLoad/onError
  • useBackgroundImage() — composable для ленивых + адаптивных (image-set()) фонов с blur-up; возможность srcset, которой не хватает v-lazy-img

Composables и утилиты

  • useImage() — headless конечный автомат (idle → loading → loaded | error) + вычисляемый imgAttrs; работает с любой разметкой
  • useImagePreloader() — предзагрузка пакета URL перед навигацией; { loaded, total, progress, isComplete, errors }
  • buildSizes() — построение атрибута sizes из объекта, ключи которого — брейкпоинты; интегрируется с брейкпоинтами плагина
  • generatePreloadLink() — генерирует HTML <link rel="preload" as="image"> для SSR/Nuxt useHead

CDN-адаптеры — vue-image-kit/cdn

  • Билдеры URL без зависимостей для Cloudinary, imgix, Bunny CDN, Sanity, Storyblok, Contentful, Vercel, Cloudflare Images, ImageKit.io, TwicPics, Netlify Image CDN, Gumlet
  • Единый интерфейс .url(path, options) / .srcset(path, widths) для всех провайдеров
  • autoLoader() — определяет 8 из 12 провайдеров прямо по хосту URL, без ручной настройки адаптера на каждое изображение; нераспознанные хосты проходят без изменений

CLI — npx vue-image-kit generate

  • Изменяет размер изображений под несколько ширин, конвертирует в WebP/AVIF, генерирует base64 LQIP, кодирует BlurHash
  • Записывает TypeScript-манифест (images.ts) со всеми предвычисленными метаданными
  • Режим --watch, --dry-run, --skip-existing, --concurrency; конфиг через vue-image-kit.config.js
  • sharp как опциональная peer-зависимость — не включается в браузерный бандл

Экосистема

  • Модуль Nuxtvue-image-kit/nuxt; автоматически регистрирует <VImage> и v-lazy-img; автоимпортирует все composables и утилиты; брейкпоинты через runtimeConfig
  • Плагин Vitevue-image-kit/vite; запускает обработчик CLI на buildStart; перезапускается в handleHotUpdate во время разработки; импорты на этапе сборки через суффиксы запроса ?vik / ?thumbhash
  • Vue-плагинapp.use(VImageKitPlugin, { breakpoints }) регистрирует компонент и директиву глобально
  • Ноль внешних runtime-зависимостей — только Vue 3 как peer-зависимость; полный ESM + CJS, tree-shakeable, sideEffects: false (см. Размер бандла и peer-зависимости)

Установка

bash
npm install vue-image-kit

Peer-зависимость:

bash
npm install vue@>=3.0

Быстрый старт — Vue 3

1. Зарегистрируйте плагин

ts
// main.ts
import { createApp } from 'vue'
import { VImageKitPlugin } from 'vue-image-kit'
import App from './App.vue'

const app = createApp(App)
app.use(VImageKitPlugin)
app.mount('#app')

2. Используйте компонент

vue
<template>
  <VImage
    src="/photo.jpg"
    alt="Mountain landscape"
    :width="1200"
    :height="600"
    blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
  />
</template>

<VImage> зарегистрирован глобально плагином. Импорт не нужен.

3. Или импортируйте явно

vue
<script setup lang="ts">
import { VImage } from 'vue-image-kit'
</script>

<template>
  <VImage src="/photo.jpg" alt="My photo" />
</template>

Быстрый старт — Nuxt 3

1. Добавьте модуль в nuxt.config.ts

ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['vue-image-kit/nuxt'],
  vueImageKit: {
    breakpoints: {
      sm: '(max-width: 640px)',
      md: '(max-width: 1024px)',
    },
  },
})

2. Используйте в страницах и компонентах — всё автоимпортируется

vue
<template>
  <VImage
    :src="{ avif: '/hero.avif', webp: '/hero.webp', fallback: '/hero.jpg' }"
    alt="Hero image"
    :width="1920"
    :height="1080"
    :widths="[640, 1024, 1920]"
    sizes="100vw"
    blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
    :lazy="true"
  />
</template>

<VImage>, v-lazy-img и все composables регистрируются автоматически — импорты не нужны. Canvas и IntersectionObserver активируются только на клиенте — без рассинхронизации при гидратации.