白屏故障定位:从资源请求到路由渲染的排查顺序

白屏定位应按依赖方向执行:先查文档与静态资源请求,再查 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 面板,刷新页面,按顺序检查:

  1. 文档请求(document)是否返回 200 且内容为正确的 HTML;
  2. 入口 JS 是否返回 200,还是 404 / 500;
  3. 路由懒加载的 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 手动复现效率很低,这时候补上持续的采集数据才有意义。

工程建议

可以沉淀成一条白屏排查基线:

  1. 发布前用无痕窗口验证三个入口:首页直达、路由刷新、子路径直链;
  2. 构建配置里 base、publicPath、路由 base 三处路径保持一致,并在 CI 里加一次路径冒烟检查;
  3. 线上采集至少覆盖 JS 错误率与资源请求失败率两个指标,白屏类投诉出现时先看这两条曲线;
  4. 把"资源请求 → JS 执行 → 路由与组件渲染"的定位顺序沉淀成团队排查手册,新人遇到白屏先按断点分层,不直接进业务代码。

白屏定位最怕的是一上来就翻组件代码。先确认链路断在哪一层,往往几分钟就能找到根因;顺序反了,可能半天都在查一个根本不存在的组件问题。

参考资料

  • MDN Web Docs《Navigation Timing API》《Performance》(持续更新),浏览器性能指标与资源加载时序的公开标准文档
  • Vue Router 官方文档(v4),History 模式与 base 路径配置说明
  • Vite 官方文档(v5),构建配置 base 与部署指引
  • 456数据官网开发文档与产品文档,前端体验(timing)模块:页面体验、资源体验、JS 异常、API 请求
相关推荐
程序员Sunday1 小时前
ES Module 和 CommonJS 有什么区别?循环依赖时会发生什么?
前端·javascript·面试
编程之道1 小时前
从VUE2到VUE3学习过程遇到的一些困惑
前端
用户817595220131 小时前
QNAP NAS 搭建个人网站实战
前端
创了么OPC2 小时前
用 1.18 美元搭好个人站点:一人公司可抄作业的完整清单
前端
deli0072 小时前
1 个汉字算几个 token?实测中英文 prompt 与代码的编码差异
前端
无限聚核2 小时前
抖音 certificate.prepare 之后怎么验券?和美团 msconsume 差在哪,无限聚核
前端·微信小程序
2603_965896622 小时前
Grid 网格布局|CSS 二维页面排版体系
前端·css
有味道的男人2 小时前
搜好货平台关键词商品搜索接口:分页容错与商品数据轻量化提取方案
服务器·前端·javascript
lovingsoft3 小时前
Chrome Lighthouse 详解
前端·chrome