必须结尾带斜杠,否则Firefox/Opera会截断路径导致404;它仅影响HTML解析阶段的相对资源路径,与前端路由、fetch、import等运行时路径无关,且须与Vue Router/React Router的base配置严格一致,避免资源加载与导航割裂。

<base> 标签在复杂网站中不是“锦上添花”,而是部署阶段的路径控制开关——配错就批量 404,配对了才能让资源加载、路由跳转、缓存策略三者不打架。
为什么 <base href="/subapp/"> 必须结尾带斜杠
Firefox 和 Opera 会把 href="https://cdn.example.com/v2" 这类缺斜杠的值截断后拼接,比如 css/app.css 变成 https://cdn.example.com/v2css/app.css;Chrome 虽不截断,但行为不一致本身就会埋雷。根相对写法同理:/subapp → 拼出 /subappjs/app.js。
必须写成:
<base href="https://cdn.example.com/v2/"><base href="/subapp/">
协议相对写法 //cdn.example.com/v2/ 可用,但旧版 Android WebView 支持弱,线上环境慎用。
立即学习“前端免费学习笔记(深入)”;
<base> 和 Vue Router / React Router v6+ 的 base 配置必须双写
HTML 的 <base href="/subapp/"> 只管 <script src="chunk.js"></script> 这类静态资源加载;而 router.push('/home') 是 JS 运行时行为,完全不看 <base>,只认框架自己的 base 配置。
漏掉任一,后果明确:
- 只配 HTML
<base>:JS chunk 能加载,但点击导航跳到/home(根路径),不是/subapp/home - 只配 Vue Router
base: '/subapp/':路由能跳转,但chunk.js请求 404(仍按当前页面 URL 拼)
两者是平行机制,没有自动同步,必须人工保持一致。
Webpack/Vite 构建时 publicPath 或 build.base 和 <base> 别重复写
Vite 设置 build.base: '/subapp/' 后,它会在生成的 HTML 中自动注入 <base href="/subapp/">。你再手动加一条,会导致资源路径被拼两次:/subapp//subapp/js/app.js。
Webpack 同理:output.publicPath: '/subapp/' 已控制所有打包后资源的前缀,HTML 中再写 <base href="/subapp/"> 就是冗余,且容易因构建配置和手写 HTML 不同步引发问题。
建议做法:
- Vite:关掉
build.rollupOptions.output.manualChunks外的任何 HTML 手动干预,信任构建输出 - Webpack:用
html-webpack-plugin的templateParameters注入<base>,而非硬编码在模板里
哪些地方写了 <base> 也完全没用
<base> 只在 HTML 解析阶段起效,对运行时路径构造毫无影响。以下全是常见幻觉:
-
fetch('./api/user')—— 无视<base>,按当前 JS 文件位置或window.location.origin解析 -
import('./utils.js')—— ESM 路径解析走模块规范,<base>不参与 -
document.createElement('img').src = 'logo.png'—— 动态创建的元素,路径按当前文档 URL 解析 -
element.style.backgroundImage = "url(bg.jpg)"—— CSS 属性值走 CSS 规则,相对路径基于 CSS 文件所在位置
最易被忽略的一点:document.baseURI 确实返回 <base href> 的值,但它只是个只读快照,不能靠它“修复”动态路径——你得自己用 new URL('data.json', document.baseURI) 显式构造。



















