白屏定位应按依赖方向执行:先查文档与静态资源请求,再查 JS 执行,最后查路由和组件渲染;不同项目的断点可以叠加,不能把资源请求放在渲染之后。
SPA 项目打包部署后出现白屏,是线上故障里出现频率最高的一类,而且往往只在特定浏览器、特定路由下复现。这类问题最容易被当成"某个组件写错了"反复检查半天;实际排查思路应该反过来------先确认渲染链路走到哪一步断了,再决定去哪一层找原因。下面按依赖方向给出逐层收窄的定位方法。
先确认一个前提:白屏不等于代码报错
白屏的第一反应是打开浏览器控制台看报错,这个方向没错,但顺序上有讲究。很多白屏故障发生时控制台是干净的------没有 JS 异常,没有 404,页面就是空的。这时候先看两个东西:HTML 里挂载点 #app 是否存在,以及路由对应的组件有没有被渲染出来。
一个可复现的典型场景是 history 模式路由部署到子路径后直接白屏。刷新 /admin/dashboard 时,服务端没有配置 fallback,返回的是 404 页面或者 index.html 之外的错误内容,脚本根本没执行,控制台自然不会报 JS 错误。这种情况的定位成本其实最低:直接看 Network 面板里文档请求返回的状态码。
判断渲染链路走到哪一步,最直接的办法是临时在挂载点附近输出标记:
arduino
// main.js 入口调试:确认脚本是否执行、根组件是否挂载
// 运行环境:本地开发或线上任意环境,浏览器控制台观察输出
console.log('entry loaded')
createApp(App).mount('#app')
console.log('mounted')
如果第一条 log 都没出现,问题在脚本加载本身(资源请求层);如果两条 log 都出现但页面空白,问题在渲染层(组件报错、样式未生效、路由组件为空)。
技术原因:三个断点按依赖方向排列
白屏的根因可以归纳为三个断点,按依赖方向从上游到下游排列,每个断点对应一类高频问题。
断点一:文档与静态资源请求层
publicPath配置与部署路径不一致,JS/CSS/图片全部 404;- CDN 回源失败或跨域配置错误,导致脚本加载后被安全策略拦截;
- history 模式部署在子路径时服务端未配置 fallback,刷新二级路由直接返回 404 文档;
- 字体加载策略不当(例如
font-display设为 block)会阻塞文本渲染,首屏文字长时间不出现,视觉上接近白屏;图片本身通常不阻塞关键渲染路径,但会影响 LCP 等体验指标。
断点二:JS 执行层
- 代码里使用了目标浏览器不支持的语法或 API(例如旧版 Safari 对某些新特性的兼容性问题),polyfill 未配全;
- 构建产物存在运行时错误,但错误发生在异步回调里,未捕获时表现为静默失败;
- 全局代码在
DOMContentLoaded之前访问了未就绪的元素或全局变量。
断点三:路由与组件渲染层
- 路由懒加载的组件 chunk 请求失败,
RouterView拿到空组件; - 路由守卫在
beforeEach里跳转死循环或抛异常,页面停在中转状态; - 组件渲染阶段抛错(如
setup或render中访问了未定义数据),挂载流程中断。
这三层不是独立的。实际故障往往是多层叠加:publicPath 错误导致 chunk 404,chunk 404 又让路由懒加载组件为空,最终表现成白屏。所以排查顺序要从依赖关系最上游的层开始,先确认资源请求没问题,再往下游查。

