source map 还原js报错

最近在做前端全链路监控,其中一个功能就是根据sdk上报的错误信息利用source map进行还原

上报信息类似这样

{ 
  file: '../../node_modules/downloadjs/download.js',
  message: 'Uncaught ReferenceError: data is not defined',
  line: 1,
  column: 200,
 }

包括报错信息,所在行列,然后就希望可以通过源码的source map 还原成这样子
iShot_2024-05-24_09.52.45.png

思路是使用mozilla的source-map https://github.com/mozilla/source-map

1.修改打包配置,这里是使用vite

 build: {
      sourcemap: true,
      //...其他配置
}

2.新建index.html,引入sourcemap包

<script src="https://unpkg.com/source-map@0.7.3/dist/source-map.js"></script>
  <script>
    sourceMap.SourceMapConsumer.initialize({
      "lib/mappings.wasm":
        "https://unpkg.com/source-map@0.7.3/lib/mappings.wasm",
    });
  </script>

3.获取代码的source map,这里为了方便演示,直接用一个对象代替,真正到生产的时候,可以直接通过服务去自动读取

const file = {
      version: 3,
      file: "downloadjs-legacy-b08799ac.js",
      sources: ["../../node_modules/downloadjs/download.js"],
      sourcesContent: [
        '//download.js v4.2, by dandavis; 2008-2016. [MIT] see http://danml.com/download.html for tests/usage\n// v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime\n// v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs\n// v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support. 3.1 improved safari handling.\n// v4 adds AMD/UMD, commonJS, and plain browser support\n// v4.1 adds url download capability via solo URL argument (same domain/CORS only)\n// v4.2 adds semantic variable names, long (over 2MB) dataURL support, and hidden by default temp anchors\n// https://github.com/rndme/download\n\n(function (root, factory) {\n\tif (typeof define === \'function\' && define.amd) {\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine([], factory);\n\t} else if (typeof exports === \'object\') {\n\t\t// Node. Does not work with strict CommonJS, but\n\t\t// only CommonJS-like environments that support module.exports,\n\t\t// like Node.\n\t\tmodule.exports = factory();\n\t} else {\n\t\t// Browser globals (root is window)\n\t\troot.download = factory();\n  }\n}(this, function () {\n\n\treturn function download(data, strFileName, strMimeType) {\n\n\t\tvar self = window, // this script is only for browsers anyway...\n\t\t\tdefaultMime = "application/octet-stream", // this default mime also triggers iframe downloads\n\t\t\tmimeType = strMimeType || defaultMime,\n\t\t\tpayload = data,\n\t\t\turl = !strFileName && !strMimeType && payload,\n\t\t\tanchor = document.createElement("a"),\n\t\t\ttoString = function(a){return String(a);},\n\t\t\tmyBlob = (self.Blob || self.MozBlob || self.WebKitBlob || toString),\n\t\t\tfileName = strFileName || "download",\n\t\t\tblob,\n\t\t\treader;\n\t\t\tmyBlob= myBlob.call ? myBlob.bind(self) : Blob ;\n\t  \n\t\tif(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback\n\t\t\tpayload=[payload, mimeType];\n\t\t\tmimeType=payload[0];\n\t\t\tpayload=payload[1];\n\t\t}\n\n\n\t\tif(url && url.length< 2048){ // if no filename and no mime, assume a url was passed as the only argument\n\t\t\tfileName = url.split("/").pop().split("?")[0];\n\t\t\tanchor.href = url; // assign href prop to temp anchor\n\t\t  \tif(anchor.href.indexOf(url) !== -1){ // if the browser determines that it\'s a potentially valid url path:\n        \t\tvar ajax=new XMLHttpRequest();\n        \t\tajax.open( "GET", url, true);\n        \t\tajax.responseType = \'blob\';\n        \t\tajax.onload= function(e){ \n\t\t\t\t  download(e.target.response, fileName, defaultMime);\n\t\t\t\t};\n        \t\tsetTimeout(function(){ ajax.send();}, 0); // allows setting custom ajax headers using the return:\n\t\t\t    return ajax;\n\t\t\t} // end if valid url?\n\t\t} // end if url?\n\n\n\t\t//go ahead and download dataURLs right away\n\t\tif(/^data:([\\w+-]+\\/[\\w+.-]+)?[,;]/.test(payload)){\n\t\t\n\t\t\tif(payload.length > (1024*1024*1.999) && myBlob !== toString ){\n\t\t\t\tpayload=dataUrlToBlob(payload);\n\t\t\t\tmimeType=payload.type || defaultMime;\n\t\t\t}else{\t\t\t\n\t\t\t\treturn navigator.msSaveBlob ?  // IE10 can\'t do a[download], only Blobs:\n\t\t\t\t\tnavigator.msSaveBlob(dataUrlToBlob(payload), fileName) :\n\t\t\t\t\tsaver(payload) ; // everyone else can save dataURLs un-processed\n\t\t\t}\n\t\t\t\n\t\t}else{//not data url, is it a string with special needs?\n\t\t\tif(/([\\x80-\\xff])/.test(payload)){\t\t\t  \n\t\t\t\tvar i=0, tempUiArr= new Uint8Array(payload.length), mx=tempUiArr.length;\n\t\t\t\tfor(i;i<mx;++i) tempUiArr[i]= payload.charCodeAt(i);\n\t\t\t \tpayload=new myBlob([tempUiArr], {type: mimeType});\n\t\t\t}\t\t  \n\t\t}\n\t\tblob = payload instanceof myBlob ?\n\t\t\tpayload :\n\t\t\tnew myBlob([payload], {type: mimeType}) ;\n\n\n\t\tfunction dataUrlToBlob(strUrl) {\n\t\t\tvar parts= strUrl.split(/[:;,]/),\n\t\t\ttype= parts[1],\n\t\t\tdecoder= parts[2] == "base64" ? atob : decodeURIComponent,\n\t\t\tbinData= decoder( parts.pop() ),\n\t\t\tmx= binData.length,\n\t\t\ti= 0,\n\t\t\tuiArr= new Uint8Array(mx);\n\n\t\t\tfor(i;i<mx;++i) uiArr[i]= binData.charCodeAt(i);\n\n\t\t\treturn new myBlob([uiArr], {type: type});\n\t\t }\n\n\t\tfunction saver(url, winMode){\n\n\t\t\tif (\'download\' in anchor) { //html5 A[download]\n\t\t\t\tanchor.href = url;\n\t\t\t\tanchor.setAttribute("download", fileName);\n\t\t\t\tanchor.className = "download-js-link";\n\t\t\t\tanchor.innerHTML = "downloading...";\n\t\t\t\tanchor.style.display = "none";\n\t\t\t\tdocument.body.appendChild(anchor);\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tanchor.click();\n\t\t\t\t\tdocument.body.removeChild(anchor);\n\t\t\t\t\tif(winMode===true){setTimeout(function(){ self.URL.revokeObjectURL(anchor.href);}, 250 );}\n\t\t\t\t}, 66);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// handle non-a[download] safari as best we can:\n\t\t\tif(/(Version)\\/(\\d+)\\.(\\d+)(?:\\.(\\d+))?.*Safari\\//.test(navigator.userAgent)) {\n\t\t\t\tif(/^data:/.test(url))\turl="data:"+url.replace(/^data:([\\w\\/\\-\\+]+)/, defaultMime);\n\t\t\t\tif(!window.open(url)){ // popup blocked, offer direct download:\n\t\t\t\t\tif(confirm("Displaying New Document\\n\\nUse Save As... to download, then click back to return to this page.")){ location.href=url; }\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t//do iframe dataURL download (old ch+FF):\n\t\t\tvar f = document.createElement("iframe");\n\t\t\tdocument.body.appendChild(f);\n\n\t\t\tif(!winMode && /^data:/.test(url)){ // force a mime that will download:\n\t\t\t\turl="data:"+url.replace(/^data:([\\w\\/\\-\\+]+)/, defaultMime);\n\t\t\t}\n\t\t\tf.src=url;\n\t\t\tsetTimeout(function(){ document.body.removeChild(f); }, 333);\n\n\t\t}//end saver\n\n\n\n\n\t\tif (navigator.msSaveBlob) { // IE10+ : (has Blob, but not a[download] or URL)\n\t\t\treturn navigator.msSaveBlob(blob, fileName);\n\t\t}\n\n\t\tif(self.URL){ // simple fast and modern way using Blob and URL:\n\t\t\tsaver(self.URL.createObjectURL(blob), true);\n\t\t}else{\n\t\t\t// handle non-Blob()+non-URL browsers:\n\t\t\tif(typeof blob === "string" || blob.constructor===toString ){\n\t\t\t\ttry{\n\t\t\t\t\treturn saver( "data:" +  mimeType   + ";base64,"  +  self.btoa(blob)  );\n\t\t\t\t}catch(y){\n\t\t\t\t\treturn saver( "data:" +  mimeType   + "," + encodeURIComponent(blob)  );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Blob but not URL support:\n\t\t\treader=new FileReader();\n\t\t\treader.onload=function(e){\n\t\t\t\tsaver(this.result);\n\t\t\t};\n\t\t\treader.readAsDataURL(blob);\n\t\t}\n\t\treturn true;\n\t}; /* end download() */\n}));\n',
      ],
      names: [
        "module",
        "exports",
        "download",
        "data",
        "strFileName",
        "strMimeType",
        "blob",
        "reader",
        "self",
        "window",
        "defaultMime",
        "mimeType",
        "payload",
        "url",
        "anchor",
        "document",
        "createElement",
        "toString",
        "a",
        "String",
        "myBlob",
        "Blob",
        "MozBlob",
        "WebKitBlob",
        "fileName",
        "call",
        "bind",
        "this",
        "length",
        "split",
        "pop",
        "href",
        "indexOf",
        "ajax",
        "XMLHttpRequest",
        "open",
        "responseType",
        "onload",
        "e",
        "target",
        "response",
        "setTimeout",
        "send",
        "test",
        "navigator",
        "msSaveBlob",
        "dataUrlToBlob",
        "saver",
        "type",
        "i",
        "tempUiArr",
        "Uint8Array",
        "mx",
        "charCodeAt",
        "strUrl",
        "parts",
        "binData",
        "atob",
        "decodeURIComponent",
        "uiArr",
        "winMode",
        "setAttribute",
        "className",
        "innerHTML",
        "style",
        "display",
        "body",
        "appendChild",
        "click",
        "removeChild",
        "URL",
        "revokeObjectURL",
        "userAgent",
        "replace",
        "confirm",
        "location",
        "f",
        "src",
        "createObjectURL",
        "constructor",
        "btoa",
        "y",
        "encodeURIComponent",
        "FileReader",
        "result",
        "readAsDataURL",
      ],
      mappings:
        "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",
      x_google_ignoreList: [0],
    };

