当前位置: 首页 > 后端技术 > Node.js

详解js压缩、sourcemap、通过sourcemap查找原始错误信息

时间:2023-04-03 23:59:37 Node.js

详解js压缩、sourcemap、通过sourcemap查找原始错误信息1.js压缩JS压缩是前端开发者的必修课。一般来说,js压缩主要有以下两个目的:减少代码体积,加快前端资源加载速度,保护源代码不被他人获取。压缩js使用的工具库:UglifyJS2:Compresses5uglify-es:Compresses6+closure-compiler,closure-compiler-js:google的js压缩和优化工具压缩js的主要过程:去除无用代码混淆变量名等预编译代码和代码中的函数名扁平化结构1.去除无用代码去除所有对解析引擎无用的字符,包括空格、注释、换行符、无用的变量声明、函数声明等2.混淆变量名、函数名等代码中,将一些局部变量名、函数名等替换为a,b,...,$1,$2,...,_1,_2,...等简单字符替换即可实现混淆的目的。源代码(function(){varhello='hi';varprint=function(str){console.log(str);};print(hello);})();缩小代码(仅演示混淆)(function(){vara='hi';varb=function(c){console.log(c);};b(a);})();3.预编译代码不依赖于外部环境预先计算好逻辑,将运算结果替换成对应的源码,再将这段逻辑从源码中去除。sourcecode(function(){varhello='hi'+'everyone,';varcount=3*5;console.log(hello+count+'girls');})();压缩代码(仅演示预编译功能)(function(){varhello='hieveryone,';varcount=15;console.log(hello+count+'girls');})();4.结构扁平化对于js来说,嵌套越深,执行越慢,代码扁平化也是一种优化代码的方式。源代码(function(){varsay={hello:function(str){console.log('hello'+str);}};say.hello('everyone');})();压缩代码(仅演示平面结构函数)!function(str){console.log("hello"+str)}("everyone");完整示例源码(function(){varsay={hello:function(str){console.log('hello'+str);}};say.hello('everyone');})();压缩代码!function(l){console.log("hello"+l)}("50girls");2.sourcemap经过js压缩后通常只有一行代码,里面的变量名和函数名都是混淆的。这在实际运行中会造成一个问题,就是js的报错信息会失真,无法追查到源代码的哪一行哪一列出错。Sourcemap就是为了解决这个问题而诞生的。sourcemap文件是一个记录表,记录了从源代码文件到压缩文件的代码对应关系。通过压缩文件和sourcemap文件可以找到源代码文件。查看阮一峰对JavaScriptSourceMap的详解,了解sourcemap的原理和格式。一般在压缩js的过程中,会生成一个对应的sourcemap文件,并在压缩后的js文件末尾附加一个sourcemap文件的链接//#sourceMappingURL=bundle-file-name.js.map。这样浏览器在加载压缩后的js时,就会知道有对应的sourcemap文件,就会一起加载。如果js在运行过程中报错,也会给出相应源码的行号和列号。而不是压缩文件。例如压缩如下源码:(function(){varsay={hi:function(){console.log('hi');}};say.hello();returnsay;})();未添加sourcemap文件时,报错信息:添加sourcemap文件时,报错信息:sourcemapextensionwebpackhasextendedthesourcemap,devtool配置项中定义:eval:eval:eachmoduleexecuteusingeval(),并且都用//@sourceURL,构建速度快,但是不能正确显示行号eval(),一般开发模式使用这种方式cheap-eval-source-map:类似eval-source-map,但只映射行,不映射列,忽略来自loader的sourcemap,只显示翻译后的代码cheap-module-eval-source-map:类似于cheap-eval-source-map,但会保留来自加载程序的源映射pinline-source-map:将源映射转换为DataUrl并将其添加到bundlecheap-source-map:只映射行,不映射列,忽略加载器的源映射,只显示翻译后的代码inline-cheap-source-map:inline-source-map和cheap-source-map的组合cheap-module-source-map:类似到cheap-module-eval-source-map,但不要使用eval()来执行inline-cheap-module-source-map:inline-source-map和cheap-module-source-mapsource-map的组合:整个sourcemap生成为一个文件,产品环境一般采用这种模式hidden-source-map:类似于source-map,但不放//#sourceMappingURL=bundle-file-name.js.map追加到压缩文件的后面nosources-source-map:类似source-map,但只有堆栈信息,没有源代码信息,更详细的信息请参考to:webpackdevtool(英文)webpackDevtool(中文)使用建议使用webpack构建项目,开发时建议使用eval-source-map,产品环境使用source-map,因为可以找到源码原始形式有压缩文件和sourcemap文件,所以为了保护Sourcecode,可以这样隐藏sourcemap文件:sourcemap文件不能在web服务器设置之外访问,只能使用内部访问直接存储其他地方的sourcemap文件3.通过sourcemap查找原始错误信息一般来说,在产品阶段,我们会使用window.onerror来捕获js错误,然后上报给服务器,收集用户使用时出现的bug:window.onerror。onerror=function(message,source,lineno,colno,error){//message:错误信息//source:报错脚本的url地址//lineno:行号//colno:列号//error:错误对象//向服务器报告必要的信息}但是生产环境中的代码是经过压缩的,行号和列号是失真的,所以需要使用sourcemap文件找到源代码对应的行号和列号错误以及其他信息。使用工具:mozilla/source-mapsourcecode(function(){varsay={hi:function(){console.log('hi');}};say.hello();returnsay;})();压缩后的错误信息window.onerror=function(message,source,lineno,colno,error){console.log(`message:${message}`);console.log(`来源:${source}`);console.log(`lineno:${lineno}`);console.log(`colno:${colno}`);console.log(`error:${error}`);}//message:UncaughtTypeError:e.helloisnotafunction//source:url/to/bundle.min.js//lineno:1//colno:982//error:TypeError:e.helloisnotafunction通过source-mapinfo找到原来的报错constfs=require('fs');constSourceMap=require('source-map');const{readFileSync}=fs;const{SourceMapConsumer}=SourceMap;constrawSourceMap=JSON.parse(readFileSync('path/to/js/map/file','utf8'));SourceMapConsumer.with(rawSourceMap,null,consumer=>{constpos=consumer.originalPositionFor({line:1,列:982});console.log(pos);});原始资料找到{source:'path/to/index.js',line:8,column:7,name:'hello'}这样找到原来的错误信息:originalerrorfile:path/to/index.jsoriginalerrorlinenumber:8原始错误栏目数:7原始对象名称:你好如果是这样的话,你可以马上找到错误在哪里Commons3.0许可)