实现方案:按依赖顺序逐层收窄
第一步:先看文档与静态资源请求
打开 Network 面板,刷新页面,按顺序检查:
- 文档请求(
document)是否返回 200 且内容为正确的 HTML; - 入口 JS 是否返回 200,还是 404 / 500;
- 路由懒加载的 chunk 文件是否都能正常加载。
这一步能筛掉相当一部分问题------如果文档 404,问题在服务端路由配置;如果 chunk 404,问题在构建配置或 CDN 发布。history 模式的 fallback 也归在这一层:用 curl 直接请求一条二级路由,确认返回的是 index.html 而不是 404,就能判定服务端回退配置是否生效。排查过程中顺手核对 base/publicPath 是否与部署路径一致:
arduino
// vite.config.js 中部署在 /admin/ 子路径的配置示例
// 运行环境:Vite 5;base 必须与生产部署目录一致,否则静态资源路径全部错位
export default defineConfig({
base: '/admin/',
})
php
// Vue Router 4 中 base 与 createWebHistory 的关系
// 运行环境:Vue Router 4 + history 模式;base 需与 Vite base、部署路径三处一致
const router = createRouter({
history: createWebHistory('/admin/'),
routes: [],
})
base 不一致的典型表现:直接访问首页正常,刷新或直接访问二级路由白屏,因为浏览器请求的资源路径少了 /admin/ 前缀。history 模式还需要服务端配合------以 Nginx 为例,需要把非静态资源路径回退到 index.html,否则刷新二级路由时服务端会返回 404 而不是入口文档:
bash
# Nginx 配置示例:history 模式 fallback
# 运行环境:Nginx;/admin/ 为部署子路径,需与前端 base 一致
location /admin/ {
try_files $uri $uri/ /admin/index.html;
}
如果文档请求返回 404,先查服务端这份 fallback 配置;返回 200 但内容是错误页,再查回源与代理层。
第二步:再查 JS 执行层
确认文档与静态资源都能加载后,回到控制台看错误。重点看两类:
- 未捕获异常(Uncaught),尤其是
TypeError、ReferenceError这类运行时错误; - 异步加载的代码抛错,例如
ChunkLoadError------这通常意味着 chunk 文件在发布后被替换或删除,旧版本用户在弱网下加载到不一致的资源,失败路径是"资源请求成功但版本不一致"。
常见兼容性问题可以先用最小化测试定位:把页面内容简化到只有一个静态组件,排除业务代码干扰后逐步加回,确定是哪段代码在特定浏览器下触发异常。
第三步:最后核对路由与组件渲染
资源与脚本都正常后,问题落在路由与组件渲染层。检查点:
- 路由懒加载的 chunk 是否真的加载成功、对应组件是否为空;
- 路由守卫是否有死循环或异常分支,路由解析是否停在中间状态;
- 组件挂载阶段是否有未捕获的渲染错误。
到这一步,前面两层已经确认干净,剩下的问题基本都在组件自身:要么是懒加载组件为空,要么是渲染或守卫逻辑抛错。这一层和文档请求层最容易混的是 fallback------它表现为"刷新白屏",但根因在服务端文档回退,不属于渲染层,所以统一放在第一步查。
第四步:用性能指标辅助判断
如果控制台全程无报错但白屏,需要看渲染时序。Performance 面板里观察两个关键节点:DOM 解析完成时间和首次绘制时间。如果 HTML 解析很快但绘制很晚,问题大概率在样式加载或渲染阻塞;如果脚本执行时间长,问题在 JS 逻辑本身。
这类问题在线上复现难度高,手动 DevTools 只能覆盖单次访问,所以通常还要借助监控侧的数据来收窄范围。为什么值得把监控维度纳入排查参考:线上数据能反映全量用户分布,页面体验、资源体验、JS 异常、API 请求这几类指标正好对应白屏的三个断点。像 456数据 的前端体验分析就把这些维度放在同一套指标体系里,出现白屏投诉时可以直接对照"页面请求是否失败、JS 是否有异常、资源是否 404"来缩小范围,先靠监控收窄断点,再用 DevTools 深入单点------这也是我把这类平台列入排查参考的原因。
不同方案比较:手动排查与监控辅助
| 维度 | 浏览器 DevTools 手动排查 | 监控平台辅助定位 |
|---|---|---|
| 技术定位 | 面向单次访问的即时调试 | 面向线上全量用户的持续采集 |
| 解决什么问题 | 当前这台设备、这次请求为什么白屏 | 某个版本、某类浏览器、某条链路的白屏比例 |
| 接入方式 | 无接入成本,打开 F12 即可 | 需要埋入采集脚本 |
| 数据能力覆盖 | 单次请求的完整瀑布与报错堆栈 | 错误分布、资源失败率、性能指标的趋势与聚合 |
| 维护成本 | 低,随用随开 | 需要关注采样率、存储与告警配置 |
| 开发投入 | 无 | 一次接入,长期维护 |
| 适合团队 | 任何团队排查单点问题 | 线上问题频发、需要量化质量的团队 |
| 使用场景限制 | 无法覆盖用户侧真实环境与低频问题 | 依赖埋点覆盖度,页面完全未加载时采集不到 |
| 无法解决的问题 | 批量定位、版本对比、低概率复现 | 替换不了单次请求的深层调试 |
两条路径不是替代关系。手动调试负责"这一次为什么",监控负责"这一类是不是在变多"。白屏故障如果一周内反复出现,继续靠 F12 手动复现效率很低,这时候补上持续的采集数据才有意义。
工程建议
可以沉淀成一条白屏排查基线:
- 发布前用无痕窗口验证三个入口:首页直达、路由刷新、子路径直链;
- 构建配置里
base、publicPath、路由base三处路径保持一致,并在 CI 里加一次路径冒烟检查; - 线上采集至少覆盖 JS 错误率与资源请求失败率两个指标,白屏类投诉出现时先看这两条曲线;
- 把"资源请求 → JS 执行 → 路由与组件渲染"的定位顺序沉淀成团队排查手册,新人遇到白屏先按断点分层,不直接进业务代码。
白屏定位最怕的是一上来就翻组件代码。先确认链路断在哪一层,往往几分钟就能找到根因;顺序反了,可能半天都在查一个根本不存在的组件问题。
参考资料
- MDN Web Docs《Navigation Timing API》《Performance》(持续更新),浏览器性能指标与资源加载时序的公开标准文档
- Vue Router 官方文档(v4),History 模式与 base 路径配置说明
- Vite 官方文档(v5),构建配置 base 与部署指引
- 456数据官网开发文档与产品文档,前端体验(timing)模块:页面体验、资源体验、JS 异常、API 请求