AngularJS - 忽略源映射的堆栈跟踪

Tom*_*don 30 javascript angularjs source-maps

我已经编写了一个AngularJS应用程序,但它确实是一个调试的噩梦.我正在使用Grunt + uglify来连接和缩小我的应用程序代码.它还会在缩小的JS文件旁边创建源映射.

当文件中存在JS错误但在AngularJS应用程序之外时,源映射似乎正常工作.例如,如果我console.log('a.b');在其中一个文件的顶部写入,则Chrome调试器中记录的错误会显示原始文件的行+文件信息,而不是缩小的文件.

当Angular运行自己的代码出现问题时(例如在Controller代码中),会出现问题.我从Angular获得了很好的堆栈跟踪,但它只详细说明了缩小的文件而不是原始文件.

有什么办法让Angular能够确认源地图吗?

示例错误如下:

TypeError: Cannot call method 'getElement' of undefined
at Object.addMapControls (http://my-site/wp-content/plugins/my-maps/assets/js/app.min.js:1:2848)
at Object.g [as init] (http://my-site/wp-content/plugins/my-maps/assets/js/app.min.js:1:344)
at new a (http://my-site/wp-content/plugins/my-maps/assets/js/app.min.js:1:591)
at d (http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js:29:495)
at Object.instantiate (http://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js:30:123)
Run Code Online (Sandbox Code Playgroud)

Jak*_*mpl 9

我能找到的唯一解决方案是咬紧牙关并自己解析源地图.以下是一些可以执行此操作的代码.首先,您需要将source-map添加到您的页面.然后添加以下代码:

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);
  };
});
Run Code Online (Sandbox Code Playgroud)

此代码将下载源代码,然后下载源映射,解析它们,最后尝试替换堆栈中的位置跟踪映射的位置.这在Chrome中完美运行,在Firefox中非常可接受.缺点是您要向代码库添加相当大的依赖项,并且从非常快速的同步错误报告转移到相当慢的异步错误报告.

  • 这对我来说很有用,在Chrome中.我将```_. map```改为```$.map```,以便它使用jQuery而不是underscore.js.我已经有了jQuery依赖项,并且不想添加underscore.js. (2认同)

Mar*_*din 9

Larrifax的答案很好,但同一问题报告中记录了该函数的改进版本:

.config(function($provide) {

  // Fix sourcemaps
  // @url https://github.com/angular/angular.js/issues/5217#issuecomment-50993513
  $provide.decorator('$exceptionHandler', function($delegate) {
    return function(exception, cause) {
      $delegate(exception, cause);
      setTimeout(function() {
        throw exception;
      });
    };
  });
})
Run Code Online (Sandbox Code Playgroud)

这将生成两个堆栈跟踪,正如Andrew Magee 所说:一个是由Angular格式化的,另一个是由浏览器格式化的.第二个跟踪将应用源图.禁用重复项可能不是一个好主意,因为您可能还有其他Angular模块也可以使用通过委派可以在此之后调用的异常.


jra*_*ede 6

我只是遇到了同样的问题并且一直在寻找解决方案 - 显然它是一般的堆栈跟踪的Chrome问题,并且恰好适用于Angular,因为它在错误报告中使用堆栈跟踪.看到:

Google Chrome中的源映射是否会推送到Error.stack