后端集成
注意
如果你希望使用传统的后端(例如 Rails、Laravel)来渲染 HTML,但使用 Vite 来提供资源服务,请查看 Awesome Vite 中列出的现有集成。
如果你需要自定义集成,可以按照本指南中的步骤进行手动配置。
在你的 Vite 配置文件中,配置入口点并启用构建清单(build manifest)
jsexport defaultdefineConfig({server: {cors: { // the origin you will be accessing via browserorigin: 'http://my-backend.example.com', }, },build: { // generate .vite/manifest.json in outDirmanifest: true,rollupOptions: { // overwrite default .html entryinput: '/path/to/main.js', }, }, })如果你没有禁用 module preload polyfill,你还需要在入口文件中导入该 polyfill
js// add the beginning of your app entry import 'vite/modulepreload-polyfill'在开发过程中,请在服务器的 HTML 模板中注入以下内容(将
https://:5173替换为 Vite 运行的本地 URL)html<!-- if development --> <script type="module" src="https://:5173/@vite/client"></script> <script type="module" src="https://:5173/main.js"></script>为了正确提供资源服务,你有两个选择
- 确保服务器配置为将静态资源请求代理到 Vite 服务器
- 设置
server.origin,以便生成的资源 URL 将使用后端服务器 URL 解析,而不是使用相对路径
这对于图片等资源的正常加载是必需的。
注意:如果你在使用带有
@vitejs/plugin-react的 React,你还需要在上述脚本之前添加此内容,因为该插件无法修改你所提供的 HTML(将https://:5173替换为 Vite 运行的本地 URL)html<script type="module"> import RefreshRuntime from 'https://: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>结构,其中每个 chunk 都遵循ManifestChunk接口tsinterface ManifestChunk { /** * The input file name of this chunk / asset if known */ src?: string /** * The output file name of this chunk / asset */ file: string /** * The list of CSS files imported by this chunk */ css?: string[] /** * The list of asset files imported by this chunk, excluding CSS files */ assets?: string[] /** * Whether this chunk or asset is an entry point */ isEntry?: boolean /** * The name of this chunk / asset if known */ name?: string /** * Whether this chunk is a dynamic entry point * * This field is only present in JS chunks. */ isDynamicEntry?: boolean /** * The list of statically imported chunks by this chunk * * The values are the keys of the manifest. This field is only present in JS chunks. */ imports?: string[] /** * The list of dynamically imported chunks by this chunk * * The values are the keys of the manifest. This field is only present in JS chunks. */ dynamicImports?: string[] }清单中的每个条目代表以下内容之一
- 入口 chunk(Entry chunks):由
build.rollupOptions.input中指定的文件生成。这些 chunk 的isEntry: true,其键是项目根目录的相对源路径。 - 动态入口 chunk(Dynamic entry chunks):由动态导入生成。这些 chunk 的
isDynamicEntry: true,其键是项目根目录的相对源路径。 - 非入口 chunk(Non-entry chunks):其键是生成文件的基本名称,并带有
_前缀。 - 资源 chunk(Asset chunks):由导入的资源(如图片、字体)生成。其键是项目根目录的相对源路径。
- CSS 文件:当
build.cssCodeSplit为false时,会生成一个带有键style.css的单个 CSS 文件。当build.cssCodeSplit不为false时,键的生成方式类似于 JS chunk(即入口 chunk 不会带有_前缀,而非入口 chunk 则会带有_前缀)。
JS chunk(除资源或 CSS 以外的 chunk)将包含其静态和动态导入的信息(两者均为映射到清单中相应 chunk 的键)。如果 chunk 有对应的 CSS 和资源文件,它们也会被列出。
- 入口 chunk(Entry chunks):由
你可以使用此文件来渲染带有哈希文件名的链接或预加载指令。
以下是渲染正确链接的 HTML 模板示例。此处的语法仅供参考,请替换为你所使用的服务器模板语言。
importedChunks函数仅为演示说明,Vite 未提供该函数。html<!-- if production --> <!-- for cssFile of manifest[name].css --> <link rel="stylesheet" href="/{{ cssFile }}" /> <!-- for chunk of importedChunks(manifest, name) --> <!-- for cssFile of chunk.css --> <link rel="stylesheet" href="/{{ cssFile }}" /> <script type="module" src="/{{ manifest[name].file }}"></script> <!-- for chunk of importedChunks(manifest, name) --> <link rel="modulepreload" href="/{{ chunk.file }}" />具体来说,生成 HTML 的后端在给定清单文件和入口点时,应包含以下标签。注意,为了获得最佳性能,建议遵循此顺序
- 为入口 chunk 的
css列表中的每个文件(如果存在)添加一个<link rel="stylesheet">标签 - 递归遍历入口点
imports列表中的所有 chunk,并为每个导入 chunk 的css列表中的每个 CSS 文件(如果存在)添加一个<link rel="stylesheet">标签。 - 为入口 chunk 的
file键添加一个标签。对于 JavaScript,这可以是<script type="module">;对于 CSS,则为<link rel="stylesheet">。 - 可选地,为每个导入的 JavaScript chunk 的
file添加<link rel="modulepreload">标签,同样需要从入口 chunk 开始递归遍历导入。
根据上述示例清单,对于入口点
views/foo.js,在生产环境中应包含以下标签html<link rel="stylesheet" href="assets/foo-5UjPuW-k.css" /> <link rel="stylesheet" href="assets/shared-ChJ_j-JJ.css" /> <script type="module" src="assets/foo-BRBmoGS9.js"></script> <!-- optional --> <link rel="modulepreload" href="assets/shared-B7PI925R.js" />而对于入口点
views/bar.js,则应包含以下内容html<link rel="stylesheet" href="assets/shared-ChJ_j-JJ.css" /> <script type="module" src="assets/bar-gkvgaI9m.js"></script> <!-- optional --> <link rel="modulepreload" href="assets/shared-B7PI925R.js" />importedChunks的伪实现TypeScript 中
importedChunks的伪实现示例(你需要根据自己的编程语言和模板语言进行调整)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]) }- 为入口 chunk 的
