programing tip

“알 수없는 공급자 : aProvider <-a”원래 공급자를 찾으려면 어떻게합니까?

itbloger 2020. 8. 20. 07:56
반응형

“알 수없는 공급자 : aProvider <-a”원래 공급자를 찾으려면 어떻게합니까?


AngularJS 애플리케이션의 축소 된 (UglifyJS를 통해) 버전을로드 할 때 콘솔에 다음 오류가 발생합니다.

Unknown provider: aProvider <- a

이제 이것이 변수 이름 맹 글링 때문이라는 것을 알고 있습니다. 얽 히지 않은 버전은 잘 작동합니다. 그러나, 나는 절대적인 우리의 JS 출력 파일의 크기를 감소시키기 때문에, 변수 이름 맹 글링의 사용을 만들고 싶어.

그렇기 때문에 우리는 빌드 프로세스에서 ngmin사용 하고 있지만 과거에는 잘 해냈 지만이 문제를 해결하지 못하는 것 같습니다.

따라서이 문제를 디버깅하기 위해 uglify grunt 작업에서 소스 맵을 활성화했습니다. 그것들은 잘 생성되고 Chrome 서버에서지도를로드합니다. 그러나 이제 공급자의 원래 이름을보아야한다는 인상을 받았음에도 불구하고 여전히 도움이되지 않는 동일한 오류 메시지가 표시됩니다.

Chrome에서 소스 맵을 사용하여 여기에서 문제가되는 공급자를 알려주려면 어떻게해야합니까? 아니면 다른 방법으로 공급자를 찾으려면 어떻게해야합니까?


이 문제를 일으킨 소스 코드의 위치를 ​​어떻게 찾을 수 있었는지 알고 싶지만 이후 수동으로 문제를 찾을 수있었습니다.

.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에서 DevTools를 열어 프로젝트 웹 사이트를 열었습니다. 다음과 같은 오류가 기록됩니다.

여기에 이미지 설명 입력

우리가 관심을 갖는 호출 추적의 메서드는 화살표로 표시 한 메서드입니다. 이다 providerInjector에서injector.js . 예외가 발생하는 곳에 중단 점을 배치하고 싶을 것입니다.

여기에 이미지 설명 입력

이제 애플리케이션을 다시 실행하면 중단 점에 도달하고 호출 스택을 점프 할 수 있습니다. "Incorrect injection token"문자열에서 인식 할 수있는 invokein에서injector.js 호출이 발생 합니다.

여기에 이미지 설명 입력

locals매개 변수 (로 엉망이 d내 코드에서)이 문제가 소스에있는 개체에 대해 꽤 좋은 아이디어를 제공합니다 :

여기에 이미지 설명 입력

grep소스를 빠르게 살펴보면의 많은 인스턴스 modalInstance를 찾을 수 있지만 거기에서 소스에서이 지점을 쉽게 찾을 수 있습니다.

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

다음으로 변경해야합니다.

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

변수에 유용한 정보가없는 경우 스택에서 더 위로 점프 할 수 invoke있으며 추가 힌트가 있어야 하는 호출을 입력 해야합니다.

여기에 이미지 설명 입력

다시 발생하지 않도록 방지

이제 문제를 발견 했으므로 앞으로 다시 발생하지 않도록 최선의 방법을 언급해야한다고 생각합니다.

분명히, 당신은 어디에서나 인라인 배열 주석을 사용 하거나 (선호도에 따라) $inject속성 주석을 사용할 수 있으며 단순히 미래에 그것을 잊지 않도록 노력할 수 있습니다. 그렇게하는 경우 이와 같은 오류를 조기에 포착하려면 엄격한 종속성 주입 모드 를 활성화해야합니다 .

조심해! Angular Batarang을 사용하는 경우 Angular Batarang이 주석이없는 코드를 사용자의 코드에 삽입하므로 StrictDI가 작동하지 않을 수 있습니다 (나쁜 Batarang!).

또는 ng-annotate 가 처리 하도록 할 수 있습니다. 이 영역에서 다음과 같은 실수가 발생할 가능성을 많이 제거하므로 그렇게하는 것이 좋습니다.

  • DI 주석 누락
  • DI annotation incomplete
  • DI annotation in wrong order

Keeping the annotations up-to-date is simply a pain in the ass and you shouldn't have to do it if it can be done automatically. ng-annotate does exactly that.

It should integrate nicely into your build process with grunt-ng-annotate and gulp-ng-annotate.


Oliver Salzburg's write-up was fantastic. Upvoted.

Tip for anyone who might have this error. Mine was simply caused by forgetting to pass in an array for a directive controller:

BAD

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

GOOD

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

use ng-strict-di with ng-app

If you're using Angular 1.3 you can save yourself a world of hurt by using ngStrictDi directive with ngApp:

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

Now — pre-minification — anything that doesn't use annotations will blow up your console and you can see the friggin' name without hunting through mangled stack traces.

Per the docs:

the application will fail to invoke functions which do not use explicit function annotation (and are thus unsuitable for minification)

One caveat, it only detects that there are annotations, not that the annotations are complete.

Meaning:

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

Will not catch that ThingB isn't part of the annotation.

Credit for this tip goes to the ng-annotate folks, which is recommend over the now deprecated ngMin.


To minify angular all you need is to do is to change your declaration to the "array" declaration "mode" for example:

From:

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

To

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

How to declare factory services?

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

I just had the same problem and resolved it by simply replacing ngmin (now deprecated) with ng-annotate for my grunt build task.

It seems that yeoman angular has also been updated to use ng-annotate as of this commit: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

However if you are using an older version of yeoman angular like me, just replace ng-min with ng-annotate in your package.json:

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

run npm install (then optionally npm prune), and follow the changes in the commit to edit Gruntfile.js.


in order to know what the original variable name was you can change how uglify mangles the 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;
    [...]
  }
};

and now the error is much more obvious

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)

EDIT

So obvious now...

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

now each variable is mangled to a unique value that also contains the original... just open up the minified javascript and search for "a_orig_$stateProvider_91212" or whatever... you will see it in it's original context...

couldn't be any easier...


Also do not forget the resolve property of the route. It also must be defined as the array:

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

With generator-gulp-angular:

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

}

Write /** @ngInject */ before each controller, service, directive.


A quick and dirty fix for this if you don't require Uglify to mangle/shorten your variable names is to set mangle = false in your Gruntfile

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

참고 URL : https://stackoverflow.com/questions/21688681/unknown-provider-aprovider-a-how-do-i-find-the-original-provider

반응형