index.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import { errorStore, ErrorInfo } from '/@/store/modules/error';
  2. import { useSetting } from '/@/hooks/core/useSetting';
  3. import { ErrorTypeEnum } from '/@/enums/exceptionEnum';
  4. import { App } from 'vue';
  5. function processStackMsg(error: Error) {
  6. if (!error.stack) {
  7. return '';
  8. }
  9. let stack = error.stack
  10. .replace(/\n/gi, '') // 去掉换行,节省传输内容大小
  11. .replace(/\bat\b/gi, '@') // chrome中是at,ff中是@
  12. .split('@') // 以@分割信息
  13. .slice(0, 9) // 最大堆栈长度(Error.stackTraceLimit = 10),所以只取前10条
  14. .map((v) => v.replace(/^\s*|\s*$/g, '')) // 去除多余空格
  15. .join('~') // 手动添加分隔符,便于后期展示
  16. .replace(/\?[^:]+/gi, ''); // 去除js文件链接的多余参数(?x=1之类)
  17. const msg = error.toString();
  18. if (stack.indexOf(msg) < 0) {
  19. stack = msg + '@' + stack;
  20. }
  21. return stack;
  22. }
  23. function formatComponentName(vm: any) {
  24. if (vm.$root === vm) {
  25. return {
  26. name: 'root',
  27. path: 'root',
  28. };
  29. }
  30. const options = vm.$options as any;
  31. if (!options) {
  32. return {
  33. name: 'anonymous',
  34. path: 'anonymous',
  35. };
  36. }
  37. const name = options.name || options._componentTag;
  38. return {
  39. name: name,
  40. path: options.__file,
  41. };
  42. }
  43. function vueErrorHandler(err: Error, vm: any, info: string) {
  44. const { name, path } = formatComponentName(vm);
  45. errorStore.commitErrorInfoState({
  46. type: ErrorTypeEnum.VUE,
  47. name,
  48. file: path,
  49. message: err.message,
  50. stack: processStackMsg(err),
  51. detail: info,
  52. url: window.location.href,
  53. });
  54. }
  55. export function scriptErrorHandler(
  56. event: Event | string,
  57. source?: string,
  58. lineno?: number,
  59. colno?: number,
  60. error?: Error
  61. ) {
  62. if (event === 'Script error.' && !source) {
  63. return false;
  64. }
  65. const errorInfo: Partial<ErrorInfo> = {};
  66. colno = colno || (window.event && (window.event as any).errorCharacter) || 0;
  67. errorInfo.message = event as string;
  68. if (error && error.stack) {
  69. errorInfo.stack = error.stack;
  70. } else {
  71. errorInfo.stack = '';
  72. }
  73. const name = source ? source.substr(source.lastIndexOf('/') + 1) : 'script';
  74. errorStore.commitErrorInfoState({
  75. type: ErrorTypeEnum.SCRIPT,
  76. name: name,
  77. file: source as string,
  78. detail: 'lineno' + lineno,
  79. url: window.location.href,
  80. ...(errorInfo as Pick<ErrorInfo, 'message' | 'stack'>),
  81. });
  82. return true;
  83. }
  84. function registerPromiseErrorHandler() {
  85. window.addEventListener(
  86. 'unhandledrejection',
  87. function (event: any) {
  88. errorStore.commitErrorInfoState({
  89. type: ErrorTypeEnum.PROMISE,
  90. name: 'Promise Error!',
  91. file: 'none',
  92. detail: 'promise error!',
  93. url: window.location.href,
  94. stack: 'promise error!',
  95. message: event.reason,
  96. });
  97. },
  98. true
  99. );
  100. }
  101. function registerResourceErrorHandler() {
  102. // 监控资源加载错误(img,script,css,以及jsonp)
  103. window.addEventListener(
  104. 'error',
  105. function (e: Event) {
  106. const target = e.target ? e.target : (e.srcElement as any);
  107. errorStore.commitErrorInfoState({
  108. type: ErrorTypeEnum.RESOURCE,
  109. name: 'Resouce Error!',
  110. file: (e.target || ({} as any)).currentSrc,
  111. detail: JSON.stringify({
  112. tagName: target.localName,
  113. html: target.outerHTML,
  114. type: e.type,
  115. }),
  116. url: window.location.href,
  117. stack: 'resouce is not found',
  118. message: (e.target || ({} as any)).localName + ' is load error',
  119. });
  120. },
  121. true
  122. );
  123. }
  124. export function setupErrorHandle(app: App) {
  125. const { projectSetting } = useSetting();
  126. const { useErrorHandle } = projectSetting;
  127. if (!useErrorHandle) {
  128. return;
  129. }
  130. // Vue异常监控;
  131. app.config.errorHandler = vueErrorHandler;
  132. // js错误
  133. window.onerror = scriptErrorHandler;
  134. // promise 异常
  135. registerPromiseErrorHandler();
  136. // 静态资源异常
  137. registerResourceErrorHandler();
  138. }