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напрямую - Плейсхолдер shimmer —
placeholderMode="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/3xsrcset на изображениях фиксированного размера - Фокальная точка —
focal: { x, y }отображается вobject-position, чтобы объект оставался в кадре при обрезке черезfit="cover" - Переключение WebP / AVIF —
srcкак{ avif?, webp?, fallback }рендерит<picture>с типизированными элементами<source> - Адаптивная арт-дирекция — именованные брейкпоинты отображаются в элементы
<source media="...">; запросыmax-widthиmin-widthсортируются корректно - Проп
fetchpriority—highдля LCP-изображений,lowдля находящихся ниже первого экрана; отображается в нативный HTML-атрибут - Проп
decoding—async(по умолчанию) /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/NuxtuseHead
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-зависимость — не включается в браузерный бандл
Экосистема
- Модуль Nuxt —
vue-image-kit/nuxt; автоматически регистрирует<VImage>иv-lazy-img; автоимпортирует все composables и утилиты; брейкпоинты черезruntimeConfig - Плагин Vite —
vue-image-kit/vite; запускает обработчик CLI наbuildStart; перезапускается вhandleHotUpdateво время разработки; импорты на этапе сборки через суффиксы запроса?vik/?thumbhash - Vue-плагин —
app.use(VImageKitPlugin, { breakpoints })регистрирует компонент и директиву глобально - Ноль внешних runtime-зависимостей — только Vue 3 как peer-зависимость; полный ESM + CJS, tree-shakeable,
sideEffects: false(см. Размер бандла и peer-зависимости)
Установка
npm install vue-image-kitPeer-зависимость:
npm install vue@>=3.0Быстрый старт — Vue 3
1. Зарегистрируйте плагин
// 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. Используйте компонент
<template>
<VImage
src="/photo.jpg"
alt="Mountain landscape"
:width="1200"
:height="600"
blurhash="LEHV6nWB2yk8pyo0adR*.7kCMdnj"
/>
</template><VImage> зарегистрирован глобально плагином. Импорт не нужен.
3. Или импортируйте явно
<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
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['vue-image-kit/nuxt'],
vueImageKit: {
breakpoints: {
sm: '(max-width: 640px)',
md: '(max-width: 1024px)',
},
},
})2. Используйте в страницах и компонентах — всё автоимпортируется
<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 активируются только на клиенте — без рассинхронизации при гидратации.