"未知提供商:aProvider < - a"我如何找到原始提供商?

Der*_*ler 99 google-chrome uglifyjs angularjs source-maps

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

Unknown provider: aProvider <- a
Run Code Online (Sandbox Code Playgroud)

现在,我意识到这是由于变量名称错误造成的.unmangled版本工作得很好.但是,我确实希望使用变量名称修改,因为它大大减少了我们的JS输出文件的大小.

出于这个原因,我们在构建过程中使用了ngmin,但它似乎并没有解决这个问题,尽管它在过去很好地帮助了我们.

因此,为了调试此问题,我在uglify grunt任务中启用了源映射.它们生成得很好,Chrome 从服务器加载地图.然而,我仍然得到同样无益的错误信息,即使我的印象是我现在应该看到提供者的原始名称.

如何让Chrome使用源地图告诉我这里的问题是哪个提供商,或者,我怎样才能以其他方式找到提供商?

Der*_*ler 191

我仍然希望知道我怎么能找到我们的源代码,导致此问题的地方,但因为我已经能够手动查找问题.

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

所以有这样的事情:

function SomeController( $scope, i18n ) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

这对于AngularJS来说效果很好,但为了使它能够正确处理,我不得不将其更改为:

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

在进一步测试之后,我实际上发现了更多控制器的实例也导致了问题.这就是我手动找到所有这些源的方法:

首先,我认为在uglify选项中启用输出美化非常重要.对于我们的grunt任务意味着:

options : {
    beautify : true,
    mangle   : true
}
Run Code Online (Sandbox Code Playgroud)

然后,我在Chrome中打开了项目网站,DevTools打开了.这导致如下记录的错误:

在此输入图像描述

我们感兴趣的呼叫追踪中的方法是我用箭头标记的方法.这是providerInjectorinjector.js.您将要在它抛出异常的位置放置断点:

在此输入图像描述

当您现在重新运行应用程序时,将触发断点,您可以跳转调用堆栈.将有来自invokeininjector.js的调用,可从"不正确的注入令牌"字符串中识别:

在此输入图像描述

locals参数(错位,以d我的代码)给出了一个不错的主意,哪些对象在源的问题是:

在此输入图像描述

快速浏览grep我们的源代码可以找到许多实例modalInstance,但是从那里开始,很容易在源代码中找到这个位置:

var ModalCreateEditMeetingController = function( $scope, $modalInstance ) {
};
Run Code Online (Sandbox Code Playgroud)

必须更改为:

var ModalCreateEditMeetingController = [ "$scope", "$modalInstance", function( $scope, $modalInstance ) {
} ];
Run Code Online (Sandbox Code Playgroud)

如果变量没有保存有用的信息,你也可以进一步向上跳转,你应该打一个invoke应该有其他提示的调用:

在此输入图像描述

防止这种情况再次发生

既然你有希望找到问题,我觉得我应该提一下如何在将来再次发生这种情况.

显然,您可以在任何地方使用内联数组注释,或者(取决于您的偏好)$inject属性注释,并且尽量不要在将来忘记它.如果这样做,请确保启用严格依赖注入模式,以尽早捕获这样的错误.

小心!如果您正在使用Angular Batarang,StrictDI可能不适合您,因为Angular Batarang会将未经注释的代码注入您的内容(糟糕的Batarang!).

或者你可以让ng-annotate来处理它.我强烈建议这样做,因为它消除了很多这方面的错误,例如:

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

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

它应该与grunt-ng-annotategulp-ng-annotate很好地集成到你的构建过程中.

  • 这是一篇精彩的文章,写得很谨慎.我刚刚遇到这个问题,似乎是某个地方的ngmin问题.你的提示帮助我知道在哪里看.最后我只是"阵列式"所有我的角度参数,问题就消失了.所有先前的构建都很简单,没有什么大的改变.我没有添加任何全局函数 - 它只是通过修改一些控制器/指令/服务/过滤器而神秘地停止工作? (12认同)
  • 在我的情况下,它是指令中的控制器.如果在'd'变量中你会看到$ attr,那可能是同样的问题.你应该将params包装在内部指令控制器的数组括号中.controller:["$ scope",function($ scope){...}]而不是controller:function($ scope){...} (4认同)
  • 你是天赐之物. (2认同)

Ash*_*rke 30

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

提示可能有此错误的任何人.我只是因为忘记为指令控制器传入数组而导致:

return {
    restrict: "E",
    scope: {                
    },
    controller: ExampleDirectiveController,
    templateUrl: "template/url/here.html"
};
Run Code Online (Sandbox Code Playgroud)

return {
    restrict: "E",
    scope: {                
    },
    controller: ["$scope", ExampleDirectiveController],
    templateUrl: "template/url/here.html"
};
Run Code Online (Sandbox Code Playgroud)

  • 这是一个如此厚颜无耻的......在最近的更新之前,Uglify并没有对我造成这种情况! (2认同)

Mar*_*Fox 25

将ng-strict-di与ng-app一起使用

如果你正在使用Angular 1.3,那么通过在ngApp中使用ngStrictDi指令可以为自己节省一个伤害的世界:

<html lang="en" ng-app="myUglifiablyGreatApp" ng-strict-di>
Run Code Online (Sandbox Code Playgroud)

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

根据文档:

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

有一点需要注意,它只能检测到有注解,而不是注释是完整的.

含义:

['ThingOne', function(ThingA, ThingB) { … }]
Run Code Online (Sandbox Code Playgroud)

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

这个提示的功劳归于ng-annotate人,推荐使用现已弃用的ngMin.


Dal*_*rzo 11

要缩小角度,您需要做的就是将声明更改为"数组"声明"模式",例如:

从:

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

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

如何申报工厂服务?

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

  • 我*以这种方式创建我们的代码.但我们有外部依赖,但没有.ngmin过去很好地解决了这个问题.我假设最近的一次更改造成了这个问题.我现在想找到这个问题的来源,以便我可以在我们的代码,我们的依赖或可能在ngmin本身中正确地修复它. (3认同)

小智 8

我只是遇到了同样的问题并通过简单地用ng-annotate替换ngmin(现已弃用)来解决它我的grunt构建任务.

似乎yeoman angular也已更新为使用ng-annotate作为此提交:https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

但是如果你像我一样使用较旧版本的yeoman角度,只需在你的package.json中用ng-annotate替换ng-min:

-    "grunt-ngmin": "^0.0.3",
+    "grunt-ng-annotate": "^0.3.0",
Run Code Online (Sandbox Code Playgroud)

运行npm install(然后可选npm prune),并按照提交中的更改进行编辑Gruntfile.js.


use*_*098 7

为了知道原始变量名称是什么,您可以更改uglify如何修改变量:

../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;
    [...]
  }
};
Run Code Online (Sandbox Code Playgroud)

现在错误更明显了

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)
Run Code Online (Sandbox Code Playgroud)

编辑

现在很明显......

Gruntfile.js

uglify: {
  example: {
    options: {
      beautify: true,
      mangle: true
    },
    [...]
  },
  [...]
}
Run Code Online (Sandbox Code Playgroud)

../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++;
    [...]
  }
};
Run Code Online (Sandbox Code Playgroud)

现在每个变量都被修改为一个唯一的值,它也包含原始...只需打开缩小的javascript并搜索"a_orig_ $ stateProvider_91212"或者其他......你会在它的原始上下文中看到它...

再也不容易了......