source-map 定位源码错误位置
- 需要安装source-map库
- webpack配置需要配上devtool: “hidden-source-map”,devtool详细配置看这里devtool配置
- 配置完webpack打包后,可以看到打包出来的.js.map文件
- 将生产包产生错误的栈赋值给stack即可,即设置stack = error.stack,格式见下面例子,可以这样获取,注意是error.stack
window.addEventListener("error", (event) => {
console.log("%c [ event.error.stack ]-13", "font-size:13px; background:pink; color:#bf2c9f;", event.error.stack)
})
- 注意这里说的是生产包产生的错误,不是测试环境,测试环境一般是设置为自动加载source map,也就是直接在浏览器可以点击定位到源码(为防止别人发现我代码写得太烂,线上不建议这样使用)
- 主要流程:通过将.js.map读出来,然后通过source-map库的处理该文件,再根据错误栈error.stack做位置匹配,具体匹配流程可以到这里膜拜一下大佬操作source-map
- 这里只是一个简单的demo,需要手动复制错误,手动执行文件
/** 通过source-map 定位源码错误位置 */
const fs = require("fs")
const path = require("path")
const { SourceMapConsumer } = require("source-map")
const stack = `
Error: 手动抛出错误
at onClick (http://localhost:3000/static/js/main.08fa76b6.js:2:12177)
at te (http://localhost:3000/static/js/vendor.30784604.js:2:131903)
at Object.Ie (http://localhost:3000/static/js/vendor.30784604.js:2:596135)
at De (http://localhost:3000/static/js/vendor.30784604.js:2:596289)
at http://localhost:3000/static/js/vendor.30784604.js:2:616171
at Zr (http://localhost:3000/static/js/vendor.30784604.js:2:616265)
at zr (http://localhost:3000/static/js/vendor.30784604.js:2:616679)
at http://localhost:3000/static/js/vendor.30784604.js:2:622117
at cu (http://localhost:3000/static/js/vendor.30784604.js:2:685488)
at Ae (http://localhost:3000/static/js/vendor.30784604.js:2:595268)
`
function processShowErrorLocation() {
const dirName = path.resolve(__dirname, "../../dist/static/js")
const isExit = fs.existsSync(dirName)
if (!isExit) {
console.log(
"%c [ 文件夹路径不存在,是不是没有打包,可执行命令yarn build:prod ]-26",
"font-size:13px; background:pink; color:#bf2c9f;",
)
return
}
const files = fs.readdirSync(dirName)
const regex = /^(?!vendor).*\.js.map$/
files.forEach((item) => {
if (!regex.test(item)) {
return
}
const filePath = path.join(dirName, item)
getSourceCodeLocation(filePath)
})
}
async function getSourceMapConsumer(filePath) {
const mapFile = path.resolve(filePath)
const sourceMapContent = fs.readFileSync(mapFile).toString()
return await new SourceMapConsumer(sourceMapContent)
}
async function getSourceCodeLocation(filePath) {
const match = /(\w+\.js):(\d+):(\d+)/.exec(stack)
const line = parseInt(match[2], 10)
const column = parseInt(match[3], 10)
const consumer = await getSourceMapConsumer(filePath)
const originalPosition = consumer.originalPositionFor({
line,
column,
bias: SourceMapConsumer.GREATEST_LOWER_BOUND,
})
originalPosition.mapFilePath = filePath
if (!originalPosition.source) {
return
}
console.log(originalPosition) // { source: 'test.js', line: 2, column: 0, name: 'sum' }
}
processShowErrorLocation()