后端集成
后端集成
:::tip 提示
如果你想使用传统后端(例如 Rails、Laravel)来提供 HTML 服务,但使用 Vite 来提供静态资源,请查看 Awesome Vite 中列出的现有集成方案。
如果你需要自定义集成,可以按照本指南中的步骤手动配置。
:::
-
在你的 Vite 配置中,配置入口并启用构建 manifest:
js twoslash [vite.config.js]import { defineConfig } from 'vite' // ---cut--- export default defineConfig({ // 覆盖默认的 .html 入口 input: '/path/to/main.js', server: { cors: { // 你通过浏览器访问的来源 origin: 'http://my-backend.example.com', }, }, build: { // 在 outDir 中生成 .vite/manifest.json manifest: true, }, })如果你还没有禁用 模块预加载 polyfill,你还需要在你的入口中导入该 polyfill:
js// 在你的应用入口开头添加 import 'vite/modulepreload-polyfill' -
在开发环境中,将以下内容注入到你的服务器 HTML 模板中(将
http://localhost:5173替换为 Vite 运行时的本地 URL):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替换为 Vite 运行时的本地 URL):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文件。以下是一个 manifest 文件的示例:json [.vite/manifest.json] style:max-height:400px{ "_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"] } }Manifest 将源文件映射到它们的构建输出和依赖关系:
graph TD foo["views/foo.js<br/>(入口)"] -->|imports| shared["_shared-B7PI925R.js<br/>(公共代码块)"] bar["views/bar.js<br/>(入口)"] -->|imports| shared bar -->|dynamicImports| baz["baz.js<br/>(动态导入)"] foo -->|css| foocss["foo.css<br/>(资源)"] shared -->|css| sharedcss["shared.css<br/>(资源)"]Manifest 具有
Record<name, chunk>结构,其中每个 chunk 遵循ManifestChunk接口:ts style:max-height:400pxinterface ManifestChunk { /** * 该 chunk / 资源的输入文件名(如果已知) */ src?: string /** * 该 chunk / 资源的输出文件名 */ file: string /** * 该 chunk 导入的 CSS 文件列表 */ css?: string[] /** * 该 chunk 导入的资源文件列表(不包括 CSS 文件) */ assets?: string[] /** * 该 chunk 或资源是否为入口点 */ isEntry?: boolean /** * 该 chunk / 资源的名称(如果已知) */ name?: string /** * 该 chunk 是否为动态入口点 * * 此字段仅存在于 JS chunk 中。 */ isDynamicEntry?: boolean /** * 该 chunk 静态导入的 chunk 列表 * * 这些值是 manifest 的键。此字段仅存在于 JS chunk 中。 */ imports?: string[] /** * 该 chunk 动态导入的 chunk 列表 * * 这些值是 manifest 的键。此字段仅存在于 JS chunk 中。 */ dynamicImports?: string[] }Manifest 中的每个条目代表以下之一:
- 入口 chunk:由
build.rolldownOptions.input中指定的文件生成。这些 chunk 具有isEntry: true,其键是相对于项目根目录的 src 路径。 - 动态入口 chunk:由动态导入生成。这些 chunk 具有
isDynamicEntry: true,其键是相对于项目根目录的 src 路径。 - 非入口 chunk:其键是生成文件的基础名称,并以
_作为前缀。 - 资源 chunk:由导入的资源(如图片、字体)生成。其键是相对于项目根目录的 src 路径。
- CSS 文件:当
build.cssCodeSplit为false时,会生成一个键为style.css的单独 CSS 文件。当build.cssCodeSplit不为false时,键的生成方式与 JS chunk 类似(即入口 chunk 不会有_前缀,非入口 chunk 会有_前缀)。
JS chunk(资源或 CSS 之外的 chunk)将包含其静态和动态导入的信息(两者都是映射到 manifest 中相应 chunk 的键)。Chunk 也会列出它们对应的 CSS 和资源文件(如果有的话)。
- 入口 chunk:由
-
你可以使用此文件来渲染带有哈希文件名的链接或预加载指令。
以下是一个渲染正确链接的 HTML 模板示例。这里的语法仅用于说明,请替换为你的服务器模板语言。
importedChunks函数仅用于演示,并非由 Vite 提供。html<!-- 如果是生产环境 --> <!-- 对于 manifest[name].css 中的每个 cssFile --> <link rel="stylesheet" href="/{{ cssFile }}" /> <!-- 对于 importedChunks(manifest, name) 中的每个 chunk --> <!-- 对于 chunk.css 中的每个 cssFile --> <link rel="stylesheet" href="/{{ cssFile }}" /> <script type="module" src="/{{ manifest[name].file }}"></script> <!-- 对于 importedChunks(manifest, name) 中的每个 chunk --> <link rel="modulepreload" href="/{{ chunk.file }}" />具体来说,生成 HTML 的后端在给定 manifest 文件和入口点的情况下,应包含以下标签。请注意,建议按照以下顺序以获得最佳性能:
- 为入口点 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 开始递归地遍历 imports。
根据上述 manifest 示例,对于入口点
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> <!-- 可选 --> <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> <!-- 可选 --> <link rel="modulepreload" href="assets/shared-B7PI925R.js" />::: details
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]) }info Chunk 导入映射支持(实验性)
如果你正在使用实验性的
build.chunkImportMap选项,你还需要将导入映射注入到 HTML 中。导入映射会输出到输出目录中的
importmap.json文件。请确保在任何<script type="module">标签或<link rel="modulepreload">标签之前注入<script type="importmap">标签。
::: - 为入口点 chunk 的
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
