“未知提供者:aProvider < – a”我如何find原始提供者?

当我加载AngularJS应用程序的缩小版(通过UglifyJS)时,在控制台中出现以下错误:

Unknown provider: aProvider <- a 

现在,我意识到这是由于variables名称的改变。 unmangled版本工作得很好。 但是,我确实想要使用variables名称,因为它大大减less了我们的JS输出文件的大小。

出于这个原因,我们在构build过程中使用ngmin ,但似乎并没有解决这个问题,即使它在过去也很好。

所以,为了debugging这个问题,我在uglify grunt任务中启用了源映射。 它们生成得很好,而Chrome则从服务器加载映射。 然而,即使我觉得现在应该看到提供者的原始名称,我仍然得到了同样无益的错误信息。

我如何让Chrome使用源地图来告诉我哪个提供者是这里的问题,或者,如何以另一种方式找出提供者?

我仍然很想知道如何在我们的源代码中find导致此问题的地方,但是我已经能够手动find问题了。

在全局范围声明了一个控制器函数,而不是在应用程序模块上使用.controller()调用。

所以有这样的事情:

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

这对AngularJS来说工作得很好,但为了使它正确地工作,我必须改变它:

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

经过进一步的testing,我发现更多的控制器的实例,也造成了问题。 这是我如何手动find他们的来源:

首先,我认为在uglify选项中启用输出美化是相当重要的。 对于我们的咕task任务意味着:

 options : { beautify : true, mangle : true } 

然后在Chrome中打开项目网站,DevTools打开。 这会导致如下所示的错误被logging:

在这里输入图像说明

我们感兴趣的呼叫跟踪中的方法是我用箭头标记的方法。 这是injector.js providerInjector 。 你将要在抛出exception的地方放置一个断点:

在这里输入图像说明

当你现在重新运行应用程序时,断点将会被触发,你可以跳转调用堆栈。 在inject.js中会有一个调用,可以从“Incorrect injection token”string中识别出来:

在这里输入图像说明

locals参数(在我的代码中改为d )给出了一个关于源代码中的哪个对象是问题的相当好的想法:

在这里输入图像说明

对我们的源代码的一个快速的grepfind了modalInstance许多实例,但是从那里开始,很容易在源代码中find这个点:

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

其中必须更改为:

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

如果variables没有保存有用的信息,你也可以进一步向上跳转,你应该打一个调用来invoke哪个应该有额外的提示:

在这里输入图像说明

防止这种情况再次发生

现在你已经希望find问题了,我觉得我应该提到如何最好的避免这种情况再发生。

很明显,你可以在任何地方使用内联数组注释 ,或者使用(根据你的偏好) $inject属性注释,并且尽量不要在将来忘记它。 如果你这样做,一定要启用严格的dependency injection模式 ,以尽早发现错误。

小心! 如果您使用的是Angular Batarang,那么StrictDI可能不适合您,因为Angular Batarang会将未经注释的代码注入您的(不好的Batarang!)。

或者你可以让ng-annotate照顾它。 我强烈build议这样做,因为这消除了这方面的很多潜在的错误,例如:

  • DI注释缺失
  • DI注释不完整
  • DI注释错误顺序

保持注释是最新的只是一个痛苦的屁股,你不应该这样做,如果它可以自动完成。 ng-annotate就是这样做的。

它应该用grunt-ng-annotate和gulp-ng-annotate很好地集成到你的构build过程中。

奥利弗·萨尔茨堡的写作太棒了。 Upvoted。

提示任何可能有此错误的人。 我只是因为忘记把一个数组传递给一个指令控制器而造成的:

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

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

在ng-app中使用ng-strict-di

如果您使用的是Angular 1.3,那么可以使用ngApp的ngStrictDi指令来保存自己的世界:

 <html lang="en" ng-app="myUglifiablyGreatApp" ng-strict-di> 

现在 – 预缩小化 – 任何使用注释的东西都会炸毁你的控制台你可以看到friggin的名字,而不需要通过损坏的堆栈跟踪。

根据文档:

应用程序将无法调用不使用显式函数注释的函数(因此不适合缩小)

一个警告 ,它只能检测到有注释,而不是注释是完整的。

含义:

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

不会发现ThingB不是注释的一部分。

这个技巧的信用转到ng注释的人,build议通过现在不赞成的ngMin。

为了减小angular度,你所需要做的就是把你的声明改成“数组”声明“模式”,例如:

从:

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

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

如何申报工厂服务?

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

我只是遇到了同样的问题,只需用ng-annotatereplacengmin(现在不赞成使用)就可以解决问题。

看起来yeoman angular也已经更新为使用ng-annotate作为这个提交: https : //github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

但是,如果你像我一样使用老版本的yeomanangular色,只需在你的package.json中用ng-annotatereplaceng-min:

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

运行npm install (然后selectnpm prune ),然后按照提交中的更改来编辑Gruntfile.js

为了知道原来的variables名是什么,你可以改变uglify如何破坏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; [...] } }; 

现在的错误更为明显

 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) 

编辑

现在很明显

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++; [...] } }; 

现在每个variables被摧毁到一个独特的值,也包含原来的…只是打开缩小的JavaScript和search“a_orig_ $ stateProvider_91212”或其他…你会看到它的原始上下文…

不能再简单了…

另外不要忘记路由的resolve属性。 它也必须被定义为数组:

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

如果你不需要Uglify来修改/缩短你的variables名,那么这个快速而脏的修正就是在你的Gruntfile中设置mangle = false

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

随着发电机吞咽angular:

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

在每个控制器,服务,指令之前写入/ ** @ngInject * /