web-dev-qa-db-ja.com

「不明なプロバイダー:aProvider <-a」元のプロバイダーを見つけるにはどうすればよいですか?

AngularJSアプリケーションの縮小版(UglifyJS経由)をロードすると、コンソールに次のエラーが表示されます。

Unknown provider: aProvider <- a

今、私はこれが変数名のマングリングによるものであることを理解しています。マングルされていないバージョンは問題なく動作します。ただし、私doは、JS出力ファイルのサイズを大幅に削減するため、変数名のマングリングを使用したいと考えています。

そのため、ビルドプロセスで ngmin を使用していますが、過去にはうまく機能していましたが、この問題を解決するようには見えません。

そのため、この問題をデバッグするために、uglify gruntタスクでソースマップを有効にしました。それらは正常に生成され、Chromedoesがサーバーからマップをロードします。それでも、プロバイダーの元の名前が表示されるようになったという印象を受けていたにもかかわらず、やはり同じ役に立たないエラーメッセージが表示されます。

ソースマップを使用してChromeを取得し、ここで問題のプロバイダーを特定する方法、または別の方法でプロバイダーを見つける方法を教えてください。

99
Der Hochstapler

この問題の原因となったソースコード内の場所をどのようにして見つけることができたかを知りたいのですが、それ以来、手動で問題を見つけることができました。

アプリケーションモジュールで.controller()呼び出しを使用する代わりに、グローバルスコープで宣言されたコントローラー関数がありました。

そのため、次のようなものがありました。

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

これはAngularJSではうまく機能しますが、マングリングで正しく機能させるために、次のように変更する必要がありました。

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

さらにテストを重ねた結果、実際に問題を引き起こしたコントローラーのインスタンスがさらに見つかりました。これは私がそれらすべてのソースを見つけた方法です手動で

まず、uglifyオプションで出力美化を有効にすることがかなり重要だと思います。私たちの単調な仕事のために:

options : {
    beautify : true,
    mangle   : true
}

次に、DevToolsを開いて、プロジェクトのWebサイトをChromeで開きました。これにより、以下のようなエラーがログに記録されます。

enter image description here

私たちが興味を持っている呼び出しトレースのメソッドは、私が矢印でマークしたものです。これは、injector.jsproviderInjector です。例外をスローする場所にブレークポイントを配置する必要があります。

enter image description here

アプリケーションを再実行すると、ブレークポイントにヒットし、コールスタックをジャンプできます。 injector.jsinvokeからの呼び出しがあります 、 "Incorrect injection token"文字列から認識可能:

enter image description here

localsパラメーター(私のコードではdにマングルされています)は、ソース内のどのオブジェクトが問題であるかについてかなり良いアイデアを提供します。

enter image description here

ソース上で簡単なgrepmodalInstanceの多くのインスタンスを見つけますが、そこから行くと、ソースでこの場所を見つけるのは簡単でした:

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

次のように変更する必要があります。

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

変数が有用な情報を保持していない場合、スタックをさらにジャンプして、追加のヒントが必要なinvokeの呼び出しをヒットする必要があります。

enter image description here

これが再び起こらないようにする

うまくいけば問題を発見できたので、今後この問題が再発しないようにするにはどうすればよいかを説明する必要があると思います。

明らかに、 インライン配列注釈 どこでも、または(好みに応じて) $injectプロパティ注釈 を使用して、将来的にはそれを忘れないようにしてください。その場合は、 厳密な依存関係注入モードを有効にしてください 、このようなエラーを早期にキャッチします。

気を付けて! Angular Batarangを使用している場合は、Angular Batarangが注釈のないコードを自分のコードに挿入するため(悪いBatarang!)、StrictDIが機能しない可能性があります。

またはng-annotate の世話をすることができます。次のように、この領域でのミスの多くの可能性を排除するので、そうすることを強くお勧めします。

  • DI注釈がありません
  • DI注釈が不完全です
  • 間違った順序のDI注釈

注釈を最新の状態に保つことは、単にお尻の痛みであり、自動的に実行できる場合は実行する必要はありません。 ng-annotateはまさにそれを行います。

grunt-ng-annotate および gulp-ng-annotate を使用すると、ビルドプロセスにうまく統合されるはずです。

191
Der Hochstapler

オリバー・ザルツブルクの記事は素晴らしかった。賛成。

このエラーが発生する可能性のある人へのヒント。私の原因は、単純にディレクティブコントローラーの配列を渡すのを忘れたことです。

悪い

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

良い

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

ng-appでng-strict-diを使用する

Angular 1.3を使用している場合、ngAppで ngStrictDi ディレクティブを使用することで、自分自身を傷つける世界を救うことができます。

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

今-事前縮小-アノテーションを使用しないものはすべてコンソールを爆破しますandフリギンの名前を見ることができます破損したスタックトレースを探し回る必要はありません。

ドキュメントごと:

アプリケーションは、明示的な関数注釈を使用しない関数の呼び出しに失敗します(したがって、縮小化には不向きです)

1つの注意点、注釈が完全であることではなく、are注釈があることのみを検出します。

意味:

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

ThingBが注釈の一部ではないことをキャッチしません。

このヒントの功績は、 ng-annotate の人々にあります。これは、現在廃止されているngMinよりも推奨されています。

25
Mark Fox

angularを縮小するには、次のように宣言を「配列」宣言「モード」に変更するだけです。

From:

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

To

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

工場サービスの宣言方法は?

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

私はちょうど同じ問題を抱えていたので、単純なビルドタスクのngmin(現在は非推奨)をng-annotateに置き換えるだけで解決しました。

このコミットの時点で、yeoman angularもng-annotateを使用するように更新されているようです: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

ただし、私のようなyeoman angularの古いバージョンを使用している場合は、package.jsonでng-minをng-annotateに置き換えてください。

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

npm install(その後、オプションでnpm Prune)を実行し、 commit の変更に従ってGruntfile.jsを編集します。

8
Xuwen

元の変数名が何であるかを知るために、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;
    [...]
  }
};

そして今、エラーははるかに明白です

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

現在、各変数は元の値も含む一意の値にマングルされています...縮小されたjavascriptを開き、「a_orig_ $ stateProvider_91212」などを検索します...元のコンテキストで表示されます...

簡単なことはできませんでした...

7
user3338098

また、ルートのresolveプロパティも忘れないでください。また、配列として定義する必要があります。

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

Generator-gulp-angularの場合:

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

}

/ ** @ngInject * /を各コントローラー、サービス、ディレクティブの前に記述します。

3
Maxim Danilov

Uglifyで変数名をマングルしたり短縮したりする必要がない場合は、Gruntfileでmangle = falseを設定することで、これに対する迅速で汚い修正が可能です。

    uglify: {
        compile: {
            options: {
                mangle   : false,
                ...
            },
        }
    }
2
Parris Varney