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


100

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

Unknown provider: aProvider <- a

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

そのため、ビルドプロセスではngminを使用していますが、以前はうまく機能していたとしても、この問題は解決されていないようです。

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

Chromeでソースマップを使用して、ここで問題のプロバイダーを特定するにはどうすればよいですか。または、別の方法でプロバイダーを見つけるにはどうすればよいですか。


すべてのJSソースファイルに個別のコメントを追加してみて(まだそうでない場合)、UglifyJSのpreserveCommentsオプションを使用すると、どのファイルに誤ったコードが含まれているかがわかります。
JBニゼット2014

あなたはたまたまデコレーターを使用していますか?ngminを過去に使用したときにngminが適切にデコレータを書き直していないように見えるため、あなたのようなエラーが発生します。
ダーマン2014

@JBNizet:私はそのアイデアが好きですが、オプションにそのディレクティブを追加しても効果がないようです。
Der Hochstapler、2014

@dherman:デコレータの例を教えてください。彼らがこの文脈でどうなるかはわかりません。
Der Hochstapler、2014

github.com/gruntjs/grunt-contrib-uglifyを参照してください(gruntを使用している場合)。オプションの値は「すべて」でなければなりません。
JBニゼット2014

回答:


193

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

.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
}

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

ここに画像の説明を入力してください

関心のある呼び出しトレースのメソッドは、矢印でマークしたものです。これはproviderInjectorにありinjector.jsます。例外をスローする場所にブレークポイントを配置したいとします。

ここに画像の説明を入力してください

ここでアプリケーションを再実行すると、ブレークポイントがヒットし、コールスタックをジャンプアップできます。invokeininjector.jsからの呼び出しがあり、「不正な注入トークン」文字列から認識できます。

ここに画像の説明を入力してください

localsパラメータ(に台無しにd私のコードでは)問題であり、あなたのソース内のどのオブジェクトについてはかなり良いアイデアを与えます:

ここに画像の説明を入力してください

grepソースをすばやく確認すると、の多くのインスタンスが見つかりますがmodalInstance、そこからソース内でこの場所を見つけるのは簡単でした。

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

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

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

変数に有用な情報が含まれていない場合は、スタックをさらに上に移動して、invoke追加のヒントが必要な呼び出しをヒットする必要があります。

ここに画像の説明を入力してください

これが再発しないようにする

うまくいけば問題を見つけたので、今後この問題が再発しないようにするための最善の方法について触れておきたいと思います。

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

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

またはng-annotateに処理を任せることもできます。次のように、この領域でのミスの可能性を大幅に取り除くため、そうすることを強くお勧めします。

  • DIアノテーションがありません
  • DIアノテーションが不完全
  • DIアノテーションの順序が間違っている

アノテーションを最新の状態に保つことは、単にお尻の痛みであり、自動的に実行できるのであれば、そうする必要はありません。ng-annotateはまさにそれを行います。

grunt-ng-annotategulp-ng-annotateを使用してビルドプロセスにうまく統合できます。


12
これは、注意深く書かれた素晴らしい記事です。私はこの問題に遭遇しました、どこかでngminの深い問題のようです。あなたのヒントは私がどこを見ればよいかを知るのに役立ちました。最後に、すべての角度パラメーターを「配列化」するだけで、問題はなくなりました。以前のすべてのビルドはng-minifiedで問題なく、大幅な変更はありません。私はグローバル関数を追加しませんでした-不思議なことに、いくつかのコントローラー/ディレクティブ/サービス/フィルターをマングリングすることによって機能しなくなりましたか?
zenocon、2014年

これは大きな助けとなりました。ルーターの解決、.run、.configなどの他の関数にも配列(インライン)構文を使用する必要があることを知りませんでした
VDest

4
私の場合、それはディレクティブのコントローラーでした。'd'変数に$ attrが表示される場合は、おそらく同じ問題です。内部ディレクティブコントローラーの場合は、パラメーターを配列ブラケットでラップする必要があります。コントローラー:["$ scope"、function($ scope){...}]コントローラーの代わりに:function($ scope){...}
alex naumov

var関数リファレンスに安全な依存性注入/配列表記を使用した記述と解決策をありがとうございます。私にもこのエラーがあり、あなたの解決策のおかげで私は前進し続けることができました。あなたはロック!
Frankie Loscavio 2014年

1
この問題が発生するたびに、私はこれをもう一度読み、もう一度投票したいと思います。ところで、ここではuglify({ output : { beautify : true }})
gulp

30

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

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

悪い

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

良い

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

2
これはとても生意気なものでした... Uglifyは最近のアップデートまで私にこれを引き起こしていませんでした!
SamMorrowDrums

私の問題は同じでしたが/* @ngInject */、関数の前に追加する必要があることがわかりました。含まれている各モジュールを入力する必要なく、複雑な注入部分を行うようです(私はYeomanを使用しています)
Nicholas Blasgen

25

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

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

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

今-事前縮小-何もしない、あなたのコンソールを爆破します注釈を使用して、あなたがマングルされたスタックトレースによる狩猟ずにfrigginの名前を見ることができます。

ドキュメントごと:

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

注意点の1つは、注釈があることだけを検出し、注釈が完全であることを検出するわけでありません。

意味:

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

ThingBがアノテーションの一部ではないことをキャッチしません。

このヒントの功績はng-annotate関係者にあり、現在非推奨のngMinよりも推奨されています。


これにはもっと賛成票が必要です。これは、ngInjectまたは文字列配列構文を使用したことがないアプリのデバッグに最適です。
マイケルピアソン

11

角度を最小化するには、宣言を「配列」宣言「モード」に変更するだけです。次に例を示します。

から:

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
    };
}]);

知っている。これがngminを使用する理由です。ソースの一部またはその依存関係に問題があると思います。これが私がこの問題の根本に到達しようとしている理由です。
Der Hochstapler、2014

1
この方法でコードを作成することをお勧めします。したがって、任意の縮小機能を使用できます
Dalorzo

3
私がしています。この方法で私たちのコードを作成します。しかし、そうではない外部依存関係があります。ngminは過去にこの問題をうまく解決してくれました。最近の変更によりこの問題が発生したと思います。次に、この問題の原因を見つけて、コード、依存関係、またはngmin自体で適切に修正できるようにします。
Der Hochstapler、2014

特定のコンポーネントやコードに非常に特定のような問題が鳴りますので、少なくとも私の端から、ガイダンスを提供するのは難しい
Dalorzo

ngminでは、配列宣言モードを使用する必要はありません。多くの無駄な宣言が追加されます。
Nanocom 2014

8

私は同じ問題を抱えていて、単純な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)実行し、コミットの変更に従ってeditを実行しますGruntfile.js


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

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

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」などを検索するだけです...元のコンテキストで表示されます...

これ以上簡単なことはありません...


4

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

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

これは、ルートに多数の解決策を追加したときに起こりました。おかげで、あなたは潜在的に私に苦痛なデバッグの時間を節約しました。
Paul McClean、2015年

3

generator-gulp-angularの場合:

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

}

書き込み/ ** * @ngInject /各コントローラの前に、サービス、ディレクティブ。


2

変数名をマングル/短縮するためにUglifyを必要としない場合のこれに対する迅速でダーティな修正は、Gruntfileでmangle = falseを設定することです。

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

これで問題が解決する可能性がありますが、マングルが無効になっているため、結果のビルドサイズは大きくなります。
NotABot

それでもまったく醜くないよりも小さい
mjwrazor
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.