React 项目打包后页面空白,通常不是“打包失败”,而是浏览器拿到的 HTML 已经加载,但脚本没执行成功、资源路径不对,或者首屏渲染时抛了异常。先别急着改业务代码,把“空白”拆成可以观察的现象:打开控制台看有没有红色报错,切到 Network 看 index.html 引用的 JS/CSS 是否 404,再检查页面根节点 <div id="root"> 里是不是完全空。这三步基本能把问题从“React 渲染”收敛到“资源加载”或“运行时异常”两类,后面的处理路径才不至于乱试。
打包后空白建议按“先看控制台报错,再看静态资源请求,最后看路由和渲染异常”的顺序排查。适用场景是本地开发正常、构建产物部署后首屏空白;操作动作包括核对 index.html 的资源前缀、确认路由模式与部署路径一致、在本地用静态服务器复现构建产物。验证方式是以构建目录为根启动静态服务,观察浏览器是否出现完整首屏。边界在于:本地静态服务器通过不代表 CDN 或反向代理配置正确,缓存和路径重写仍需在目标环境单独确认。
先确认当前场景和目标
空白页有几个前提需要先确认,不同前提对应的排查方向差别很大。第一,npm run dev 或本地开发服务器是否正常,如果开发环境也空白,那问题不在构建产物,应该先查入口文件和依赖安装。第二,空白是“整页纯白”还是“有导航没内容”,前者多半是脚本未执行,后者更可能是路由匹配不到或数据请求失败。第三,直接访问 / 空白,还是刷新 /user/1 这类子路径才空白,后者通常是服务端没有做 history 回退。
还要确认部署形态:构建产物放在域名根目录,还是放在 /app/ 这样的子路径下;静态服务器是 Nginx、对象存储还是其他托管平台;是否经过 CDN 缓存。这几项决定了资源前缀和路由回退该怎么写,先问清楚再动手,比反复重新打包更省时间。
按这个顺序处理
第一步看控制台。打开浏览器开发者工具的 Console,重点关注 Uncaught SyntaxError、Failed to load module script、ChunkLoadError 和不熟悉的 TypeError。语法错误一般意味着构建产物的目标浏览器版本不匹配;ChunkLoadError 往往是异步分包路径或缓存问题。
第二步看 Network 中 JS/CSS 的请求地址。如果请求成了 https://example.com/static/js/main.xxxx.js 而实际部署在 /app/ 下,就是资源前缀没配对。Webpack 项目可以在 package.json 里配置 homepage,或者在构建配置里设置 publicPath;Vite 项目用 base。示例片段按自己的部署路径替换:

// package.json(Create React App / 部分 Webpack 脚手架)
{
"homepage": "/app/"
}
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
base: '/app/'
})
第三步查路由模式。使用 BrowserRouter 时,服务器必须把所有未知路径回退到 index.html,否则刷新子路径会得到服务器 404,页面自然空白。Nginx 可以参考下面的写法,路径和文件名按实际构建目录调整:
location / {
root /var/www/my-app;
index index.html;
try_files $uri $uri/ /index.html;
}
如果暂时无法改服务器配置,可以先换用 HashRouter 让路由信息落在 # 后面,作为过渡手段;但 HashRouter 会改变 URL 形式,涉及分享链接、统计埋点和 SEO 时要评估后再换回。
第四步查运行时异常。在入口处临时加一层错误捕获,或者给根组件包一个 ErrorBoundary,把错误打到控制台,能快速区分是“某个组件初始化就抛错”还是“压根没渲染”。同时确认构建时注入的环境变量是否存在,例如 process.env.REACT_APP_API_URL 或 import.meta.env.VITE_API_URL,值缺失导致初始化逻辑直接 throw 的情况并不少见。

改完后怎么验证
不要改完直接传服务器。先在本地以构建目录为根启动静态服务复现,例如执行 npx serve build 或 npx serve dist,然后访问带子路径的地址,逐项确认:Network 里所有 JS/CSS 都返回 200 且路径前缀正确;Console 没有新的红色报错;页面根节点里有渲染出的 DOM 结构;直接刷新一个子路径仍能正常显示。
本地通过后再到部署环境验证,重点看两点:一是浏览器无痕窗口访问,排除旧缓存干扰;二是检查响应头里的缓存策略,构建产物文件名带哈希的可以长缓存,index.html 建议不缓存或短缓存,否则用户可能拿到旧 HTML 引用已经不存在的 JS。若线上仍空白,用 view-source 看返回的 HTML 是不是最新构建的那份,这一步能直接判断问题在构建环节还是分发环节。
容易忽略的边界
资源前缀只解决静态文件路径,不会自动修正接口地址。如果接口基地址写死成开发环境地址,页面可能有 DOM 但请求全失败,看起来也像“空白”。这类问题要单独检查请求 URL,而不是继续改 publicPath。
另外,publicPath 或 base 改成相对路径 ./ 在单页应用里容易和子路由冲突,刷新深层路径时相对前缀会解析错位置,一般不建议在带前端路由的项目里用。CDN 与反向代理的错误页、跨域限制、托管平台的默认回退规则,都可能让本地正常、线上空白;如果短时间无法定位,可以先回退到上一个可用的构建产物,再在隔离环境复现。构建产物本身是否可用,也要结合目标浏览器的支持范围确认,低版本浏览器遇到较新的语法会直接报错,而不是降级显示。