Интеграция с бэкендом
Примечание
Если вы хотите обслуживать HTML с помощью традиционного бэкенда (например, Rails, Laravel), но использовать Vite для обслуживания ресурсов, проверьте существующие интеграции, перечисленные в Awesome Vite.
Если вам нужна пользовательская интеграция, вы можете следовать шагам в этом руководстве, чтобы настроить её вручную.
В вашей конфигурации Vite настройте точку входа и включите манифест сборки:
jsexport default
defineConfig({server: {cors: { // источник, к которому вы будете обращаться через браузерorigin: 'http://my-backend.example.com', }, },build: { // генерация .vite/manifest.json в outDirmanifest: true,rollupOptions: { // перезапись стандартной точки входа .htmlinput: '/path/to/main.js', }, }, })Если вы не отключили полифилл предварительной загрузки модулей, вам также нужно импортировать полифилл в вашу точку входа.
js// добавление начала входной точки вашего приложения import 'vite/modulepreload-polyfill'
Для разработки вставьте следующее в HTML-шаблон вашего сервера (замените
http://localhost:5173
на локальный URL, по которому работает Vite):html<!-- в режиме разработки --> <script type="module" src="http://localhost:5173/@vite/client"></script> <script type="module" src="http://localhost:5173/main.js"></script>
Чтобы правильно обслуживать ресурсы, у вас есть два варианта:
- Убедитесь, что сервер настроен на проксирование запросов статических ресурсов к серверу Vite
- Установите
server.origin
, чтобы сгенерированные URL-адреса ресурсов разрешались с использованием URL-адреса бэкенд-сервера вместо относительного пути
Это необходимо для правильной загрузки ресурсов, таких как изображения.
Обратите внимание, что если вы используете React с
@vitejs/plugin-react
, вам также нужно добавить это перед вышеуказанными скриптами, так как плагин не может изменить HTML, который вы обслуживаете (заменитеhttp://localhost:5173
на локальный URL, по которому работает Vite):html<script type="module"> import RefreshRuntime from 'http://localhost:5173/@react-refresh' RefreshRuntime.injectIntoGlobalHook(window) window.$RefreshReg$ = () => {} window.$RefreshSig$ = () => (type) => type window.__vite_plugin_react_preamble_installed__ = true </script>
Для продакшен-сборки, после выполнения команды
vite build
, будет сгенерирован файл.vite/manifest.json
вместе с другими файлами ресурсов. Пример файла манифеста выглядит следующим образом:json{ "_shared-B7PI925R.js": { "file": "assets/shared-B7PI925R.js", "name": "shared", "css": ["assets/shared-ChJ_j-JJ.css"] }, "_shared-ChJ_j-JJ.css": { "file": "assets/shared-ChJ_j-JJ.css", "src": "_shared-ChJ_j-JJ.css" }, "logo.svg": { "file": "assets/logo-BuPIv-2h.svg", "src": "logo.svg" }, "baz.js": { "file": "assets/baz-B2H3sXNv.js", "name": "baz", "src": "baz.js", "isDynamicEntry": true }, "views/bar.js": { "file": "assets/bar-gkvgaI9m.js", "name": "bar", "src": "views/bar.js", "isEntry": true, "imports": ["_shared-B7PI925R.js"], "dynamicImports": ["baz.js"] }, "views/foo.js": { "file": "assets/foo-BRBmoGS9.js", "name": "foo", "src": "views/foo.js", "isEntry": true, "imports": ["_shared-B7PI925R.js"], "css": ["assets/foo-5UjPuW-k.css"] } }
Манифест имеет структуру
Record<name, chunk>
, где каждый чанк соответствует интерфейсуManifestChunk
:tsinterface ManifestChunk { src?: string file: string css?: string[] assets?: string[] isEntry?: boolean name?: string names?: string[] isDynamicEntry?: boolean imports?: string[] dynamicImports?: string[] }
Каждая запись в манифесте представляет собой что-то одно из следующего списка:
- Чанки точек входа: Генерируются из файлов, указанных в
build.rollupOptions.input
. Эти чанки имеютisEntry: true
, а их ключ — это относительный путь src от корня проекта. - Динамические чанки точек входа: Генерируются из динамических импортов. Эти чанки имеют
isDynamicEntry: true
, а их ключ — это относительный путь src от корня проекта. - Чанки, не являющиеся точками входа: Их ключ — это базовое имя сгенерированного файла с префиксом
_
. - Чанки активов: Генерируются из импортированных активов, таких как изображения, шрифты. Их ключ — это относительный путь src от корня проекта.
- **CSS-файлы: Когда
build.cssCodeSplit
равноfalse
, генерируется единый CSS-файл с ключомstyle.css
. Когдаbuild.cssCodeSplit
не равноfalse
, ключ генерируется аналогично JS-чанкам (т. е. чанки точек входа не будут иметь префикс_
, а чанки, не являющиеся точками входа, будут иметь префикс_
).
Чанки содержат информацию о своих статических и динамических импортах (оба являются ключами, которые соответствуют соответствующему чанку в манифесте), а также о соответствующих CSS-файлах и файлах активов (если таковые имеются).
- Чанки точек входа: Генерируются из файлов, указанных в
Вы можете использовать этот файл для рендеринга ссылок или директив предварительной загрузки с хешированными именами файлов.
Вот пример HTML-шаблона для рендеринга правильных ссылок. Синтаксис здесь приведен только для объяснения, замените его на язык шаблонов вашего сервера. Функция
importedChunks
приведена для иллюстрации и не предоставляется Vite.html<!-- в режиме разработки --> <!-- для cssFile из manifest[name].css --> <link rel="stylesheet" href="/{{ cssFile }}" /> <!-- для чанка из importedChunks(manifest, name) --> <!-- для cssFile из chunk.css --> <link rel="stylesheet" href="/{{ cssFile }}" /> <script type="module" src="/{{ manifest[name].file }}"></script> <!-- для чанка из importedChunks(manifest, name) --> <link rel="modulepreload" href="/{{ chunk.file }}" />
В частности, бэкенд, генерирующий HTML, должен включать следующие теги, учитывая файл манифеста и точку входа:
Обратите внимание, что рекомендуется следовать этому порядку для оптимальной производительности:
- Тег
<link rel="stylesheet">
для каждого файла в спискеcss
чанка точки входа (если он существует). - Рекурсивно следовать всем чанкам в списке
imports
точки входа и включать тег<link rel="stylesheet">
для каждого CSS-файла из спискаcss
каждого импортированного чанка (если он существует). - Тег для ключа
file
чанка точки входа. Это может быть<script type="module">
для JavaScript или<link rel="stylesheet">
для CSS. - Опционально, тег
<link rel="modulepreload">
для ключаfile
каждого импортированного JavaScript-чанка, снова рекурсивно следуя импорту, начиная с чанка точки входа.
Следуя приведённому выше примеру манифеста, для точки входа
main.js
в продакшен-сборке должны быть включены следующие теги:html<link rel="stylesheet" href="assets/main.b82dbe22.css" /> <link rel="stylesheet" href="assets/shared.a834bfc3.css" /> <script type="module" src="assets/main.4889e940.js"></script> <!-- опционально --> <link rel="modulepreload" href="assets/shared.83069a53.js" />
В то время как следующее должно быть включено для точки входа
views/foo.js
:html<link rel="stylesheet" href="assets/shared.a834bfc3.css" /> <script type="module" src="assets/foo.869aea0d.js"></script> <!-- опционально --> <link rel="modulepreload" href="assets/shared.83069a53.js" />
Псевдо-реализация
importedChunks
Пример псевдо-реализации
importedChunks
на TypeScript (это потребуется адаптировать для вашего языка программирования и языка шаблонов):tsimport type { Manifest, ManifestChunk } from 'vite' export default function importedChunks( manifest: Manifest, name: string, ): ManifestChunk[] { const seen = new Set<string>() function getImportedChunks(chunk: ManifestChunk): ManifestChunk[] { const chunks: ManifestChunk[] = [] for (const file of chunk.imports ?? []) { const importee = manifest[file] if (seen.has(file)) { continue } seen.add(file) chunks.push(...getImportedChunks(importee)) chunks.push(importee) } return chunks } return getImportedChunks(manifest[name]) }
- Тег