【前端疑难杂症】Vue 项目报错Uncaught SyntaxError: Unexpected token <
Uncaught SyntaxError: Unexpected token <
场景复现:
页面打开不操作,前端项目代码更新重新部署后,页面不刷新,操作页面(点击打开弹窗、切换菜单等),页面没有反应,控制台报错 Uncaught SyntaxError: Unexpected token <。这个问题偶现,只有在项目重新部署后会出现,页面刷新后就恢复正常
问题分析:
控制台报错可以看出,报错信息来自script,
报错信息很简单,51.chunk.866cbe17.js、163.chunk.866cbe17.js这两个js文件在Unexpected的地方出现了尖括号<。这两个js文件是webpack打包后的js文件,在本地调试是无法复现这个问题的。组件资源是动态加载的,在head标签里我们可以看到已经加载的很多js/css文件,在用户操作界面触发加载新组件时,该组件的js也会以script标签的形式动态添加到head标签里,如下图:
图1
图2
图1是页面刚打开时,head标签里的资源,图2是页面点击操作后加载了新的组件资源。
报错后刷新页面,重复原来的操作,发现js文件后面的hash码变了:
这就是问题所在,在前端项目未更新之前打开的页面,在前端项目更新后,hash码更新导致js请求路径改变,而页面依然以之前的路径请求js资源,必然会请求不到。如果资源请求不到一般会报404问题,但是服务器配置了404页面,对于请求不到的资源会返回一个404页面,在script标签里解析html文件,就会报错Unexpected token <。
解决思路:
问题的根源是服务器js文件更新了,页面还在请求以前的js文件。可以保留之前webpack打包的文件,但是时间久了文件体积会积累到很大,而且从产品角度更希望用户访问新的资源。所以最好的解决方式是在报错时给用户提示,用户点击确认后刷新页面。前端如何能catch到这种错误?
目前还没找到catch这种错误的方法,但是,可以模拟这种错误的出现。
js文件是以script标签的形式动态添加到head标签里的,可以给head绑定DOMNodeInserted这个事件在有子元素插入的时候触发,可以在回调里拿到插入的标签名以及标签的属性包括src。这样在所有js资源加载时我们都可以在回调事件里拿到资源路径,然后在创建一个请求去请求该资源,代码如下:
const head = document.getElementsByTagName('head')[0]
head.addEventListener('DOMNodeInserted', e => {
// 获取标签名
const type = e.target.tagName
// 获取资源路径
const url = e.target.src
if (type === 'SCRIPT' && url) {
// 创建请求,如果需要低版本浏览器兼容的,请注意
let xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.onload = () => {
const text = xhr.responseText
if (text.indexOf('<') === 0) {
this.$modal.info({
title: '检测到有新的版本发布,需要刷新页面以访问最新内容',
width: 350,
okText: '确定',
onOk() {
location.reload()
}
})
}
}
xhr.send()
}
})
对于报错的js文件,我们会在xhr.responseText获取到一个以尖括号开头的html,这时候我们就可以知道当前资源路径失效,就可以在此时做一些处理
总结:
操作页面时报错Unexpected token <,刷新后页面正常,这是因为页面请求的js文件资源找不到,服务器返回一个html,在script标签里解析这段html内容,就会报错Unexpected token <。js文件资源找不到是因为代码更新重新打包,导致js文件路径中的hash码改变造成的。
PS:
如果是一打开页面就报错Unexpected token <,那应该是路径配置问题,检查一下webpack的publicPath配置,这种场景跟上面提到的不是同一个问题。
更多推荐
所有评论(0)