AngularJS - Stack trace ignoring source map

后端 未结 6 1720
悲&欢浪女
悲&欢浪女 2020-12-13 18:46

I\'ve written an AngularJS app but it\'s proving a bit of a nightmare to debug. I\'m using Grunt + uglify to concatenate and minify my application code. It also creates a so

6条回答
  •  [愿得一人]
    2020-12-13 19:20

    The only solution I could find is to bite the bullet and parse the source maps yourself. Here is some code that will do this. First you need to add source-map to your page. Then add this code:

    angular.module('Shared').factory('$exceptionHandler', 
    function($log, $window, $injector) {
      var getSourceMappedStackTrace = function(exception) {
        var $q = $injector.get('$q'),
            $http = $injector.get('$http'),
            SMConsumer = window.sourceMap.SourceMapConsumer,
            cache = {};
    
        // Retrieve a SourceMap object for a minified script URL
        var getMapForScript = function(url) {
          if (cache[url]) {
            return cache[url];
          } else {
            var promise = $http.get(url).then(function(response) {
              var m = response.data.match(/\/\/# sourceMappingURL=(.+\.map)/);
              if (m) {
                var path = url.match(/^(.+)\/[^/]+$/);
                path = path && path[1];
                return $http.get(path + '/' + m[1]).then(function(response) {
                  return new SMConsumer(response.data);
                });
              } else {
                return $q.reject();
              }
            });
            cache[url] = promise;
            return promise;
          }
        };
    
        if (exception.stack) { // not all browsers support stack traces
          return $q.all(_.map(exception.stack.split(/\n/), function(stackLine) {
            var match = stackLine.match(/^(.+)(http.+):(\d+):(\d+)/);
            if (match) {
              var prefix = match[1], url = match[2], line = match[3], col = match[4];
              return getMapForScript(url).then(function(map) {
                var pos = map.originalPositionFor({
                  line: parseInt(line, 10), 
                  column: parseInt(col, 10)
                });
                var mangledName = prefix.match(/\s*(at)?\s*(.*?)\s*(\(|@)/);
                mangledName = (mangledName && mangledName[2]) || '';
                return '    at ' + (pos.name ? pos.name : mangledName) + ' ' + 
                  $window.location.origin + pos.source + ':' + pos.line + ':' + 
                  pos.column;
              }, function() {
                return stackLine;
              });
            } else {
              return $q.when(stackLine);
            }
          })).then(function (lines) {
            return lines.join('\n');
          });
        } else {
          return $q.when('');
        }
      };
    
      return function(exception) {
        getSourceMappedStackTrace(exception).then($log.error);
      };
    });
    

    This code will download the source, then download the sourcemaps, parse them, and finally attempt to replace the locations in the stack trace the mapped locations. This works perfectly in Chrome, and quite acceptably in Firefox. The disadvantage is that you are adding a fairly large dependency to your code base and that you move from very fast synchronous error reporting to fairly slow async error reporting.

提交回复
热议问题