"Proveedor desconocido: aProvider < - a" ¿Cómo puedo encontrar el proveedor original?


Cuando estoy cargando la versión minificada (a través de UglifyJS) de mi aplicación AngularJS, obtengo el siguiente error en la consola:

Unknown provider: aProvider <- a

Ahora, me doy cuenta de que esto se debe a la alteración del nombre de la variable. La versión desenfocada funciona muy bien. Sin embargo, yo quiero hacer uso de la alteración de nombres de variables, 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 esto problema, a pesar de que nos sirvió bien en el pasado.

Entonces, para depurar este problema, habilité los mapas de origen en nuestra tarea uglify grunt. Se generan muy bien y Chrome hace cargar los mapas desde el servidor. Sin embargo, todavía 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 puedo hacer que Chrome use los mapas de origen para decirme qué proveedor es el problema aquí, o, alternativamente, ¿cómo puedo encontrar el proveedor de otra manera?

Author: Der Hochstapler, 2014-02-11

9 answers

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 he sido capaz de encontrar el problema manualmente.

Hubo una función de controlador declarada en el ámbito global, en lugar de usar una llamada .controller() en el módulo de la aplicación.

Así que había algo como esto: {[17]]}

function SomeController( $scope, i18n ) { /* ... */ }

Esto funciona muy bien para AngularJS, pero para que funcione bien con la mutilación, tuve que cambiarlo a:{[17]]}

var applicationModule = angular.module( "example" );
function SomeController( $scope, i18n ) { /* ... */ }
applicationModule.controller( "SomeController", [ "$scope", "i18n", SomeController ] );

Después de más pruebas, en realidad encontré instancias de más controladores que también causaron problemas. Así es como encontré la fuente de todos ellos manualmente :

En primer lugar, considero que es bastante importante habilitar el embellecimiento de salida en las opciones uglify. Para nuestra tarea de gruñido que significaba:

options : {
    beautify : true,
    mangle   : true
}

Luego abrí el sitio web del proyecto en Chrome, con los DevTools abiertos. Lo que resulta en un error como el siguiente que se registra:

introduzca la descripción de la imagen aquí

El método en la llamada el rastro que nos interesa es el que marcé con una flecha. Este es providerInjector en injector.js. Vas a querer colocar un punto de interrupción donde lanza una excepción:

introduzca la descripción de la imagen aquí

Cuando vuelva a ejecutar la aplicación, se alcanzará el punto de interrupción y podrá saltar a la pila de llamadas. Habrá una llamada de invoke en injector.js, reconocible por la cadena "token de inyección incorrecta":

introduzca la descripción de la imagen aquí

El parámetro locals (mutilado a d en mi código) da una idea bastante buena sobre qué objeto en su fuente es el problema:

introduzca la descripción de la imagen aquí

Un rápido grep sobre nuestra fuente encuentra muchos ejemplos de modalInstance, pero yendo desde allí, fue fácil encontrar este punto en la fuente:{[17]]}

var ModalCreateEditMeetingController = function( $scope, $modalInstance ) {
};

Que debe cambiarse 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 realizar una llamada a invoke que debe tener información adicional consejos:

introduzca la descripción de la imagen aquí

Evitar que esto suceda de nuevo

Ahora que espero haber encontrado el problema, siento que debo mencionar la mejor manera de evitar que esto vuelva a suceder en el futuro.

Obviamente, podría usar la anotación de matriz inline en todas partes, o la (dependiendo de su preferencia) $inject anotación de propiedad y simplemente trate de no olvidarlo en el futuro. Si lo hace, asegúrese de habilitar strict modo de inyección de dependencias , para detectar errores como este temprano.

¡cuidado! En caso de que estés usando Angular Batarang, StrictDI podría no funcionar para ti, ya que Angular Batarang inyecta código no anotado en el tuyo (¡bad Batarang!).

