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û à un changement de nom variable. La version démêlée fonctionne très bien. Cependant, je ne veux utiliser mangling nom de la variable, car elle réduit considérablement la taille de notre fichier de sortie JS.
Pour cette raison, nous utilisons ngmin dans notre processus de construction, mais cela ne semble pas résoudre ce problème, même s'il nous a bien servi dans le passé.
Donc, pour déboguer ce problème, j'ai activé les cartes sources dans notre tâche uglify grunt. Ils sont générés très bien et Chrome ne charge les cartes du serveur. Pourtant, j'obtiens toujours le même message d'erreur inutile, même si j'avais l'impression que je devrais maintenant voir le nom d'origine du fournisseur.
Comment puis-je faire en sorte que Chrome utilise les cartes sources pour me dire quel fournisseur est le problème ici, ou, alternativement, comment puis-je trouver le fournisseur d'une autre manière?
la source
Réponses:
J'adorerais toujours savoir comment j'aurais pu trouver l'emplacement dans notre code source qui a causé ce problème, mais j'ai depuis pu trouver le problème manuellement.
Il y avait une fonction de contrôleur déclarée sur la portée globale, au lieu d'utiliser un
.controller()
appel sur le module d'application.Il y avait donc quelque chose comme ça:
Cela fonctionne très bien pour AngularJS, mais pour que cela fonctionne correctement avec le mangling, j'ai dû le changer en:
Après d'autres tests, j'ai trouvé des instances de plusieurs contrôleurs qui ont également causé des problèmes. Voici comment j'ai trouvé la source de chacun d'eux manuellement :
Tout d'abord, je considère qu'il est assez important d'activer l'embellissement de la sortie dans les options uglify. Pour notre tâche difficile, cela signifiait:
J'ai ensuite ouvert le site Web du projet dans Chrome, avec les DevTools ouverts. Ce qui entraîne une erreur comme celle ci-dessous enregistrée:
La méthode de la trace d'appel qui nous intéresse est celle que j'ai marquée d'une flèche. C'est
providerInjector
dansinjector.js
. Vous allez vouloir placer un point d'arrêt où il lève une exception:Lorsque vous réexécutez maintenant l'application, le point d'arrêt est atteint et vous pouvez sauter dans la pile d'appels. Il y aura un appel de
invoke
ininjector.js
, reconnaissable à partir de la chaîne "Jeton d'injection incorrect":Le
locals
paramètre (mutiléd
dans mon code) donne une assez bonne idée de quel objet dans votre source est le problème:Un rapide
grep
sur notre source trouve de nombreuses instances demodalInstance
, mais à partir de là, il était facile de trouver cet endroit dans la source:Qui doit être changé en:
Dans le cas où la variable ne contient pas d'informations utiles, vous pouvez également sauter plus haut dans la pile et vous devriez frapper un appel
invoke
qui devrait avoir des indices supplémentaires:Empêcher que cela ne se reproduise
Maintenant que vous avez trouvé le problème avec un peu de chance, je pense que je devrais mentionner la meilleure façon d'éviter que cela ne se reproduise à l'avenir.
De toute évidence, vous pouvez simplement utiliser l' annotation de tableau en ligne partout, ou l'
$inject
annotation de propriété (selon vos préférences) et essayer simplement de ne pas l'oublier à l'avenir. Si vous le faites, assurez-vous d'activer le mode d'injection de dépendances strict , pour détecter les erreurs comme celle-ci tôt.Ou vous pouvez laisser ng-annotate s'en occuper. Je recommande vivement de le faire, car cela supprime beaucoup de risques d'erreurs dans ce domaine, comme:
Garder les annotations à jour est tout 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 .
la source
uglify({ output : { beautify : true }})
La rédaction d'Oliver Salzburg était fantastique. J'ai voté pour.
Astuce pour tous ceux qui pourraient avoir cette erreur. Le mien a simplement été causé par l'oubli de passer dans un tableau pour un contrôleur de directive:
MAUVAIS
BIEN
la source
/* @ngInject */
avant la fonction. Il semble faire la partie d'injection compliquée sans avoir besoin de taper chaque module inclus (j'utilise Yeoman)utiliser ng-strict-di avec ng-app
Si vous utilisez angulaire 1.3 vous pouvez vous sauver un monde de mal en utilisant ngStrictDi directive avec ngApp:
Maintenant - pré-minification - tout ce qui n'utilise pas d' annotations fera exploser votre console et vous pouvez voir le nom de friggin 'sans chercher à travers les traces de pile mutilées.
Selon les documents:
Une mise en garde , il détecte seulement qu'il ya des annotations, pas que les annotations sont terminées.
Sens:
Ne comprendra pas que ThingB ne fait pas partie de l'annotation.
Le mérite de cette astuce va aux gens de ng-annotate , ce qui est recommandé par rapport au ngMin désormais obsolète.
la source
Pour minimiser angulaire, tout ce que vous avez à faire est de changer votre déclaration en "mode" déclaration "tableau" par exemple:
De:
À
Comment déclarer les services d'usine?
la source
J'ai juste eu le même problème et je l'ai résolu en remplaçant simplement ngmin (maintenant obsolète) par ng-annotate pour ma tâche de construction grunt.
Il semble que yeoman angular a également été mis à jour pour utiliser ng-annotate à partir de ce commit: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb
Cependant, si vous utilisez une ancienne version de yeoman angular comme moi, remplacez simplement ng-min par ng-annotate dans votre package.json:
run
npm install
(puis éventuellementnpm prune
), et suivez les changements dans le commit pour éditerGruntfile.js
.la source
afin de savoir quel était le nom d'origine de la variable, vous pouvez modifier la façon dont uglify modifie les variables:
et maintenant l'erreur est beaucoup plus évidente
ÉDITER
Si évident maintenant ...
maintenant chaque variable est transformée en une valeur unique qui contient également l'original ... ouvrez simplement le javascript minifié et recherchez "a_orig_ $ stateProvider_91212" ou autre ... vous le verrez dans son contexte d'origine ...
ne pourrait pas être plus simple ...
la source
N'oubliez pas non plus la
resolve
propriété de l'itinéraire. Il doit également être défini comme le tableau:la source
Avec générateur-gulp-angular:
Écrivez / ** @ngInject * / avant chaque contrôleur, service, directive.
la source
Une solution rapide et sale pour cela si vous n'avez pas besoin d'Uglify pour modifier / raccourcir vos noms de variables est de définir mangle = false dans votre Gruntfile
la source