Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

脚本错误量极致优化-让脚本错误一目了然 #14

Open
joeyguo opened this issue May 3, 2017 · 30 comments
Open

脚本错误量极致优化-让脚本错误一目了然 #14

joeyguo opened this issue May 3, 2017 · 30 comments

Comments

@joeyguo
Copy link
Owner

joeyguo commented May 3, 2017

原文地址

在上篇《脚本错误量极致优化-监控上报与Script error》 中,主要提到了js脚本错误上报的方式,并讲解了如何使用 crossorigin 来解决 Script error 报错信息的方案,于是我们就可以查看到脚本报错信息了。而此时可能会遇到另一个问题:”JS 代码压缩后,定位具体出错代码困难!“。本篇《脚本错误量极致优化-让脚本错误一目了然》 将结合示例,通过多种解决方案逐一分析,让脚本错误 一目了然。

示例 · 压缩代码定位错误困难

1.源代码(存在错误)

function test() {
    noerror // <- 报错
}

test();

2.经 webpack 打包压缩后产生如下代码

!function(n){function r(e){if(t[e])return t[e].exports;var o=t[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var t={};r.m=n,r.c=t,r.i=function(n){return n},r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e})},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,"a",t),t},r.o=function(n,r){return Object.prototype.hasOwnProperty.call(n,r)},r.p="",r(r.s=0)}([function(n,r){function t(){noerror}t()}]);

3.代码如期报错,并上报相关信息

{ msg: 'Uncaught ReferenceError: noerror is not defined',
  url: 'http://127.0.0.1:8077/main.min.js',
  row: '1',
  col: '515' }

此时,错误信息中行列数为 1 和 515。 结合压缩后的代码,肉眼观察很难定位出具体问题。

如何定位到具体错误

方案一:不压缩 js 代码

这种方式简单粗暴,但存在明显问题:1. 源代码泄漏,2. 文件的大小大大增加。

方案二:将压缩代码中分号变成换行

uglifyjs 有一个叫 semicolons 配置参数,设置为 false 时,会将压缩代码中的分号替换为换行符,提高代码可读性, 如

!function(n){function r(e){if(t[e])return t[e].exports
var o=t[e]={i:e,l:!1,exports:{}}
return n[e].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var t={}
r.m=n,r.c=t,r.i=function(n){return n},r.d=function(n,t,e){r.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:e})},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n}
return r.d(t,"a",t),t},r.o=function(n,r){return Object.prototype.hasOwnProperty.call(n,r)},r.p="",r(r.s=0)}([function(n,r){function t(){noerror}t()}])

此时,错误信息中行列数为 5 和 137,查找起来比普通压缩方便不少。但仍会出现一行中有很多代码,不容易定位的问题。

方案三:js 代码半压缩 · 保留空格和换行

uglifyjs 的另一配置参数 beautify 设置为 true 时,最终代码将呈现压缩后进行格式化的效果(保留空格和换行),如

!function(n) {
    // ...
    // ...
}([ function(n, r) {
    function t() {
        noerror;
    }
    t();
} ]);

此时,错误信息中行列数为 32 和 9,能够快速定位到具体位置,进而对应到源代码。但由于增加了换行和空格,所以文件大小有所增加。

方案四:SourceMap 快速定位

SourceMap 是一个信息文件,存储着源文件的信息及源文件与处理后文件的映射关系。

在定位压缩代码的报错时,可以通过错误信息的行列数与对应的 SourceMap 文件,处理后得到源文件的具体错误信息。

sourcemap_1

SourceMap 文件中的 sourcesContent 字段对应源代码内容,不希望将 SourceMap 文件发布到外网上,而是将其存储到脚本错误处理平台上,只用在处理脚本错误中。

通过 SourceMap 文件可以得到源文件的具体错误信息,结合 sourcesContent 上源文件的内容进行可视化展示,让报错信息一目了然!

基于 SourceMap 快速定位脚本报错方案

sourcemap_2

整套方案的代码实现可以在这 noerror 查看,效果如下

sourcemap-noerror

1.左边的为线上页面,上报脚本错误
2.右边的为 noerror 脚本错误监控系统

此时,错误信息中行列数为 1 和 515。 结合 sourcemap,经处理(source-map)后,拿到对应的源文件上的具体错误信息,并进行展示。

方案五:开源方案 sentry

sentry 是一个实时的错误日志追踪和聚合平台,包含了上面 sourcemap 方案,并支持更多功能,如:错误调用栈,log 信息,issue管理,多项目,多用户,提供多种语言客户端等,具体介绍可以查看 getsentry/sentrysentry.io,这里暂不展开。

features-page-dash 1

总结

以上的方案都有各自使用场景,能够解决问题的方案都是好方案。可以先快速支持,然后逐渐过渡到完整的方案。除了本篇文章 提到的方案外,社区还有不少其他的优秀方案。

关于 sourceMap 文件的生成,通过 gulp,webpack 都可以很好支持, noerror 的示例使用的是 webpack,只需要设置 devtool: "source-map",具体示例可以查看这里

查看更多文章 >>
https://github.com/joeyguo/blog

@EthanLin-TWer
Copy link

关于方案一:不压缩 JS。前几天才发现一个工具,直接把 minify + uglify 过的 JS 代码通过机器学习还原出来,虽然效果不一定很好:http://jsnice.org/

