Vite 默认不将 index.html 作为构建目标,仅将其作为入口模板,因此不会自动重写 script 路径;构建后 HTML 中的 script 仍指向开发路径(如 /src/main.js),而实际输出为带哈希的 assets/index-xxx.js,导致空白页或模块加载失败。

为什么直接用 vite build 不生成可运行的 HTML?
因为 Vite 默认把 index.html 当作入口模板,不是构建目标——它不会被编译成 JS,也不会自动注入打包后的资源路径。你看到的空白页、404 或 “Failed to load module” 错误,大概率是 HTML 中的 <script type="module"> 仍指向开发时的 /src/main.js,而构建后实际输出的是带哈希的 assets/index-xxx.js。
关键点:Vite 的构建流程不重写 HTML,只处理其中的模块脚本(通过插件)和内联脚本(需显式启用)。要让构建后的 HTML 正确加载资源,必须满足两个条件:
-
index.html必须放在项目根目录(Vite 默认入口 HTML 路径) - 所有脚本引用必须是相对路径或省略协议的路径(如
<script src="./main.js">),不能是<script src="/src/main.js"> - 确保没有手动修改
base配置却忘了同步更新 HTML 中的资源前缀
vite build 后 HTML 里 script 路径还是错的?检查 build.rollupOptions.output
Vite 底层用 Rollup 打包,但默认不暴露完整 Rollup 配置。如果你在 vite.config.ts 里改过 build.rollupOptions.output(比如加了 entryFileNames 或 assetFileNames),就可能破坏 Vite 内置的 HTML 插件行为——它依赖约定的 chunk 名称格式来定位并重写 script 标签。
实操建议:
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 除非真有分包需求,否则不要碰
rollupOptions.output;Vite 的默认值(assets/[name]-[hash].js)已适配 HTML 注入逻辑 - 若必须自定义,确保
entryFileNames匹配index入口(例如assets/index-[hash].js),否则vite-plugin-html(内置)找不到对应 chunk - 检查构建产物中
index.html是否已被重写:打开 dist/index.html,确认<script>标签的src值是assets/index-xxx.js而非原./main.js
想用自定义 HTML 模板(比如多页、带变量)?别绕开 vite-plugin-html
Vite 内置支持基于 EJS 的 HTML 模板(通过 vite-plugin-html),但很多人直接删掉 index.html、手写一个 src/template.html 然后指望 vite build 自动识别——这行不通。Vite 只认根目录的 index.html,其他文件默认当静态资源处理。
正确做法:
- 保留根目录
index.html,用 EJS 语法写变量,例如<title><%= VITE_APP_TITLE %></title> - 在
vite.config.ts中配置plugins: [html({ inject: { data: { VITE_APP_TITLE: 'My App' } } })] - 环境变量需以
VITE_开头才能被注入,且不能在 EJS 中直接读import.meta.env——那是运行时,EJS 是构建时执行 - 多页场景下,每个页面仍需独立的
index.html(如about.html),并配合rollupOptions.input显式声明,否则不会生成对应 HTML
本地双击打开 dist/index.html 报错:Failed to fetch?这是 CORS,不是构建问题
构建本身没问题,错在浏览器安全策略:双击打开文件时使用的是 file:// 协议,现代浏览器禁止其加载本地 JS 模块(type="module")。这不是 Vite 的锅,也不是代码写错了。
验证和解决方式:
- 用
npx serve -s dist或vite preview启动一个本地 HTTP 服务,再访问http://localhost:5000—— 这时一切正常 - 如果非要双击测试,可在 Chrome 启动时加参数:
chrome --allow-file-access-from-files(仅调试用,不推荐长期依赖) - 注意:某些插件(如
vite-plugin-pwa)生成的manifest.webmanifest也会因file://协议加载失败,同样需走 HTTP
真正容易被忽略的是:这个错误会掩盖真实的构建问题。务必先用 vite preview 确认功能是否正常,再排查部署路径或服务器配置。


















