javascript - source - what are map files
AngularJS-Seguimiento de pila ignorando el mapa fuente (6)
Acabo de tener el mismo problema y he estado buscando una solución. Al parecer, es un problema de Chrome con los seguimientos de pila en general y resulta que se aplica a Angular porque utiliza rastreos de pila en los informes de errores. Ver:
He escrito una aplicación AngularJS pero está resultando ser una pesadilla para depurar. Estoy usando Grunt + uglify para concatenar y minimizar el código de mi aplicación. También crea un mapa fuente junto con el archivo JS minificado.
El mapa fuente parece funcionar correctamente cuando hay un error JS en el archivo, pero fuera de la aplicación AngularJS. por ejemplo, si escribo console.log(''a.b'');
en la parte superior de uno de los archivos, el error registrado en el depurador de Chrome muestra información de línea + archivo para el archivo original, no el archivo modificado.
El problema ocurre cuando hay un problema con el código que Angular se ejecuta a sí mismo (por ejemplo, en el código del Controlador). Obtengo un buen seguimiento de pila de Angular, pero solo detalla el archivo minimizado, no el original.
¿Hay algo que pueda hacer para que Angular reconozca el mapa de origen?
Ejemplo de error a continuación:
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)
Como el error se corrigió en Chrome (pero el problema persiste en Angular), una solución que no imprime el seguimiento de la pila dos veces sería la siguiente:
app.factory(''$exceptionHandler'', function() {
return function(exception, cause) {
console.error(exception.stack);
};
});
La única solución que podría encontrar es morder la bala y analizar los mapas fuente usted mismo. Aquí hay un código que hará esto. Primero necesitas agregar source-map a tu página. A continuación, agregue este código:
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);
};
});
Este código descargará la fuente, luego descargará los mapas fuente, los analizará, y finalmente intentará reemplazar las ubicaciones en la pila para rastrear las ubicaciones mapeadas. Esto funciona perfectamente en Chrome, y bastante aceptable en Firefox. La desventaja es que está agregando una dependencia bastante grande a su base de códigos y que pasa de informes de errores sincrónicos muy rápidos a informes de errores asincrónicos bastante lentos.
La answer de Larrifax es buena, pero hay una versión mejorada de la función documentada en el mismo informe de problemas :
.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;
});
};
});
})
Esto generará dos rastros de pila, como lo noted Andrew Magee: uno formateado por Angular y luego otro formateado por el navegador. La segunda traza aplicará sourcemaps. Probablemente no sea una buena idea deshabilitar los duplicados, ya que es posible que tenga otros módulos Angular que también funcionan con excepciones que podrían llamarse después de esto a través de la delegación.
Me gustaría echar un vistazo al siguiente proyecto: https://github.com/novocaine/sourcemapped-stacktrace
Hace esencialmente lo mismo que la respuesta de @ jakub-hampl, pero podría ser útil.
Según este problema , parece que $logProvider
Angular rompe el mapeo de fuente. Una solución como esta se sugiere en el problema:
var module = angular.module(''source-map-exception-handler'', [])
module.config(function($provide) {
$provide.decorator(''$exceptionHandler'', function($delegate) {
return function(exception, cause) {
$delegate(exception, cause);
throw exception;
};
});
});