SPA必须只用一个index.html作唯一入口,所有路由由JS动态渲染;多HTML文件属MPA,Vite多入口适用于SEO敏感静态页与SPA混合部署场景。

SPA 必须只用一个 index.html 作入口
单页应用(SPA)的路由不是靠服务端跳转,而是靠前端 JS 控制 history.pushState 和监听 popstate 实现的。这意味着无论用户访问 /、/user 还是 /settings,服务器都必须返回同一个 index.html —— 否则直接刷新页面就会 404。
常见错误是把不同页面写成多个 HTML 文件(比如 about.html、contact.html),再用超链接跳转。这本质是多页应用(MPA),不是 SPA,也完全无法享受路由懒加载、状态保持、无缝过渡等特性。
如果你用 Vite 或 Webpack 构建,index.html 必须是唯一 HTML 入口;所有其他“页面”都应由 JS 动态渲染,而不是独立 HTML 文件。
Vite 多入口 ≠ SPA,但可用于 MPA 场景
当项目实际需要多个独立 HTML 页面(如营销页 landing.html、文档页 docs.html、后台页 admin.html),Vite 可通过 build.rollupOptions.input 配置多个入口:
立即学习“前端免费学习笔记(深入)”;
- 指定路径数组:
input: ['src/index.html', 'src/landing.html'] - 或对象形式:
input: { main: 'src/index.html', landing: 'src/landing.html' } - 注意:每个入口会生成独立 JS 文件(如
main.js、landing.js),且模块作用域隔离 - 构建后
dist/下会出现index.html和landing.html,但它们彼此不共享路由状态
这种配置适合 SEO 敏感型静态页 + 后台 SPA 混合部署,但不能当作“伪 SPA”来用——landing.html 刷新后不会加载 index.html 的 JS,也不会响应 /user 路由。
服务端 fallback 配置决定 SPA 是否可用
开发时 Vite Dev Server 默认已启用 fallback(即所有未匹配路由返回 index.html),但上线后必须手动配 Nginx / Apache / Cloudflare Pages 等:
- Nginx 示例:
location / { try_files $uri $uri/ /index.html; } - Cloudflare Pages:在
_redirects文件中加一行:/* /index.html 200 - 注意:不能只配
/或/app/*,必须覆盖所有前端路由路径(如/user/123、/post?tag=vue) - 若漏配,用户从二级路径直接访问就会看到 404,而非你的 SPA 应用
HTML 入口文件里容易被忽略的细节
index.html 看似简单,但几个 meta 标签和 script 加载方式直接影响首屏性能、SEO 和 PWA 行为:
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">缺失会导致移动端布局错乱 -
<link rel="manifest" href="/manifest.json">和<meta name="theme-color">是 PWA 添加到主屏幕的前提 - script 标签推荐用
<script type="module" src="/src/main.ts"></script>,避免阻塞渲染;不用defer或async混搭模块加载 - 禁止缓存调试时有用,但上线后别留
<meta http-equiv="Cache-Control" content="no-cache">,它会破坏 CDN 和浏览器缓存机制
真正麻烦的不是写对这些标签,而是每次改完都要验证:打开 Chrome DevTools → Application → Manifest 是否加载成功,Lighthouse 是否报 viewport 缺失,以及在手机上长按添加到桌面是否生效。



















