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


100

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

Unknown provider: aProvider <- a

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

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

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

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


모든 JS 소스 파일에 고유 한 주석을 추가하고 (아직 그렇지 않은 경우) UglifyJS의 preserveComments 옵션을 사용하면 잘못된 코드가 포함 된 파일에 대한 아이디어를 얻을 수 있습니다.
JB Nizet 2014

데코레이터를 사용하고 있습니까? 나는 ngmin이 과거에 그것을 사용했을 때 데코레이터를 올바르게 다시 작성하지 않는 것 같아서 당신과 같은 오류가 발생한다는 것을 발견했습니다.
dherman

@JBNizet : 아이디어가 마음에 들지만 옵션에 해당 지시문을 추가해도 효과가없는 것 같습니다.
데르 Hochstapler

@dherman : 데코레이터의 예를 들어 주실 수 있나요? 나는 그들이이 맥락에서 무엇 일지 확신하지 못한다.
Der Hochstapler

github.com/gruntjs/grunt-contrib-uglify(grunt 를 사용하는 경우)를 참조하십시오 . 옵션 값은 "all"이어야합니다.
JB Nizet 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에서 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 주석 불완전
  • 잘못된 순서의 DI 주석

주석을 최신 상태로 유지하는 것은 당연한 일이며 자동으로 수행 할 수 있다면 그렇게 할 필요가 없습니다. ng-annotate는 정확히 그렇게합니다.

grunt-ng-annotategulp-ng-annotate 로 빌드 프로세스에 잘 통합되어야합니다 .


12
이것은 신중하게 작성된 환상적인 글입니다. 방금이 문제를 만났는데 어딘가 ngmin에서 깊은 문제인 것 같습니다. 당신의 조언은 내가 어디를 봐야할지 아는 데 도움이되었습니다. 결국 저는 모든 각도 매개 변수를 "배열"하고 문제가 해결되었습니다. 모든 이전 빌드는 잘 축소되었으며 크게 변경된 사항은 없습니다. 전역 함수를 추가하지 않았습니다. 컨트롤러 / 지시문 / 서비스 / 필터를 변경하여 신비하게도 작동을 멈췄습니까?
zenocon

이것은 큰 도움의 원천이었습니다. 라우터 확인,
.run

4
제 경우에는 지시문의 컨트롤러였습니다. 'd'변수에 $ attr이 표시되면 아마도 동일한 문제 일 것입니다. 내부 지시어 컨트롤러의 경우 매개 변수를 배열 대괄호로 묶어야합니다. 컨트롤러 : [ "$ scope", function ($ scope) {...}] 컨트롤러 대신 : function ($ scope) {...}
alex naumov 2014 년

var 함수 참조에 대해 안전한 종속성 주입 / 배열 표기법을 사용하여 작성하고 솔루션을 작성해 주셔서 감사합니다. 나도이 오류가 있었고 귀하의 솔루션 덕분에 계속 나아갈 수있었습니다. 당신은 락!
Frankie Loscavio

1
이 문제가있을 때마다 나는 이것을 다시 읽고 이것에 대해 다시 투표하고 싶습니다. BTW, 여기에 어떻게 설정 꿀꺽 버전입니다uglify({ output : { beautify : true }})
유진 Gluhotorenko

30

Oliver Salzburg의 글은 환상적이었습니다. 찬성.

이 오류가있을 수있는 모든 사용자를위한 팁입니다. 내 것은 단순히 지시어 컨트롤러에 대한 배열을 전달하는 것을 잊었 기 때문에 발생했습니다.

나쁜

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 2015

내 문제는 동일했지만 추가해야 할 /* @ngInject */것이 기능 이전 에 있었던 것으로 밝혀졌습니다 . 포함 된 각 모듈을 입력 할 필요없이 복잡한 사출 부분을 수행하는 것 같습니다. (저는 Yeoman을 사용하고 있습니다)
Nicholas Blasgen

25

ng-app과 함께 ng-strict-di 사용

Angular 1.3을 사용하는 경우 ngApp 과 함께 ngStrictDi 지시문을 사용하여 상처의 세계를 구할 수 있습니다 .

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

지금 - 사전 축약 - 아무것도 하지 않는 콘솔을 날려 버리겠다 주석을 사용 하고 당신이 엉망이 스택 추적을 통해 사냥을하지 않고 빌어 먹을 이름을 볼 수 있습니다.

문서 당 :

애플리케이션이 명시 적 함수 주석을 사용하지 않는 함수를 호출하지 못하므로 축소에 적합하지 않습니다.

한 가지주의해야 할 점은 , 그것은 단지가 감지 됩니다 주석이 완료하지 않는 것이, 주석.

의미:

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

ThingB가 주석의 일부가 아님을 포착하지 않습니다.

이 팁에 대한 크레딧은 ng-annotate 사람들에게 전달되며, 이는 현재 사용되지 않는 ngMin보다 권장됩니다.


이것은 더 많은 찬성표가 필요합니다. 이것은 ngInject 또는 문자열 배열 구문을 사용한 적이없는 앱을 디버깅하는 데 유용합니다.
Michael Pearson

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

1
이 방법으로 코드를 작성하는 것이 좋습니다. 그래서 당신은 어떤
축소기를

3
내가 하고 이런 식으로 우리의 코드를 작성. 그러나 우리는 그렇지 않은 외부 의존성을 가지고 있습니다. ngmin은 과거에 우리를 위해이 문제를 잘 해결했습니다. 최근 변경으로 인해이 문제가 발생했다고 가정합니다. 이제 코드, 종속성 또는 ngmin 자체에서 올바르게 수정할 수 있도록이 문제의 원인을 찾고 싶습니다.
Der Hochstapler

특정 구성 요소 또는 코드에 대한 매우 구체적인 같은 문제 소리 때문에 적어도 내 끝에서, 지침을 제공하기 어렵다
Dalorzo

ngmin은 배열 선언 모드를 사용할 필요가 없으며 쓸모없는 선언을 많이 추가합니다.
Nanocom 2014

8

나는 방금 같은 문제가 있었고 단순히 ngmin (현재 사용되지 않음)을 ng-annotate로 대체하여 grunt 빌드 작업을 수행하여 해결했습니다.

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)하고 커밋 의 변경 사항을 따라 편집 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++;
    [...]
  }
};

이제 각 변수는 원본도 포함하는 고유 한 값으로 변경됩니다 ... 축소 된 자바 스크립트를 열고 "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,
                ...
            },
        }
    }

이렇게하면 문제가 해결 될 수 있지만 mangle이 비활성화되어 있으므로 결과 빌드 크기가 더 커집니다.
NotABot

전혀 어리석은 것보다 여전히 작습니다
mjwrazor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.