React history.push路由跳转报chunk.js Unexpected token '<'错误
SyntaxError: Unexpected token '<' 这类JS解析错误,核心原因非常明确:浏览器请求目标JS chunk时,收到的响应内容不是合法的JS代码,而是以<开头的HTML文档(通常是单页应用入口index.html、登录页、网关错误页),JS引擎解析第一个字符<时就会直接抛出语法错误。
结合你描述的「路由跳转时触发、鉴权流程正常、目标页面useEffect未执行、禁页面缓存/关service worker无效」的特征,按优先级从高到低按以下方案排查修复:
排查修复步骤
第一步先定位错误响应来源
打开浏览器开发者工具切到Network面板,筛选JS类型,复现跳转操作找到加载失败的26.3ac4f9fa.chunk.js请求,直接查看Response标签页的内容:- 如果返回内容是你站点的
index.html:- 优先检查构建配置的
publicPath是否正确。如果你的项目不是部署在域名根目录,而是部署在子路径下(例如https://your-domain.com/admin/),必须把构建工具(webpack/vite)的publicPath配置为对应子路径/admin/,否则路由跳转后浏览器会去域名根路径请求chunk资源,路径不匹配找不到文件,就会被服务器的单页应用重定向规则返回index.html。 - 修正服务器的路由匹配规则。必须把
/static/开头的静态资源请求匹配优先级调到最高,静态资源不存在时直接返回404,不要 fallback 到index.html;只有非静态资源的页面路由请求,才需要重定向到index.html交给前端路由处理。最常见的错误配置是nginx里直接写全局的try_files $uri $uri/ /index.html;,一旦静态资源路径配置错误、或者发版后旧hash的chunk文件被清理,JS请求就会被错误返回HTML。
- 优先检查构建配置的
- 如果返回内容是登录页/网关鉴权失败的报错页:
说明静态资源请求被鉴权拦截了。你之前排查的是跳转前页面内的鉴权逻辑,但chunk是浏览器独立发起的静态资源请求,如果这类请求没有自动携带cookie/鉴权token,就会被网关/后端的鉴权规则重定向到登录页,自然拿不到JS内容。需要把静态资源路径加入鉴权白名单,或者调整鉴权逻辑让静态资源请求自动携带登录凭证。 - 如果返回内容是CDN/代理的错误页:
检查CDN回源规则是否配置正确,手动刷新CDN对应路径的缓存,同时确认静态资源响应头的Content-Type是application/javascript,避免CDN缓存错误的响应内容。
- 如果返回内容是你站点的
修复发版导致的旧chunk加载失败问题
这是React懒加载路由的高频场景:用户打开页面后长时间未操作,你发布了新版本,构建时生成了新hash的chunk文件,服务器上旧hash的chunk被清理,此时用户触发路由跳转,浏览器请求已经被删除的旧chunk就会触发错误。可以给懒加载加失败重试逻辑,捕获到chunk加载错误时自动刷新页面拉取最新的资源清单,不需要用户手动刷新:const lazyWithRetry = (componentImport) => React.lazy(async () => { const hasRefreshed = JSON.parse( sessionStorage.getItem('chunk-load-refreshed') || 'false' ); try { const component = await componentImport(); sessionStorage.setItem('chunk-load-refreshed', 'false'); return component; } catch (err) { if (!hasRefreshed && /ChunkLoadError/.test(err.message)) { sessionStorage.setItem('chunk-load-refreshed', 'true'); window.location.reload(); } throw err; } }); // 路由配置时替换原React.lazy即可 const TargetPage = lazyWithRetry(() => import('./pages/TargetPage'));修正缓存配置
你之前在index.html里加的meta标签只能控制HTML文档本身的缓存策略,对单独加载的JS chunk资源不生效。正确的缓存配置应该是:带hash指纹的chunk资源配置长缓存,入口index.html配置no-cache不缓存,从根源避免缓存错乱。
内容的提问来源于stack exchange,提问作者Carlos Soler