上面的file对象就是一个完成的source map

4.使用sourcemap包提供的方法,根据报错信息找到真正的报错行列,大概这样子

 const consumer = await new sourceMap.SourceMapConsumer(file);
    const lookup = {
      file: "../../node_modules/downloadjs/download.js",
      message: "Uncaught ReferenceError: data is not defined",
      line: 1,
      column: 200,
    };
 const result = consumer.originalPositionFor(lookup);

result返回

{
column: 26,
line: 25,
name: "data",
source: "../../node_modules/downloadjs/download.js"
}

5.根据result信息还原
iShot_2024-05-24_10.22.56.png

最后效果

iShot_2024-05-24_09.52.45.png

下面是完整代码

<!DOCTYPE html>
<head>
  <script src="https://unpkg.com/source-map@0.7.3/dist/source-map.js"></script>
  <script>
    sourceMap.SourceMapConsumer.initialize({
      "lib/mappings.wasm":
        "https://unpkg.com/source-map@0.7.3/lib/mappings.wasm",
    });
  </script>
</head>
<html>
  <div id="abc"></div>
  <script>
    const file = {
      version: 3,
      file: "downloadjs-legacy-b08799ac.js",
      sources: ["../../node_modules/downloadjs/download.js"],
      sourcesContent: [
        '//download.js v4.2, by dandavis; 2008-2016. [MIT] see http://danml.com/download.html for tests/usage\n// v1 landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime\n// v2 added named files via a[download], msSaveBlob, IE (10+) support, and window.URL support for larger+faster saves than dataURLs\n// v3 added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support. 3.1 improved safari handling.\n// v4 adds AMD/UMD, commonJS, and plain browser support\n// v4.1 adds url download capability via solo URL argument (same domain/CORS only)\n// v4.2 adds semantic variable names, long (over 2MB) dataURL support, and hidden by default temp anchors\n// https://github.com/rndme/download\n\n(function (root, factory) {\n\tif (typeof define === \'function\' && define.amd) {\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine([], factory);\n\t} else if (typeof exports === \'object\') {\n\t\t// Node. Does not work with strict CommonJS, but\n\t\t// only CommonJS-like environments that support module.exports,\n\t\t// like Node.\n\t\tmodule.exports = factory();\n\t} else {\n\t\t// Browser globals (root is window)\n\t\troot.download = factory();\n  }\n}(this, function () {\n\n\treturn function download(data, strFileName, strMimeType) {\n\n\t\tvar self = window, // this script is only for browsers anyway...\n\t\t\tdefaultMime = "application/octet-stream", // this default mime also triggers iframe downloads\n\t\t\tmimeType = strMimeType || defaultMime,\n\t\t\tpayload = data,\n\t\t\turl = !strFileName && !strMimeType && payload,\n\t\t\tanchor = document.createElement("a"),\n\t\t\ttoString = function(a){return String(a);},\n\t\t\tmyBlob = (self.Blob || self.MozBlob || self.WebKitBlob || toString),\n\t\t\tfileName = strFileName || "download",\n\t\t\tblob,\n\t\t\treader;\n\t\t\tmyBlob= myBlob.call ? myBlob.bind(self) : Blob ;\n\t  \n\t\tif(String(this)==="true"){ //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback\n\t\t\tpayload=[payload, mimeType];\n\t\t\tmimeType=payload[0];\n\t\t\tpayload=payload[1];\n\t\t}\n\n\n\t\tif(url && url.length< 2048){ // if no filename and no mime, assume a url was passed as the only argument\n\t\t\tfileName = url.split("/").pop().split("?")[0];\n\t\t\tanchor.href = url; // assign href prop to temp anchor\n\t\t  \tif(anchor.href.indexOf(url) !== -1){ // if the browser determines that it\'s a potentially valid url path:\n        \t\tvar ajax=new XMLHttpRequest();\n        \t\tajax.open( "GET", url, true);\n        \t\tajax.responseType = \'blob\';\n        \t\tajax.onload= function(e){ \n\t\t\t\t  download(e.target.response, fileName, defaultMime);\n\t\t\t\t};\n        \t\tsetTimeout(function(){ ajax.send();}, 0); // allows setting custom ajax headers using the return:\n\t\t\t    return ajax;\n\t\t\t} // end if valid url?\n\t\t} // end if url?\n\n\n\t\t//go ahead and download dataURLs right away\n\t\tif(/^data:([\\w+-]+\\/[\\w+.-]+)?[,;]/.test(payload)){\n\t\t\n\t\t\tif(payload.length > (1024*1024*1.999) && myBlob !== toString ){\n\t\t\t\tpayload=dataUrlToBlob(payload);\n\t\t\t\tmimeType=payload.type || defaultMime;\n\t\t\t}else{\t\t\t\n\t\t\t\treturn navigator.msSaveBlob ?  // IE10 can\'t do a[download], only Blobs:\n\t\t\t\t\tnavigator.msSaveBlob(dataUrlToBlob(payload), fileName) :\n\t\t\t\t\tsaver(payload) ; // everyone else can save dataURLs un-processed\n\t\t\t}\n\t\t\t\n\t\t}else{//not data url, is it a string with special needs?\n\t\t\tif(/([\\x80-\\xff])/.test(payload)){\t\t\t  \n\t\t\t\tvar i=0, tempUiArr= new Uint8Array(payload.length), mx=tempUiArr.length;\n\t\t\t\tfor(i;i<mx;++i) tempUiArr[i]= payload.charCodeAt(i);\n\t\t\t \tpayload=new myBlob([tempUiArr], {type: mimeType});\n\t\t\t}\t\t  \n\t\t}\n\t\tblob = payload instanceof myBlob ?\n\t\t\tpayload :\n\t\t\tnew myBlob([payload], {type: mimeType}) ;\n\n\n\t\tfunction dataUrlToBlob(strUrl) {\n\t\t\tvar parts= strUrl.split(/[:;,]/),\n\t\t\ttype= parts[1],\n\t\t\tdecoder= parts[2] == "base64" ? atob : decodeURIComponent,\n\t\t\tbinData= decoder( parts.pop() ),\n\t\t\tmx= binData.length,\n\t\t\ti= 0,\n\t\t\tuiArr= new Uint8Array(mx);\n\n\t\t\tfor(i;i<mx;++i) uiArr[i]= binData.charCodeAt(i);\n\n\t\t\treturn new myBlob([uiArr], {type: type});\n\t\t }\n\n\t\tfunction saver(url, winMode){\n\n\t\t\tif (\'download\' in anchor) { //html5 A[download]\n\t\t\t\tanchor.href = url;\n\t\t\t\tanchor.setAttribute("download", fileName);\n\t\t\t\tanchor.className = "download-js-link";\n\t\t\t\tanchor.innerHTML = "downloading...";\n\t\t\t\tanchor.style.display = "none";\n\t\t\t\tdocument.body.appendChild(anchor);\n\t\t\t\tsetTimeout(function() {\n\t\t\t\t\tanchor.click();\n\t\t\t\t\tdocument.body.removeChild(anchor);\n\t\t\t\t\tif(winMode===true){setTimeout(function(){ self.URL.revokeObjectURL(anchor.href);}, 250 );}\n\t\t\t\t}, 66);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// handle non-a[download] safari as best we can:\n\t\t\tif(/(Version)\\/(\\d+)\\.(\\d+)(?:\\.(\\d+))?.*Safari\\//.test(navigator.userAgent)) {\n\t\t\t\tif(/^data:/.test(url))\turl="data:"+url.replace(/^data:([\\w\\/\\-\\+]+)/, defaultMime);\n\t\t\t\tif(!window.open(url)){ // popup blocked, offer direct download:\n\t\t\t\t\tif(confirm("Displaying New Document\\n\\nUse Save As... to download, then click back to return to this page.")){ location.href=url; }\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t//do iframe dataURL download (old ch+FF):\n\t\t\tvar f = document.createElement("iframe");\n\t\t\tdocument.body.appendChild(f);\n\n\t\t\tif(!winMode && /^data:/.test(url)){ // force a mime that will download:\n\t\t\t\turl="data:"+url.replace(/^data:([\\w\\/\\-\\+]+)/, defaultMime);\n\t\t\t}\n\t\t\tf.src=url;\n\t\t\tsetTimeout(function(){ document.body.removeChild(f); }, 333);\n\n\t\t}//end saver\n\n\n\n\n\t\tif (navigator.msSaveBlob) { // IE10+ : (has Blob, but not a[download] or URL)\n\t\t\treturn navigator.msSaveBlob(blob, fileName);\n\t\t}\n\n\t\tif(self.URL){ // simple fast and modern way using Blob and URL:\n\t\t\tsaver(self.URL.createObjectURL(blob), true);\n\t\t}else{\n\t\t\t// handle non-Blob()+non-URL browsers:\n\t\t\tif(typeof blob === "string" || blob.constructor===toString ){\n\t\t\t\ttry{\n\t\t\t\t\treturn saver( "data:" +  mimeType   + ";base64,"  +  self.btoa(blob)  );\n\t\t\t\t}catch(y){\n\t\t\t\t\treturn saver( "data:" +  mimeType   + "," + encodeURIComponent(blob)  );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Blob but not URL support:\n\t\t\treader=new FileReader();\n\t\t\treader.onload=function(e){\n\t\t\t\tsaver(this.result);\n\t\t\t};\n\t\t\treader.readAsDataURL(blob);\n\t\t}\n\t\treturn true;\n\t}; /* end download() */\n}));\n',
      ],
      names: [
        "module",
        "exports",
        "download",
        "data",
        "strFileName",
        "strMimeType",
        "blob",
        "reader",
        "self",
        "window",
        "defaultMime",
        "mimeType",
        "payload",
        "url",
        "anchor",
        "document",
        "createElement",
        "toString",
        "a",
        "String",
        "myBlob",
        "Blob",
        "MozBlob",
        "WebKitBlob",
        "fileName",
        "call",
        "bind",
        "this",
        "length",
        "split",
        "pop",
        "href",
        "indexOf",
        "ajax",
        "XMLHttpRequest",
        "open",
        "responseType",
        "onload",
        "e",
        "target",
        "response",
        "setTimeout",
        "send",
        "test",
        "navigator",
        "msSaveBlob",
        "dataUrlToBlob",
        "saver",
        "type",
        "i",
        "tempUiArr",
        "Uint8Array",
        "mx",
        "charCodeAt",
        "strUrl",
        "parts",
        "binData",
        "atob",
        "decodeURIComponent",
        "uiArr",
        "winMode",
        "setAttribute",
        "className",
        "innerHTML",
        "style",
        "display",
        "body",
        "appendChild",
        "click",
        "removeChild",
        "URL",
        "revokeObjectURL",
        "userAgent",
        "replace",
        "confirm",
        "location",
        "f",
        "src",
        "createObjectURL",
        "constructor",
        "btoa",
        "y",
        "encodeURIComponent",
        "FileReader",
        "result",
        "readAsDataURL",
      ],
      mappings:
        "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",
      x_google_ignoreList: [0],
    };

    const code = "";
    window.onload = async function () {
      const consumer = await new sourceMap.SourceMapConsumer(file);
      const lookup = {
        file: "../../node_modules/downloadjs/download.js",
        message: "Uncaught ReferenceError: data is not defined",
        line: 1,
        column: 200,
      };
      const result = consumer.originalPositionFor(lookup);

      const lines = consumer.sourcesContent[0].split("\n");

      const { line, column } = result;
      const showMaxLine = 5;

      // 计算要展示的行的起始位置,起始行号不能小于1
      const startLine = Math.max(1, line - Math.floor(showMaxLine / 2));
      // 结束位置不能大于总行数
      const endLine = Math.min(lines.length, startLine + showMaxLine - 1);

      const showCode = lines
        .slice(startLine - 1, endLine)
        .map(
          (v, idx) =>
            `<div>
              <span style="color: blue;padding-right:40px;">
              ${startLine + idx} 
              </span>
              <span>
              ${
                // 针对错误的行进行下划线+红色展示
                idx + startLine === line
                  ? "<span style='color: red'>" +
                    v.slice(0, column - 1) +
                    v.slice(column - 1) +
                    "</span>"
                  : v
              }
            </span>
            </div>`
        )
        .join("\n");

      document.querySelector("#abc").innerHTML = `
      <div>
        <span style="color: red">Uncaught ReferenceError: abc is not defined</span> in ${result.source} ${result.line}:${result.column}</div>
        
      ${showCode}`;
    };
  </script>
  <body></body>
</html>

标签: none

添加新评论