Vite и Vue
Готовые конфигурации плагина Vite для проекта на Vue 3. В каждом рецепте сказано, когда его применять, показан полный конфиг и шаблон и описано, что вы получите. Выбрать рецепт поможет страница Выбор способа.
Для всех рецептов нужен sharp в dev-зависимостях, а там, где считается ThumbHash, ещё и thumbhash:
npm install -D sharp thumbhashЧтобы импорты были типизированы, один раз сошлитесь на встроенные декларации, например в env.d.ts:
/// <reference types="@macrulez/vue-image-kit/vite/client" />Размытие для импортированного изображения
Когда применять. Несколько изображений импортируются в компоненты, и всё, что нужно, — размытие и правильный размер на время загрузки. Ничего не уменьшается и никакие файлы не пишутся.
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { vueImageKit } from '@macrulez/vue-image-kit/vite'
export default defineConfig({
plugins: [vue(), vueImageKit({ generate: false })],
})generate: false не даёт плагину обрабатывать целую папку при старте, поэтому input настраивать не нужно — плагин только отвечает на импорты ниже.
<script setup lang="ts">
import photo from './assets/photo.jpg'
import placeholder from './assets/photo.jpg?placeholder'
</script>
<template>
<VImage :src="photo" v-bind="placeholder" alt="Photo" />
</template>Что вы получите. ?placeholder возвращает { hazehash, placeholderColor, width, height } (blurhash, если пакет hazehash не установлен), посчитанные при сборке по настоящему файлу, — это те же пропсы, что принимает <VImage>, поэтому хватает v-bind. Два импорта одного файла дают разное: обычный — URL изображения, с запросом — данные плейсхолдера.
Варианты.
?placeholder=blurhash— BlurHash вместо HazeHash.?placeholder=thumbhash— ThumbHash вместо HazeHash (поддерживает прозрачность).?placeholder=color— только доминирующий цвет и размер, самый лёгкий вариант.?hazehash,?blurhashили?thumbhash— только строка хеша, если хотите передать её сами:<VImage :src="photo" :hazehash="hash" :width="800" :height="600" />.?placeholder=blurhash,size— любой набор полей в одном импорте, например хеш вместе с реальнымиwidthиheight. Поля:hazehash,blurhash,thumbhash,color,size,previewиaspect; см. Выбор того, что считать.?color,?size,?aspect,?preview— по одному голому значению:'#c82828',{ width, height },2, data URI крошечного PNG.?blurhash&components=6x4— настройки только для этого изображения.
Размытие для целой папки через import.meta.glob
Когда применять. Много изображений в папке, а компонент выбирает нужное по имени файла или ключу.
// vite.config.ts — как в предыдущем рецепте
vueImageKit({ generate: false })<script setup lang="ts">
const images = import.meta.glob('./assets/gallery/*.jpg', { import: 'default', eager: true })
const placeholders = import.meta.glob('./assets/gallery/*.jpg', {
query: '?placeholder',
import: 'default',
eager: true,
})
const names = ['sunrise', 'forest', 'lake']
const path = (name: string) => `./assets/gallery/${name}.jpg`
</script>
<template>
<VImage
v-for="name in names"
:key="name"
:src="images[path(name)]"
v-bind="placeholders[path(name)]"
:alt="name"
/>
</template>Что вы получите. Два объекта с одинаковыми ключами-путями: адреса изображений и их пропсы плейсхолдера. Достаточно положить файл в папку — дописывать импорт не нужно.
Размытие для изображений, путь которых приходит из данных
Когда применять. src не написан в шаблоне: он берётся из массива, CMS или JSON-файла (:src="category.image"). Один импорт на изображение здесь не сработает, поэтому передайте плагину папки целиком, и он построит манифест по URL.
// vite.config.ts
import { vueImageKit } from '@macrulez/vue-image-kit/vite'
export default defineConfig({
plugins: [
vue(),
vueImageKit({
generate: false,
placeholders: { dirs: ['public/images'] },
}),
],
})// main.ts
import { createApp } from 'vue'
import { VImageKitPlugin } from '@macrulez/vue-image-kit'
import placeholders from 'virtual:vue-image-kit/placeholders'
import App from './App.vue'
createApp(App).use(VImageKitPlugin, { placeholders }).mount('#app')<template>
<VImage v-for="item in items" :key="item.id" :src="item.image" :alt="item.title" />
</template>Что вы получите. Каждое изображение из public/images попадает в манифест с HazeHash (BlurHash, если hazehash не установлен), цветом и размером под тем URL, по которому оно отдаётся (/images/cat.jpg). <VImage> находит свою запись по точному src, так что в шаблоне пропсы не нужны совсем. Манифест пересобирается при изменении файла в папке и кешируется между сборками.
Что важно знать.
- Файл из публичной папки записывается по пути от неё. Папке вне её нужен
urlPrefix— см. следующий рецепт. - Изображение, импортированное в компонент, после сборки получает хешированный URL, и манифест его не найдёт. Для таких используйте импорт плейсхолдера.
Папки, которые отдаются с другого URL
Когда применять. Изображения хранятся в репозитории, но отдаются откуда-то ещё — с CDN, из маршрута загрузок, с префиксом, который добавляет прокси.
vueImageKit({
generate: false,
placeholders: {
dirs: ['public/images', { dir: 'content/photos', urlPrefix: 'https://cdn.example.com/photos' }],
},
})Что вы получите. Файлы из content/photos записываются как https://cdn.example.com/photos/<путь> — именно такой src используется в шаблоне, который ссылается на CDN. Без urlPrefix папка вне public/ записывается по пути в проекте (/content/photos/a.jpg), который совпадает только с URL dev-сервера, и сборка об этом предупредит.
Удалённые и CDN-изображения в манифесте
Когда применять. Изображения лежат на другом хосте и в репозитории их нет.
vueImageKit({
generate: false,
placeholders: {
urls: ['https://res.cloudinary.com/demo/image/upload/sample.jpg'],
timeout: 20000,
},
})Что вы получите. Плагин скачивает каждый URL во время сборки и добавляет плейсхолдер в манифест под этим же адресом. URL распознаваемого CDN запрашивается в уменьшенной версии, а размер читается из начала оригинала. Результаты кешируются, поэтому повторная сборка не качает заново; refreshRemote: true заставит скачать снова.
Другой вид плейсхолдера и настройка
Когда применять. HazeHash по умолчанию не подходит: нужен BlurHash или ThumbHash, только цвет для самого лёгкого результата или более длинный HazeHash (tuning.budget).
vueImageKit({
generate: false,
placeholders: {
dirs: ['public/images'],
mode: 'thumbhash',
tuning: { components: [6, 4], sample: 128, color: 'average' },
},
})mode—'hazehash'(по умолчанию, если установлен пакетhazehash),'blurhash'(по умолчанию в остальных случаях),'thumbhash'или'color'. Он же задаёт, что вернёт импорт?placeholderбез значения.tuning.components— число компонент BlurHash по каждой оси, по умолчанию[4, 3]. Больше компонент — больше деталей и длиннее строка.tuning.sample— размер в пикселях, до которого изображение уменьшается перед расчётом хеша.tuning.color—'dominant'(самый частый цвет) или'average'.
Эти настройки применяются ко всем плейсхолдерам, которые считает плагин, в том числе к импортам ?placeholder. При их смене кеш сбрасывается. См. Настройка хешей.
Адаптивные варианты для папки
Когда применять. Нужны заранее сделанные файлы WebP/AVIF нескольких ширин и srcset, построенный по ним.
vueImageKit({
input: './src/images',
output: './public/images',
widths: [400, 800, 1200],
formats: ['webp', 'avif', 'jpg'],
manifest: './src/assets/images.ts',
})<script setup lang="ts">
import { images } from './assets/images'
const hero = images.find((image) => image.name === 'hero')
</script>
<template>
<VImage v-if="hero" :image="hero" alt="Hero" />
</template>Что вы получите. При каждой сборке плагин уменьшает каждое изображение из input в output и пишет рядом с вашим кодом TypeScript-манифест: массив images с записью на каждый исходный файл, где name — имя файла без расширения. В vite dev обработка инкрементальная: при изменении одного файла пересобирается только он. Принимаются все опции команды generate.
Варианты для одного изображения
Когда применять. Варианты нужны одному hero-изображению, а обработка всей папки не нужна.
<script setup lang="ts">
import hero from './assets/hero.jpg?vik'
</script>
<template>
<VImage :image="hero" alt="Hero" />
</template>Что вы получите. ?vik уменьшает именно этот файл в output и возвращает полные метаданные — адреса, srcset, размер, BlurHash и ThumbHash, — которые проп image принимает как есть. Варианты попадают в папку output плагина (по умолчанию ./public/images). Добавьте generate: false, если остальную часть input обрабатывать не нужно:
vueImageKit({ generate: false, output: './public/images', widths: [400, 800, 1200] })Варианты и манифест папок вместе
Когда применять. Для одних изображений нужны сгенерированные варианты, другие отдаются как есть и требуют только размытия.
vueImageKit({
input: './src/images',
output: './public/images',
widths: [400, 800, 1200],
placeholders: { dirs: ['public/uploads'] },
})Что вы получите. Эти две задачи независимы: пакетная обработка берёт input, а виртуальный манифест покрывает public/uploads. Манифест регистрируется так же, как в рецепте про папки выше.
Варианты по запросу в dev
Когда применять. Во время разработки не хочется шага сборки: изображения уменьшаются по запросу и кешируются.
vueImageKit({ generate: false, dev: { onDemand: true } })<img src="/_vik/image?src=/photos/cat.jpg&w=800&format=webp" />Что вы получите. Обработчик на /_vik/image, который работает только в vite dev. Для продакшена без CDN используйте свой сервер.