把一个现成的前端应用挂到站点的子路径下,看起来是纯粹的搬运工作:复制目录,改一行链接,部署。
实际结果是整站 404。
为什么
构建工具默认假设你的应用跑在域名根路径。于是产物里到处是绝对路径:
<script src="/assets/index-xxx.js"><link href="/assets/index-xxx.css">- CSS 里的
url(/icons/...) - Service Worker 注册的
"/sw.js" - manifest 里的
"start_url": "/"和"scope": "/"
在根路径下这些全对。挪到 /tools/some-app/ 之后,浏览器仍然去根目录找 /assets/...——那里什么都没有。
首页 HTML 本身能 200,因为它确实在那个位置。所以「首页打得开」完全不能证明搬运成功,只能证明你搬对了一个文件。
正确的顺序
不是「部署完再看哪里坏了」,是搬之前就查。一条命令的事:
grep -rno 'src="/\|href="/\|url(/' dist/ | head -30
cat dist/manifest.webmanifest
grep -o '"/sw\.js"' dist/assets/*.js
五个高频位置,按坑的深浅排序:
- HTML 里的
src/href—— 最显眼,也最容易被误以为是全部 - CSS 里的
url()—— 字体和背景图,坏了页面还能用,只是丑 - Service Worker 注册路径 —— 注册失败通常静默,控制台不翻不会发现
- manifest 的
start_url/scope—— PWA 装到桌面后打开一片空白,离部署已经过去很久了 - 代码里手写的 fetch 路径 —— 构建工具的 base 配置管不到这些
更根本的做法
真正的修法是回到源项目改构建配置(Vite 的 base、Next 的 basePath),重新构建。
但如果你手上只有 dist、没有源码,或者不想为一次挪窝重开构建环境,那就 sed 改相对路径。这是补丁,不是修复——记下来,下次构建时把 base 配对,否则每次更新都要重来一遍。
收敛成一句话
「首页能打开」不等于「搬运成功」。绝对路径是构建产物对自己位置的硬编码假设,换了位置这个假设就失效了。
搬之前 grep 一次,比部署后一个个 404 试快得多。