[angularjs] “알 수없는 공급자 : 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 주석 불완전
  • 잘못된 순서의 DI 주석

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

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


답변

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"
};


답변

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보다 권장됩니다.


답변

각도를 최소화하려면 다음과 같이 선언을 “배열”선언 “모드”로 변경하면됩니다.

에서:

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 (현재 사용되지 않음)을 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합니다.


답변

원래 변수 이름이 무엇인지 알기 위해 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″또는 무엇이든 검색하세요 … 원래 컨텍스트에서 볼 수 있습니다 …

이보다 더 쉬울 수는 없습니다 …


답변

또한 resolve경로 의 속성을 잊지 마십시오 . 또한 배열로 정의되어야합니다.

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