«Fournisseur inconnu: aProvider <- a» Comment trouver le fournisseur d'origine?

Lorsque je charge la version minifiée (via UglifyJS) de mon application AngularJS, j’obtiens l’erreur suivante dans la console:

Unknown provider: aProvider <- a 

Maintenant, je me rends compte que cela est dû à la confusion des noms de variables. La version non modifiée fonctionne parfaitement. Cependant, je souhaite utiliser la gestion des noms de variables, car elle réduit considérablement la taille de notre fichier de sortie JS.

Pour cette raison, nous utilisons ngmin dans notre processus de génération, mais cela ne semble pas résoudre ce problème, même si cela nous a bien servi par le passé.

Donc, pour déboguer ce problème, j’ai activé les cartes sources dans notre tâche fastidieuse. Ils sont générés correctement et Chrome charge les cartes depuis le serveur. Pourtant, je reçois toujours le même message d’erreur inutile, même si j’avais l’impression que je devais maintenant voir le nom d’origine du fournisseur.

Comment puis-je faire en sorte que Chrome utilise les cartes sources pour me dire quel est le fournisseur qui pose problème ou, sinon, comment trouver le fournisseur d’une autre manière?

Je voudrais toujours savoir comment j’aurais pu trouver l’endroit dans notre code source qui a causé ce problème, mais depuis j’ai pu trouver le problème manuellement.

Il y avait une fonction de contrôleur déclarée sur la scope globale, au lieu d’utiliser un appel à .controller() sur le module d’application.

Donc, il y avait quelque chose comme ça:

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

Cela fonctionne très bien pour AngularJS, mais pour que cela fonctionne correctement avec la manipulation, je devais le changer pour:

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

Après des tests supplémentaires, j’ai trouvé des instances de contrôleurs supplémentaires qui causaient également des problèmes. Voici comment j’ai trouvé la source de tous manuellement :

Tout d’abord, j’estime qu’il est assez important d’autoriser l’embellissement de la sortie dans les options de la solution. Pour notre tâche difficile:

 options : { beautify : true, mangle : true } 

J’ai ensuite ouvert le site web du projet dans Chrome, avec les DevTools ouverts. Ce qui se traduit par une erreur comme celle ci-dessous étant enregistrée:

entrer la description de l'image ici

La méthode dans la trace d’appel qui nous intéresse, est celle que j’ai marquée avec une flèche. Ceci est providerInjector dans injector.js . Vous allez vouloir placer un point d’arrêt où il génère une exception:

entrer la description de l'image ici

Lorsque vous relancez maintenant l’application, le point d’arrêt sera touché et vous pourrez monter la stack d’appels. Il y aura un appel de invoke in injector.js , reconnaissable à la chaîne “Incorrect injection token”:

entrer la description de l'image ici

Le paramètre locals (modifié en d dans mon code) donne une idée assez précise de l’object dans votre source:

entrer la description de l'image ici

Un grep rapide sur notre source trouve de nombreuses instances de modalInstance , mais à partir de là, il était facile de trouver cet endroit dans la source:

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

Qui doit être changé pour:

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

Si la variable ne contient pas d’informations utiles, vous pouvez également sauter plus haut dans la stack et vous devez appuyer sur un appel à invoke qui devrait avoir des indications supplémentaires:

entrer la description de l'image ici

Empêcher que cela ne se reproduise

Maintenant que vous avez trouvé le problème, je pense que je devrais mentionner comment éviter que cela ne se reproduise à l’avenir.

De toute évidence, vous pouvez simplement utiliser l’ annotation de tableau en ligne partout, ou l’ annotation de la propriété $inject (selon votre préférence) et essayez simplement de ne pas l’oublier à l’avenir. Si vous le faites, assurez-vous d’activer le mode d’dependency injection ssortingcte , afin de détecter les erreurs de ce type très tôt.

Fais attention! Si vous utilisez le Batarang angular, SsortingctDI pourrait ne pas fonctionner pour vous, car le Batarang angular injecte du code non annoté dans le vôtre (mauvais Batarang!).

