Vite поддерживает специальный механизм импорта файлов в виде обычной
строки. Для этого к пути файла добавляется суффикс
?raw.
Пример:
import text fr om './file.txt?raw'
console.log(text)
В этом случае содержимое файла не обрабатывается как JavaScript-модуль, а загружается как строка целиком.
Если файл file.txt содержит:
Hello Vite
то переменная text будет содержать:
"Hello Vite"
?rawВо время обработки модулей Vite анализирует импортируемый путь. Если
путь содержит ?raw, Vite:
default export.Фактически:
import content from './example.txt?raw'
превращается примерно в:
const content = `
содержимое файла
`
export default content
?raw работает практически с любыми текстовыми
файлами:
import html from './template.html?raw'
import css from './styles.css?raw'
import md from './article.md?raw'
import svg from './icon.svg?raw'
import jsonText from './data.json?raw'
import shader from './shader.glsl?raw'
Главное условие — файл должен быть текстовым.
Один из самых распространённых сценариев — загрузка HTML-шаблонов.
template.html
<div class="card">
<h2>Title</h2>
</div>
Импорт:
import template from './template.html?raw'
document.body.innerHTML = template
Без ?raw SVG обычно обрабатывается как URL ресурса:
import iconUrl from './icon.svg'
С ?raw содержимое SVG становится строкой:
import iconSvg from './icon.svg?raw'
console.log(iconSvg)
Результат:
<svg width="100" height="100">
...
</svg>
Это особенно полезно при:
Markdown-файлы часто импортируются через ?raw.
content/
article.md
import markdown from './content/article.md?raw'
После этого строку можно передать в markdown-парсер:
import { marked } from 'marked'
import markdown from './article.md?raw'
const html = marked(markdown)
Иногда необходимо отображать код прямо в интерфейсе.
import source from './example.js?raw'
console.log(source)
Это используется в:
Очень распространённый сценарий — импорт GLSL-шейдеров.
vertex.glsl
attribute vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
Импорт:
import vertexShader from './vertex.glsl?raw'
?rawimport file from './example.txt'
Чаще всего возвращается URL:
'/assets/example.a1b2c3.txt'
?rawimport file from './example.txt?raw'
Возвращается содержимое:
'Текст внутри файла'
fetchИногда возникает вопрос: что лучше — ?raw или
fetch().
?rawimport text from './text.txt?raw'
Особенности:
fetchconst response = await fetch('/text.txt')
const text = await response.text()
Особенности:
?raw?raw хорошо подходит для:
?raw
использовать нежелательноНе рекомендуется импортировать через ?raw:
Причина — содержимое встраивается в bundle и увеличивает размер JavaScript.
Обычный JSON-импорт:
import data from './data.json'
Возвращает объект:
console.log(data.user.name)
Импорт через ?raw:
import jsonText from './data.json?raw'
Возвращает строку:
console.log(jsonText)
При необходимости строку можно распарсить вручную:
const data = JSON.parse(jsonText)
?raw работает и с import().
const module = await import('./template.html?raw')
console.log(module.default)
Это удобно при ленивой загрузке шаблонов.
Во время production build:
vite build
Vite:
Дополнительные файлы при этом не создаются.
Каждый импорт через ?raw увеличивает итоговый
JavaScript-бандл.
Например:
import hugeText from './huge.txt?raw'
Если файл содержит 2 МБ текста, то bundle тоже увеличится примерно на 2 МБ.
Vite корректно экранирует:
Например:
Line 1
Line "2"
превращается в безопасную JavaScript-строку.
TypeScript может не понимать импорт нестандартных расширений.
Создание файла деклараций:
// vite-env.d.ts
declare module '*?raw' {
const content: string
export default content
}
После этого TypeScript корректно распознаёт импорт:
import shader from './shader.glsl?raw'
Vite поддерживает разные query-модификаторы:
?raw
?url
?worker
?inline
Пример:
import workerUrl from './worker.js?url'
или:
import svgText from './icon.svg?raw'
Каждый модификатор изменяет способ обработки файла.
?rawФайл импортируется как есть.
Например:
import css from './style.css?raw'
CSS не будет:
Так как импортируется одна большая строка, tree shaking неприменим.
Vite загружает весь файл полностью.
Невозможно:
<script setup>
import template from './template.html?raw'
</script>
<template>
<div v-html="template"></div>
</template>
import markdown from './article.md?raw'
export function App() {
return (
<pre>{markdown}</pre>
)
}
<script>
import text from './text.txt?raw'
</script>
<pre>{text}</pre>
Плагины могут самостоятельно обрабатывать ?raw.
Пример проверки query:
export default function myPlugin() {
return {
name: 'my-plugin',
load(id) {
if (id.endsWith('?raw')) {
console.log('Raw import:', id)
}
}
}
}
?raw и
?url?rawimport text from './file.txt?raw'
Результат:
'Содержимое файла'
?urlimport url from './file.txt?url'
Результат:
'/assets/file.a1b2c3.txt'
import cardTemplate from './card.html?raw'
function renderCard(title) {
return cardTemplate.replace('{{title}}', title)
}
card.html
<div class="card">
<h2>{{title}}</h2>
</div>
import exampleCode from './demo.js?raw'
const codeBlock = document.querySelector('#code')
codeBlock.textContent = exampleCode
import query from './query.sql?raw'
console.log(query)
query.sql
SEL ECT *
FROM users
WH ERE active = 1;
import icon fr om './icon.svg?raw'
const button = document.querySelector('button')
button.innerHTML = icon
import emailTemplate from './email.html?raw'
function buildEmail(name) {
return emailTemplate.replace('{{name}}', name)
}
При изменении raw-файла Vite автоматически обновляет модуль через HMR.
Например:
import template from './template.html?raw'
После изменения template.html модуль обновится без
полной перезагрузки страницы.
В SSR-режиме ?raw также возвращает строку:
import html from './template.html?raw'
Это одинаково работает:
Так как production-сборка Vite основана на Rollup, механизм
?raw интегрирован и в процесс финального бандлинга.
Во время сборки Rollup получает уже подготовленный виртуальный модуль со строковым экспортом.
Упрощённая схема:
Файл → Vite plugin pipeline → raw loader → JS module
Пример преобразования:
hello.txt
↓
export default "hello"
defaultНеправильно:
import { text } from './file.txt?raw'
Правильно:
import text from './file.txt?raw'
Плохо подходит для:
Для них лучше использовать:
?url
или обычный импорт ресурсов.
import massiveData from './huge.log?raw'
Это может:
?raw корректно работает с:
Пример:
Привет мир
こんにちは
مرحبا
Импорт:
import text from './unicode.txt?raw'
?raw в экосистеме
ViteМеханизм ?raw является частью философии Vite:
Он позволяет использовать файловую систему как источник данных без дополнительных загрузчиков и сложной конфигурации webpack-style экосистем.