O puedes dejar que ng-annotate se encargue de ello. Recomiendo encarecidamente hacerlo, ya que elimina una gran cantidad de posibles errores en esta área, como:

  • falta la anotación de DI
  • DI anotación incompleto
  • DI anotación en orden incorrecto

Mantener las anotaciones actualizadas es simplemente un dolor en el culo y no debería tener que hacerlo si se puede hacer automáticamente. ng-annotate hace exactamente eso.

Debería integrarse bien en su proceso de compilación con grunt-ng-annotate y gulp-ng-annotate.

 186
Author: Der Hochstapler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-21 12:24:10

El artículo de Oliver Salzburg fue fantástico. Votaron a favor.

Consejo para cualquiera que pueda tener este error. La mía fue simplemente causada por olvidarse de pasar una matriz para un controlador de directiva:

MAL

return {
    restrict: "E",
    scope: {                
    },
    controller: ExampleDirectiveController,
    templateUrl: "template/url/here.html"
};

BUENO

return {
    restrict: "E",
    scope: {                
    },
    controller: ["$scope", ExampleDirectiveController],
    templateUrl: "template/url/here.html"
};
 30
Author: Ash Clarke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-15 11:58:15

Use ng-strict-di con ng-app

Si estás usando Angular 1.3 puedes salvarte un mundo de dolor usando ngStrictDi directiva 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 puedes ver el maldito nombre sin buscar a través de rastros de pila destrozados.

Según los documentos:

La aplicación fallará al invocar funciones que no utilicen explícitamente anotación de función (y por lo tanto no son adecuados para la minificación)

Una advertencia , solo detecta que hay anotaciones, no que las anotaciones estén completas.

Significado:

['ThingOne', function(ThingA, ThingB) { … }]

No captará que ThingB no es parte de la anotación.

El crédito por este consejo va a la gente ng-annotate, que se recomienda sobre la ahora obsoleta ngMin.

 25
Author: Mark Fox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-06 03:54:14

Para reducir angular todo lo que necesita es cambiar su declaración a la declaración" array ""mode" 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
    };
}]);
 11
Author: Dalorzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-10 22:05:53

Acabo de tener el mismo problema y lo resolví simplemente reemplazando ngmin (ahora obsoleto) con ng-annotate para mi tarea de compilación de grunt.

Parece que yeoman angular también ha sido actualizado para usar ng-annotate a partir de este commit: 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-annotate en su paquete.json:

-    "grunt-ngmin": "^0.0.3",
+    "grunt-ng-annotate": "^0.3.0",

Ejecutar npm install (luego opcionalmente npm prune), y siga los cambios en el commit para editar Gruntfile.js.

 8
Author: Xuwen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-24 09:36:05

Para saber cuál era el nombre original de la variable, puede cambiar la forma en que uglify manipula 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 es destrozado a un valor único que también contiene el original... simplemente abra el javascript minificado y busque "a_orig_ stat stateProvider_91212" o lo que sea... lo verás en su contexto original...

No podría ser más fácil...

 7
Author: user3338098,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-04 19:34:30

Tampoco olvide la propiedad resolve de la ruta. También debe definirse como el array:

$routeProvider.when('/foo', {
    resolve: {
        bar: ['myService1', function(myService1) {
            return myService1.getThis();
        }],
        baz: ['myService2', function(myService2) {
            return myService2.getThat();
        }]
    }
});
 4
Author: Petr Felzmann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-25 14:23:37

Con generador-gulp-angular:

   /** @ngInject */
    function SomeController($scope, myCoolService) {

}

Escriba /** @ngInject */ antes de cada controlador, servicio, directiva.

 3
Author: Maxim Danilov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-29 08:27:41

Una solución rápida y sucia para esto si no requiere Uglify para mangle/acortar sus nombres de variables es establecer mangle = false en su Gruntfile

    uglify: {
        compile: {
            options: {
                mangle   : false,
                ...
            },
        }
    }
 2
Author: Parris Varney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-19 18:09:28