Интеграции
Модуль Nuxt
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['vue-image-kit/nuxt'],
vueImageKit: {
breakpoints: {
sm: '(max-width: 640px)',
md: '(max-width: 1024px)',
},
},
})После настройки:
<VImage>иv-lazy-imgдоступны во всех шаблонах без импортов- Все composables (
useImage,useImagePreloaderи т. д.) автоимпортируются - Все утилиты (
generateSrcset,buildSizes,generatePreloadLinkи т. д.) автоимпортируются
onDemandServer: изображения по запросу как маршрут Nitro
Задайте onDemandServer, чтобы зарегистрировать обработчик vue-image-kit/server как настоящий серверный маршрут Nitro через addServerHandler — без ручного файла server/routes/...:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['vue-image-kit/nuxt'],
vueImageKit: {
onDemandServer: true, // root по умолчанию — собственная директория `public/` Nuxt
},
})<VImage src="/photos/cat.jpg" alt="Photo" :widths="[400, 800]" loader="server" />onDemandServer: true использует все значения по умолчанию (root public/, маршрут /_vik/image); передайте объект, чтобы переопределить любое из них — те же опции, что у createImageHandler (root, cacheDir, maxAge, allowedWidths, maxWidth), плюс route:
vueImageKit: {
onDemandServer: {
root: 'assets/uploads',
route: '/api/img',
maxWidth: 2000,
},
},Маршрут также автоматически становится значением по умолчанию для loader="server" — повторять его как serverRoute не нужно, если только обработчик не размещён где-то, что этот модуль не зарегистрировал (например, развёрнут отдельно). root всегда попадает только в приватный runtime-конфиг (useRuntimeConfig().vueImageKitServer, только на сервере) — никогда не раскрывается клиенту, в отличие от breakpoints.
Плагин Vite
Обрабатывайте изображения на этапе сборки — так же, как CLI, но интегрировано в жизненный цикл Vite. Запускается на buildStart и перезапускается в dev-режиме при изменении исходных изображений.
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { vueImageKit } from 'vue-image-kit/vite'
export default defineConfig({
plugins: [
vue(),
vueImageKit({
input: './src/images',
output: './public/images',
widths: [400, 800, 1200],
manifest: './src/assets/images.ts',
}),
],
})Поддерживаются все опции CLI. sharp должен быть установлен как dev-зависимость.
buildStart/handleHotUpdate вызывают ту же generate(), что и CLI, поэтому инкрементальная генерация применима и здесь — и автоматически включается именно во время vite dev (не vite build), если не задать incremental явно. Изменение одного исходного файла в dev переобрабатывает только этот файл, а не весь пакет.
Импорты на этапе сборки
Плагин также разрешает импорты с суффиксом запроса, так что вам никогда не нужно вручную настраивать пропы — метаданные попадают прямо в ваш JS на этапе сборки:
import meta from './photo.jpg?vik'
// → { src, srcset, webp, avif, width, height, placeholder, blurhash, thumbhash, name, src400, ... }
import hash from './photo.jpg?thumbhash'
// → 'base64string'Передавайте метаданные прямо в проп image компонента <VImage> — без ручной настройки полей:
<script setup lang="ts">
import meta from './hero.jpg?vik'
</script>
<template>
<VImage :image="meta" alt="Hero" />
</template>?vikизменяет размер/кодирует изображение вoutputи возвращает полную запись манифеста (URL используютpublicPath, точно как в сгенерированном манифесте). ThumbHash включается всегда.?thumbhashвычисляет только строку хэша и не пишет файлы.
Оба перезапускаются при изменении исходного изображения в dev. Требуется sharp; thumbhash требуется для вывода хэша.
TypeScript — включите типизированные импорты ?vik / ?thumbhash, один раз сославшись на встроенные декларации (например, в env.d.ts):
/// <reference types="vue-image-kit/vite/client" />Обслуживание по запросу в dev-режиме
И CLI, и импорты на этапе сборки выше — это пакетная/заблаговременная обработка — они обрабатывают изображения до того, как их запросят. Если вы не хотите запускать шаг сборки вообще во время разработки, установите dev.onDemand: true, и изображения будут изменять размер по запросу, кэшируясь на диск после первого попадания:
vueImageKit({
dev: { onDemand: true }, // монтирует обработчик на /_vik/image во время `vite dev`
})<img src="/_vik/image?src=/photos/cat.jpg&w=800&format=webp" />Это работает только в dev — configureServer (хук Vite, который он использует) никогда не запускается во время vite build. Для продакшена без CDN смонтируйте тот же обработчик в своём собственном сервере — см. Самостоятельно размещаемый сервер по запросу ниже.
Самостоятельно размещаемый сервер по запросу
Нет CDN, не хотите заранее запускать CLI, хотите, чтобы изображения изменяли размер по запросу и в продакшене? vue-image-kit/server экспортирует тот же обработчик, что используется dev-мидлваром Vite выше — маленький, framework-агностичный обработчик запросов Node, который вы монтируете сами.
import { createImageHandler } from 'vue-image-kit/server'
const handler = createImageHandler({ root: './public' })Обычный Node http:
import { createServer } from 'node:http'
import { createImageHandler } from 'vue-image-kit/server'
const imageHandler = createImageHandler({ root: './public' })
createServer((req, res) => {
if (req.url?.startsWith('/_vik/image')) {
imageHandler(req, res)
return
}
// ...обслужить всё остальное
}).listen(3000)Express:
app.get('/_vik/image', createImageHandler({ root: './public' }))Форма запроса: GET {route}?src=/photos/cat.jpg&w=800&format=webp&q=80 — src обязателен (разрешается строго внутри root; всё, что выходит за его пределы, отклоняется с 403, несуществующий файл — с 404). w, format (jpg/webp/avif/png) и q — все опциональны. Без w и без format исходные байты передаются насквозь без изменений — без вызова sharp, работает для любого типа файла. Иначе результат изменяется в размере/перекодируется через sharp и кэшируется на диск (cacheDir, по умолчанию <root>/.vik-cache) по ключу из всех параметров, влияющих на результат, так что повторный запрос — это попадание в кэш, а не перекодирование.
buildImageUrl('/photos/cat.jpg', { width: 800, format: 'webp' })
// → '/_vik/image?src=%2Fphotos%2Fcat.jpg&w=800&format=webp'Опции
| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
root | string | — | Обязателен. Директория, к которой разрешается (и ограничивается) src. |
cacheDir | string | <root>/.vik-cache | Где кэшируется преобразованный вывод. |
maxAge | number | 31536000 (1 год) | Cache-Control: public, max-age=..., must-revalidate, плюс ETag, выведенный из источника. Закэшированный ответ всё равно переиспользуется без единого запроса весь maxAge — это и означает max-age, независимо от этого заголовка — он влияет только на то, что происходит после истечения (или при явной ревалидации, например, жёстком обновлении): дешёвый 304 на основе ETag вместо полной перезагрузки, и (в отличие от immutable) браузеру хотя бы разрешено спросить. Если источник может меняться, и это нужно подхватывать раньше, чем через год, — снизьте maxAge, используйте no-cache или добавьте версию в URL — сама по себе эта опция этого не сделает. |
allowedWidths | number[] | — | Ограничить w строго этими значениями (400 для всего остального). Не задано: любое положительное целое, ограниченное maxWidth. |
maxWidth | number | 4000 | Верхняя граница для w, когда allowedWidths не задан. |
Область применения: обрабатывает одно преобразование на запрос для стандартных растровых источников (jpg/png/webp/avif → jpg/webp/avif/png) — реалистичный случай «дай мне это фото шириной X». Не воспроизводит специальную обработку GIF/SVG из CLI или пакетную генерацию нескольких вариантов (src/cli/processor.ts — место для этого) — источник .gif/.svg всегда проходит насквозь без изменений, побайтово идентично, независимо от w/format (sharp здесь никогда не просят изменить размер GIF — это незаметно убрало бы анимацию — или растеризовать SVG). Любое другое нераспознанное расширение источника откатывается на jpg, когда запрошено преобразование, или проходит насквозь без изменений, если не заданы ни w, ни format.
Заметка о безопасности: ответы об ошибках включают исходный текст ошибки как обычный текст (например, «sharp is not installed»), чтобы упростить отладку самостоятельно размещённых установок. Если вы не хотите, чтобы эта деталь доходила до клиентов, поставьте перед этим собственный middleware обработки ошибок в продакшене.
Подключение VImage: loader="server"
Проп loader у VImage автоматически строит URL запросов к обработчику — без ручных вызовов buildImageUrl():
<VImage src="/photos/cat.jpg" alt="Photo" :widths="[400, 800]" loader="server" />Та же форма, что и у cdn: в сочетании с widths каждый кандидат получает собственный URL запроса вместо одного общего URL. Маршрут по умолчанию — /_vik/image (совпадает с dev-мидлваром Vite и собственным соглашением обработчика) — переопределите его для отдельного компонента через loaderRoute, либо задайте один раз для каждого VImage через Vue-плагин (app.use(VImageKitPlugin, { serverRoute: '/api/img' })) или опцию onDemandServer модуля Nuxt (см. Модуль Nuxt выше, которая также регистрирует настоящий маршрут Nitro за вас). Если заданы и cdn, и loader="server" на одном изображении, побеждает cdn — внешний CDN уже разрешает изображение, локальный сервер по запросу — запасной вариант на случай, когда его нет.