Ou vous pourriez laisser ng-annoter s’en occuper. Je recommande fortement de le faire, car cela supprime beaucoup de risques d’erreurs dans ce domaine, comme:

  • Annotation DI manquante
  • Annotation DI incomplète
  • Annotation DI dans le mauvais ordre

Garder les annotations à jour est simplement une douleur dans le cul et vous ne devriez pas avoir à le faire si cela peut être fait automatiquement. ng-annotate fait exactement cela.

Il devrait s’intégrer parfaitement dans votre processus de construction avec grunt-ng-annotate et gulp-ng-annotate .

Le compte rendu de Oliver Salzburg était fantastique. Voté

Astuce pour quiconque pourrait avoir cette erreur. Le mien était simplement causé par l’oubli de passer un tableau pour un contrôleur directif:

MAL

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

BIEN

 return { ressortingct: "E", scope: { }, controller: ["$scope", ExampleDirectiveController], templateUrl: "template/url/here.html" }; 

utiliser ng-ssortingct-di avec ng-app

Si vous utilisez Angular 1.3, vous pouvez vous sauver du monde en utilisant la directive ngSsortingctDi avec ngApp:

  

Maintenant – pré-minification – tout ce qui n’utilise pas d’ annotations fera exploser votre console et vous pourrez voir le nom friggin ‘sans chercher parmi les traces de stack déchiquetées.

Par les documents:

l’application n’invoquera pas les fonctions qui n’utilisent pas d’annotation explicite de la fonction (et sont donc impropres à la minification)

Une mise en garde , il ne détecte que des annotations, pas que les annotations sont complètes.

Sens:

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

Ne comprendra pas que ThingB ne fait pas partie de l’annotation.

Le crédit pour cette astuce va aux gens ng-annotate , ce qui est recommandé sur le ngMin maintenant obsolète.

Pour minimiser un angle, il suffit de changer votre déclaration en “tableau” déclaration “mode” par exemple:

De:

 var demoApp= angular.module('demoApp', []); demoApp.controller(function demoCtrl($scope) { } ); 

À

 var demoApp= angular.module('demoApp', []); demoApp.controller(["$scope",function demoCtrl($scope) { }]); 

Comment déclarer des services d’usine?

 demoApp.factory('demoFactory', ['$q', '$http', function ($q, $http) { return { //some object }; }]); 

J’ai juste eu le même problème et l’ai résolu en remplaçant simplement ngmin (maintenant obsolète) par ng-annotate pour ma tâche de construction grognée.

Il semble que yeoman angular a également été mis à jour pour utiliser ng-annotate à partir de cette validation: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

Cependant, si vous utilisez une ancienne version de yeoman angular comme moi, remplacez ng-min par ng-annotate dans votre package.json:

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

lancez npm install (puis, éventuellement, npm prune ), et suivez les modifications de la commande pour éditer Gruntfile.js .

afin de savoir quel était le nom de la variable d’origine, vous pouvez modifier la façon dont la mue change les variables:

../node_modules/grunt-consortingb-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; [...] } }; 

et maintenant l’erreur est beaucoup plus évidente

 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  (http://example.com/:64:17), :3155:20) 

MODIFIER

Si évident maintenant …

Gruntfile.js

 uglify: { example: { options: { beautify: true, mangle: true }, [...] }, [...] } 

../node_modules/grunt-consortingb-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++; [...] } }; 

maintenant chaque variable est modifiée en une valeur unique qui contient également l’original … ouvrez simplement le javascript minifié et recherchez “a_orig_ $ stateProvider_91212” ou autre chose … vous le verrez dans son contexte d’origine …

ne pourrait pas être plus facile …

N’oubliez pas non plus la propriété de resolve de l’itinéraire. Il doit également être défini comme le tableau:

 $routeProvider.when('/foo', { resolve: { bar: ['myService1', function(myService1) { return myService1.getThis(); }], baz: ['myService2', function(myService2) { return myService2.getThat(); }] } }); 

Avec générateur-gulp-angular:

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

Write / ** @ngInject * / avant chaque contrôleur, service, directive.

Un correctif rapide et sale pour cela si vous n’avez pas besoin d’Uglify pour modifier / raccourcir vos noms de variable consiste à définir mangle = false dans votre Gruntfile

  uglify: { comstack: { options: { mangle : false, ... }, } }