102

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

Unknown provider: aProvider <- a

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

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

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

Chrome にソース マップを使用させて、ここで問題となっているプロバイダーを教えてもらうにはどうすればよいですか? あるいは、別の方法でプロバイダーを見つけるにはどうすればよいでしょうか?

4

9 に答える 9

197

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

.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 を開いた状態で、Chrome でプロジェクト Web サイトを開きました。以下のようなエラーがログに記録されます。

ここに画像の説明を入力

関心のあるコール トレースのメソッドは、矢印でマークしたメソッドです。これはproviderInjectorにありinjector.jsます。例外をスローするブレークポイントを配置する必要があります。

ここに画像の説明を入力

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

ここに画像の説明を入力

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

ここに画像の説明を入力

grepソースをざっと見てみると の多くのインスタンスが見つかりますがmodalInstance、そこからソース内でこのスポットを見つけるのは簡単でした:

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

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

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

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

ここに画像の説明を入力

再発防止

うまくいけば問題が見つかったので、今後これが再び発生しないようにする最善の方法について言及する必要があると思います.

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

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

または、 ng-annotateに任せることもできます。この領域で次のようなミスが発生する可能性が大幅に減るため、これを行うことを強くお勧めします。

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

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

grunt-ng-annotategulp-ng- annotateを使用して、ビルド プロセスにうまく統合する必要があります。

于 2014-02-14T18:36:59.697 に答える
30

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

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

悪い

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

良い

return {
    restrict: "E",
    scope: {                
    },
    controller: ["$scope", ExampleDirectiveController],
    templateUrl: "template/url/here.html"
};
于 2014-10-15T11:58:15.020 に答える
26

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

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

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

現在 — プレミニフィケーション —注釈を使用しないものはすべてコンソール爆破し、壊れたスタック トレースを調べなくても名前を確認できます。

ドキュメントごと:

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

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

意味:

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

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

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

于 2015-02-06T03:33:30.837 に答える
8

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

このコミットの時点で、yeoman angular も ng-annotate を使用するように更新されているようです

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

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

run npm install(その後、オプションで ) を実行し、コミットnpm pruneの変更に従ってeditを実行します。Gruntfile.js

于 2014-09-13T05:08:44.447 に答える
4

generator-gulp-angular を使用:

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

}

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

于 2016-07-29T08:27:41.753 に答える
4

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

$routeProvider.when('/foo', {
    resolve: {
        bar: ['myService1', function(myService1) {
            return myService1.getThis();
        }],
        baz: ['myService2', function(myService2) {
            return myService2.getThat();
        }]
    }
});
于 2015-02-25T14:23:37.360 に答える