Vite рассматривает статические ресурсы как часть графа модулей приложения. Изображения, шрифты, SVG-файлы, медиафайлы и другие ассеты могут импортироваться напрямую из JavaScript, TypeScript, CSS и HTML. Во время разработки Vite отдаёт файлы через dev server практически без преобразований, а во время production-сборки оптимизирует пути, хеширует имена и перемещает ресурсы в директорию сборки.
Под статическими ресурсами обычно понимаются:
public.import logo from './assets/logo.png'
const image = document.createElement('img')
image.src = logo
document.body.appendChild(image)
После импорта переменная logo содержит URL до
обработанного файла.
Во время разработки значение может выглядеть так:
/assets/logo.png
После production-сборки:
/assets/logo.a1b2c3.png
Хеширование позволяет:
Vite автоматически обрабатывает распространённые форматы:
.png
.jpg
.jpeg
.gif
.svg
.webp
.avif
.mp4
.webm
.mp3
.woff
.woff2
.ttf
Дополнительные расширения могут подключаться через плагины или настройку Rollup.
import icon from './icons/menu.svg'
console.log(icon)
Результатом будет путь к файлу.
Для превращения SVG в строку можно использовать суффикс
?raw.
import iconRaw from './icons/menu.svg?raw'
console.log(iconRaw)
Результат:
<svg>...</svg>
Подход полезен для:
Во многих проектах используются плагины:
vite-svg-loadersvgrПример для React:
import Logo from './logo.svg?react'
export default function App() {
return <Logo />
}
Vite автоматически обрабатывает пути внутри CSS.
body {
background-image: url('./images/bg.png');
}
Во время сборки:
@font-face {
font-family: 'Inter';
src: url('./fonts/inter.woff2') format('woff2');
}
Vite корректно обработает:
import introVideo from './videos/intro.mp4'
const video = document.createElement('video')
video.src = introVideo
video.controls = true
document.body.appendChild(video)
import clickSound from './audio/click.mp3'
const audio = new Audio(clickSound)
audio.play()
Vite поддерживает JSON из коробки.
import data from './data/users.json'
console.log(data)
JSON автоматически преобразуется в JavaScript-объект.
import { name, version } from './package.json'
console.log(name)
Подход уменьшает объём импортируемых данных.
Суффикс ?raw позволяет загружать содержимое файла как
строку.
import text from './content/article.txt?raw'
console.log(text)
Применение:
?urlИногда требуется получить только URL ресурса без дополнительной обработки.
import fileUrl from './docs/manual.pdf?url'
Результат:
/assets/manual.xxxxx.pdf
Vite поддерживает .wasm.
import init from './math.wasm'
Также доступны варианты:
import wasmUrl from './math.wasm?url'
Маленькие файлы могут автоматически встраиваться в bundle как Base64.
Пример:
import icon from './icon.png'
После сборки:
data:image/png;base64,...
Это уменьшает количество HTTP-запросов.
Параметр build.assetsInlineLimit задаёт максимальный
размер файла для inline-встраивания.
import { defineConfig } from 'vite'
export default defineConfig({
build: {
assetsInlineLimit: 4096
}
})
Значение указывается в байтах.
publicПапка public предназначена для файлов, которые не должны
проходить через pipeline Vite.
Структура:
project/
├── public/
│ ├── robots.txt
│ ├── favicon.ico
│ └── images/
public<img src="/images/banner.png">
Файлы:
publicПодходит для:
robots.txt;manifest.json;public использовать нежелательноЕсли файл участвует в модульной системе приложения, предпочтительнее обычный импорт:
import image from './assets/photo.png'
Это обеспечивает:
import image from './assets/picture.png'
public<img src="/logo.png">
Во время vite build происходит:
Пример:
dist/
├── assets/
│ ├── app.a1b2.js
│ ├── logo.f3d4.png
│ └── font.e5f6.woff2
Параметр build.assetsDir управляет каталогом
ресурсов.
import { defineConfig } from 'vite'
export default defineConfig({
build: {
assetsDir: 'static'
}
})
Результат:
dist/static/
Часто используются алиасы для упрощения импортов.
import image from '@/assets/image.png'
Настройка:
import path from 'path'
import { defineConfig } from 'vite'
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
})
new URLРекомендуемый способ:
const imageUrl = new URL('./img/photo.png', import.meta.url).href
Подход корректно работает:
import.meta.globconst images = import.meta.glob('./gallery/*.png', {
eager: true
})
console.log(images)
Vite создаст объект:
{
'./gallery/1.png': Module,
'./gallery/2.png': Module
}
const modules = import.meta.glob('./pages/*.js')
Файлы загружаются только при необходимости.
Vite автоматически анализирует:
url()@importПример:
.hero {
background: url('./hero.webp');
}
Одной из важных особенностей Vite является построение графа зависимостей ресурсов.
Пример цепочки:
main.js
└── style.css
└── font.woff2
Vite отслеживает все связи и корректно обновляет ресурсы через HMR.
При изменении:
Vite обновляет модуль без полной перезагрузки страницы.
Это особенно важно при разработке интерфейсов.
Production-сборка использует content hash:
logo.a1b2c3.png
Изменение файла приводит к изменению имени, благодаря чему браузер автоматически загружает новую версию.
Vite работает через ES Modules, поэтому импорт должен быть анализируемым.
Корректно:
import img from './img/photo.png'
Проблемно:
import img from dynamicVariable
Для динамических путей рекомендуется:
new URL(path, import.meta.url)
или:
import.meta.glob()
TypeScript может требовать декларации модулей.
Пример:
declare module '*.png' {
const value: string
export default value
}
Однако большинство шаблонов Vite уже содержат необходимые типы.
Production-сборка Vite основана на Rollup.
Rollup отвечает за:
Ресурсы могут подключаться напрямую:
const image = 'https://cdn.example.com/banner.png'
Но локальный импорт через Vite даёт:
В SSR-режиме Vite генерирует специальные manifest-файлы, связывающие серверный код и production-ассеты.
Это особенно важно для:
src/
├── assets/
│ ├── images/
│ ├── fonts/
│ ├── icons/
│ └── videos/
├── components/
├── styles/
└── main.js
Часто применяется следующая схема:
assets/
├── images/
├── icons/
├── fonts/
├── audio/
├── video/
└── svg/
Это упрощает: