angularjs - source - "Proveedor desconocido: aProvider<- a" ¿Cómo puedo encontrar el proveedor original?
webpack devtool option (9)
usa ng-strict-di con ng-app
Si está usando Angular 1.3, puede ahorrarse un mundo de dolor al usar la directiva ngStrictDi con ngApp:
<html lang="en" ng-app="myUglifiablyGreatApp" ng-strict-di>
Ahora, pre-minificación, cualquier cosa que no use anotaciones volará tu consola y podrás ver el nombre sin tener que buscar rastros de pila destrozados.
Por los documentos:
la aplicación no podrá invocar funciones que no utilizan la anotación explícita de funciones (y por lo tanto no son aptas para la minificación)
Una advertencia , solo detecta que hay anotaciones, no que las anotaciones estén completas.
Sentido:
[''ThingOne'', function(ThingA, ThingB) { … }]
No captará que ThingB no es parte de la anotación.
El crédito para este consejo va para la gente de ng-annotate , que se recomienda sobre el ngMin ahora en desuso.
Cuando estoy cargando la versión minified (a través de UglifyJS) de mi aplicación AngularJS, aparece el siguiente error en la consola:
Unknown provider: aProvider <- a
Ahora, me doy cuenta de que esto se debe al cambio de nombre de variable. La versión sin sistema funciona bien. Sin embargo, sí quiero utilizar el cambio de nombre de variable, ya que reduce drásticamente el tamaño de nuestro archivo de salida JS.
Por esa razón, estamos usando ngmin en nuestro proceso de compilación, pero no parece resolver este problema, a pesar de que nos sirvió en el pasado.
Por lo tanto, para solucionar este problema, habilité los mapas de origen en nuestra tarea uglify grunt. Se generan muy bien y Chrome carga los mapas desde el servidor. Sin embargo, recibo el mismo mensaje de error inútil, a pesar de que tenía la impresión de que ahora debería ver el nombre original del proveedor.
¿Cómo hago para que Chrome use los mapas de origen para decirme qué proveedor es el problema aquí o, como alternativa, cómo puedo averiguar el proveedor de otra manera?
Acabo de tener el mismo problema y lo resolví simplemente reemplazando ngmin (ahora obsoleto) con ng-anotación para mi tarea de compilación grunt.
Parece que yeoman angular también se ha actualizado para usar ng-anotación a partir de este compromiso: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb
Sin embargo, si está utilizando una versión anterior de yeoman angular como yo, simplemente reemplace ng-min con ng-anotación en su paquete. Json:
- "grunt-ngmin": "^0.0.3",
+ "grunt-ng-annotate": "^0.3.0",
Ejecute npm install
(luego opcionalmente npm prune
) y siga los cambios en la https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb para editar Gruntfile.js
.
Además, no olvides la propiedad de resolve
de la ruta. También debe definirse como la matriz:
$routeProvider.when(''/foo'', {
resolve: {
bar: [''myService1'', function(myService1) {
return myService1.getThis();
}],
baz: [''myService2'', function(myService2) {
return myService2.getThat();
}]
}
});
Con generador-trago-angular:
/** @ngInject */
function SomeController($scope, myCoolService) {
}
Escriba / ** @ngInject * / antes de cada controlador, servicio, directiva.
La reseña de Oliver Salzburg fue fantástica. Upvoted.
Sugerencia para cualquier persona que pueda tener este error. La mía simplemente fue causada al olvidar pasar una matriz por un controlador de directiva:
MALO
return {
restrict: "E",
scope: {
},
controller: ExampleDirectiveController,
templateUrl: "template/url/here.html"
};
BUENO
return {
restrict: "E",
scope: {
},
controller: ["$scope", ExampleDirectiveController],
templateUrl: "template/url/here.html"
};
Para miniaturizar todo lo que necesita hacer es cambiar su declaración al "modo" de declaración "array", por ejemplo:
De:
var demoApp= angular.module(''demoApp'', []);
demoApp.controller(function demoCtrl($scope) {
} );
A
var demoApp= angular.module(''demoApp'', []);
demoApp.controller(["$scope",function demoCtrl($scope) {
}]);
¿Cómo declarar los servicios de fábrica?
demoApp.factory(''demoFactory'', [''$q'', ''$http'', function ($q, $http) {
return {
//some object
};
}]);
Todavía me encantaría saber cómo pude haber encontrado el lugar en nuestro código fuente que causó este problema, pero desde entonces pude encontrar el problema manualmente.
Hubo una función de controlador declarada en el ámbito global, en lugar de utilizar una llamada .controller()
en el módulo de la aplicación.
Entonces hubo algo como esto:
function SomeController( $scope, i18n ) { /* ... */ }
Esto funciona bien para AngularJS, pero para hacer que funcione bien con la manipulación, tuve que cambiarlo a:
var applicationModule = angular.module( "example" );
function SomeController( $scope, i18n ) { /* ... */ }
applicationModule.controller( "SomeController", [ "$scope", "i18n", SomeController ] );
Después de más pruebas, encontré instancias de más controladores que también causaban problemas. Así es como encontré la fuente de todos ellos de forma manual :
En primer lugar, considero bastante importante habilitar el embellecimiento de resultados en las opciones de uglify. Para nuestra tarea gruñona eso significaba:
options : {
beautify : true,
mangle : true
}
Luego abrí el sitio web del proyecto en Chrome, con DevTools abierto. Lo que da como resultado un error como el que se registra a continuación:
El método en el seguimiento de llamadas que nos interesa es el que marqué con una flecha. Este es providerInjector
en injector.js
. Querrá colocar un punto de interrupción donde arroje una excepción:
Cuando vuelva a ejecutar la aplicación, se golpeará el punto de interrupción y podrá saltar la pila de llamadas. Habrá una llamada de invoke
en injector.js
, reconocible desde la cadena "Token de inyección incorrecta":
El parámetro locals
(destrozado a d
en mi código) da una idea bastante buena sobre qué objeto en tu fuente es el problema:
Un grep
rápido sobre nuestra fuente encuentra muchas instancias de modalInstance
, pero a partir de ahí, fue fácil encontrar este lugar en la fuente:
var ModalCreateEditMeetingController = function( $scope, $modalInstance ) {
};
Que debe ser cambiado a:
var ModalCreateEditMeetingController = [ "$scope", "$modalInstance", function( $scope, $modalInstance ) {
} ];
En caso de que la variable no contenga información útil, también puede saltar más arriba en la pila y debe presionar una llamada para invoke
que debería tener sugerencias adicionales:
Evita que esto vuelva a pasar
Ahora que con suerte ha encontrado el problema, creo que debería mencionar cómo evitar que vuelva a suceder en el futuro.
Obviamente, puede usar la anotación de matriz en línea en todas partes, o la anotación de propiedad $inject
(según su preferencia) y simplemente tratar de no olvidarlo en el futuro. Si lo hace, asegúrese de habilitar el modo de inyección de dependencia estricta para detectar errores como este antes de tiempo.
¡Cuidado! En caso de que esté usando Angular Batarang, StrictDI podría no funcionar para usted, ya que Angular Batarang inyecta un código no anotado en el suyo (¡Batarang malo!).
O podrías dejar que ng-annotate se encargue de eso. Recomiendo hacerlo, ya que elimina un gran potencial de errores en esta área, como:
- Falta anotación DI
- Anotación DI incompleta
- Anotación DI en orden incorrecto
Mantener las anotaciones actualizadas es simplemente una molestia y no debería tener que hacerlo si puede hacerse automáticamente. ng-annotate hace exactamente eso.
Debe integrarse muy bien en su proceso de compilación con grunt-ng-annotate y gulp-ng-annotate .
Una solución rápida y sucia para esto si no necesita Uglify para modificar / acortar sus nombres de variable es configurar mangle = false en su Gruntfile
uglify: {
compile: {
options: {
mangle : false,
...
},
}
}
para saber cuál era el nombre de la variable original, puedes cambiar cómo uglify modifica las variables:
../node_modules/grunt-contrib-uglify/node_modulesuglify-js/lib/scope.js
SymbolDef.prototype = {
unmangleable: [...],
mangle: function(options) {
[...]
this.mangled_name = s.next_mangled(options, this)+"_orig_"+this.orig[0].name;
[...]
}
};
y ahora el error es mucho más obvio
Error: [$injector:unpr] Unknown provider: a_orig_$stateProvider
http://errors.angularjs.org/1.3.7/$injector/unpr?p0=a_orig_%24stateProvider
at eval (eval at <anonymous> (http://example.com/:64:17), <anonymous>:3155:20)
EDITAR
Tan obvio ahora ...
Gruntfile.js
uglify: {
example: {
options: {
beautify: true,
mangle: true
},
[...]
},
[...]
}
../node_modules/grunt-contrib-uglify/node_modulesuglify-js/lib/scope.js
var numberOfVariables = 1;
SymbolDef.prototype = {
unmangleable: [...],
mangle: function(options) {
[...]
this.mangled_name = s.next_mangled(options, this)+"_orig_"+this.orig[0].name+"_"+numberOfVariables++;
[...]
}
};
ahora cada variable está destrozada a un valor único que también contiene el original ... solo abre el javascript minificado y busca "a_orig_ $ stateProvider_91212" o lo que sea ... lo verás en su contexto original ...
no podría ser más fácil ...