@yuyang2016
Copy link

老师您好,我是https://sdk.cn 编辑于洋,希望转载这篇文章到我们网站上,请您放心我们会严格遵守转载规范,注明作者和出处,希望能得到老师的授权。

@joeyguo
Copy link
Owner Author

joeyguo commented May 8, 2017

@yuyang2016 可以哈

@yuyang2016
Copy link

谢谢老师!

@pengxiang-git
Copy link

方案五:开源方案 sentry,能介绍下吗

@guoxiangwen
Copy link

如果要做成一个通用的错误脚本监控,怎么实施呢,比如嵌入脚本,而且监控的网站是不会让你动代码的。

@pengkobe
Copy link

@joeyguo 哥,你的图画的极其好看,求告知下画图工具是哪个哈~

@joeyguo
Copy link
Owner Author

joeyguo commented Jul 1, 2017

@guoxiangwen 嵌入脚本是为了能够上报错误信息,所以是必须的。如果无法更改项目代码的话,可以在用代理的方式在资源返回前插入上报脚本(不推荐)。

@joeyguo
Copy link
Owner Author

joeyguo commented Jul 1, 2017

@pengkobe hi,上面那些是在keynote上制作的

@joeyguo
Copy link
Owner Author

joeyguo commented Jul 1, 2017

@pengxianggithub sentry 的文档挺全的,不妨先看看 https://sentry.io/welcome/

@ImTomy
Copy link

ImTomy commented Jul 10, 2017

global code@ 类似于这种问题,是js error捕获的api层面错误吗?貌似网上相关的文档很少

@cgkoreyoshi
Copy link

写得不错,图也画的很好

@ganyouyin
Copy link

你好,如果错误在压缩后的代码的第m行,第n列,使用类似于js-beautify的工具进行格式化后,怎么获取错误在格式化后的代码的哪一列哪一行?

@joeyguo
Copy link
Owner Author

joeyguo commented May 24, 2018

@ganyouyin
Copy link

@joeyguo node 环境下使用报错,issue地址:joeyguo/js-beautify-sourcemap#1

@npm-ued
Copy link

npm-ued commented Oct 26, 2018

看了noerror的代码,挺好的,学习到不少,但是博主是如何解决上线时还需要同步打出sourceMap线上安全问题的?是先打一个devtool:false,再打一个source-map然后将sourceMap上传到监控服务器上?

@joeyguo
Copy link
Owner Author

joeyguo commented Oct 28, 2018

@npm-ued 是说什么安全问题呢?构建只执行一次,sourceMap文件生成出来上传到监控服务器,不发到现网。

@joeyguo
Copy link
Owner Author

joeyguo commented Nov 14, 2018

@ganyouyin 已fix

@hucheng91
Copy link

要是 vue 怎么弄呀

Vue.config.errorHandler = function(err, vm, info) {}
这里没有返回行号和列

1 similar comment
@hucheng91
Copy link

要是 vue 怎么弄呀

Vue.config.errorHandler = function(err, vm, info) {}
这里没有返回行号和列

@hucheng91
Copy link

hucheng91 commented Apr 11, 2019

还原后的文件

期待的代码

export default {
  name: "app",
  components: {},
  data() {
    return {
      value: 1234689
    };
  },
  methods: {
    test(){
      throw new Error("老哥,报错了呀")
    }
  }
};

@hucheng91
Copy link

好了,是我自己的一个问题

@huruji
Copy link

huruji commented Apr 18, 2019

m

@Lionad-Morotar
Copy link

关于方案一:不压缩 JS。前几天才发现一个工具,直接把 minify + uglify 过的 JS 代码通过机器学习还原出来,虽然效果不一定很好:http://jsnice.org/

主要是靠注释和名字比对生成的代码,几乎零实用性
image

@sisterAn
Copy link

你好,可以转载到公众号高级前端进阶上吗?会标明作者与来源,感谢

@yingzidd12
Copy link

yingzidd12 commented Aug 27, 2020 via email

@joeyguo
Copy link
Owner Author

joeyguo commented Aug 31, 2020

你好,可以转载到公众号高级前端进阶上吗?会标明作者与来源,感谢

@sisterAn 可以。

@foreverwang
Copy link

还原后的文件

期待的代码

export default {
  name: "app",
  components: {},
  data() {
    return {
      value: 1234689
    };
  },
  methods: {
    test(){
      throw new Error("老哥,报错了呀")
    }
  }
};

这种可视化展示是怎么做的

@liuxsen
Copy link

liuxsen commented Mar 2, 2021

要是 vue 怎么弄呀

Vue.config.errorHandler = function(err, vm, info) {}
这里没有返回行号和列

怎么处理的呢,我遇到了相同的问题

@DBAAZzz
Copy link

DBAAZzz commented Nov 4, 2021

要是 vue 怎么弄呀
Vue.config.errorHandler = function(err, vm, info) {}
这里没有返回行号和列

怎么处理的呢,我遇到了相同的问题

把 err.stack.toString() 上报到服务器,然后在服务器上打印就能看到完整信息了,原来是浏览器自动转码了,如果把开发者工具的 sourcemap 开启的话连行号和文件都看不到。
来源:http://www.javashuo.com/article/p-yqcmwniq-bv.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests