双部署目标的 base 路径陷阱 · 根路径拼出 //slug 全站内链失效
入档:2026-06-25 来源:蛛网之上(Astro 静态站)同时部署 GitHub Pages 子路径 + 香港服务器根路径,自定义域名站全站「关联文档」链接点击跳错 状态:已定位修复并上线验证(线上双斜杠内链 0 个)
一句话总结
一套代码部署到两个 base 不同的目标(Pages 子路径 /above-the-web vs 自定义域名根路径 /)时,凡是手动拼接 `${BASE}/${slug}` 的地方,在 BASE='/' 下会拼出 //slug——浏览器把 // 开头当成协议相对 URL(等价 https://slug),于是整站内链全跳错。而它只在根路径那个镜像现形,子路径镜像完全正常,极易漏测。
根因(决策链)
- base 改成环境变量驱动:
BASE = process.env.BASE_PATH || '/above-the-web',一套代码兼容两种部署。 - wikilink 解析里手写:
return slug ?${BASE}/${encodeURI(slug)}/: null。 - 子路径:
'/above-the-web' + '/' + slug=/above-the-web/slug/✅。 - 根路径:
'/' + '/' + slug=//slug/❌ → 协议相对 URL → 浏览器当域名解析 → 点击跳到https://slug/。
判据 / 排查法
- 现象:鼠标悬停链接,状态栏显示
//开头而非/开头;或点击跳到一个莫名其妙的「域名」。 - 快速验证:
curl 线上页面 | grep 'href="//',过滤掉//www///cdn等真实协议相对资源,剩下的就是 bug。 - 构建后自检:
grep -roh 'href="//[^h]' dist/计数,应为 0。
修法
base 拼接归一化:先去掉 base 尾部斜杠再统一拼一个:
const BASE_PREFIX = BASE.endsWith('/') ? BASE.slice(0, -1) : BASE;
// 用 `${BASE_PREFIX}/${slug}/`,两种 base 都只得到单斜杠
注:框架自带的
import.meta.env.BASE_URL已被归一化为总是以/结尾,所以用它的地方(${BASE_URL}slug)不会出 bug;只有自己读process.env.BASE_PATH手拼的地方才会踩。优先用框架归一化过的变量。
补充:markdown 正文里的站内互链走相对路径(2026-07-24 回验)
上面的归一化前提是能拿到 BASE_URL 变量。但内容集合的 markdown 正文(经 <Content/> 渲染)是静态文本,注入不了 import.meta.env.BASE_URL——于是正文里写站内链接有个双 base 死角:
- 写死绝对路径
[规范](/tasks/spec/)→ 在 Pages 子路径镜像下缺了/above-the-web前缀,404; - 又没法在 md 里拼
${BASE_URL}。
解法:用相对路径,让浏览器按当前 URL 解析。 任务书详情页部署在 {base}/tasks/{slug}/,正文里写 [教程类任务规范](../spec/),浏览器以当前页 URL 为基准解析 ../spec/ → {base}/tasks/spec/——当前 URL 本就带着正确的 base,所以两种部署下都自动对,md 里一个字都不用改。
前提与判据:
- 依赖 URL 带尾斜杠:Astro 静态构建产出
/tasks/{slug}/index.html,页面 URL 带尾斜杠,../才退到/tasks/。若站点配了去尾斜杠,../spec/会多退一层,需改成spec/。 - 一句话规律:能用框架变量拼就归一化拼;拼不到变量的静态内容层(md/json 正文),站内链一律走相对路径,别写死绝对路径。
- 验证同上:两个镜像都点一遍,别只看根路径镜像。
教训(可复用)
- 多 base 部署 = 必须两个镜像都测链接。链接类 bug 会「只在一个镜像现形」,在另一个上验证会得出「没问题」的错误结论。—— 又一例「所见非真相」:看子路径镜像 ≠ 看根路径镜像。
- 本地复现根路径构建有坑:git-bash(MSYS)会把
BASE_PATH=/的值路径转换成C:/Program Files/Git/,导致构建产物路径错乱。→ 用 PowerShell 设环境变量,或MSYS_NO_PATHCONV=1。 - 凡「环境变量可能为
/」的路径拼接,默认写归一化,不要裸${A}/${B}。
关联文档
- 知识库网站免备案上线_香港轻量服务器方案 —— 本 bug 所在的双部署架构(Pages 构建 + rsync 到香港服务器)就是这篇搭起来的
- Claude预览环境不派发滚动事件_滚动类功能无法行为验证_v1 —— 同期同站踩的另一个「验证陷阱」
- 站内新版块五件套模式_三次复用与起刊两坑_v1 —— 新版块(任务书)零改动复用本档踩通的双目标管线,归一化写法的收益实证
- 任务书制作与学员协作需求收口方法论_v1 —— 「markdown 正文相对链接」补丁的来源场景:测评任务书正文指向规范页
../spec/在双 base 下都对 - 文档密集页两栏排版与对外截图脱敏_v1 —— 同站同期,该规范页(
/tasks/spec/)的版式与对外资产处理复盘 - reduced-motion本机陷阱_动效降级纯淡入而非跳过_v1 —— 同站同族「验证方式选错致误判」:那篇是 grep 线上 HTML 验 CSS 关键字永远 0 命中(样式被抽进外部 CSS 文件)