“Nhà cung cấp không xác định: aProvider <- a” Làm cách nào để tìm nhà cung cấp ban đầu?


100

Khi tôi đang tải phiên bản thu nhỏ (thông qua UglifyJS) của ứng dụng AngularJS của mình, tôi gặp lỗi sau trong bảng điều khiển:

Unknown provider: aProvider <- a

Bây giờ, tôi nhận ra rằng điều này là do sự xáo trộn tên biến. Phiên bản không bị nhầm lẫn hoạt động tốt. Tuy nhiên, tôi làm muốn tận dụng tên biến mangling, vì nó làm giảm đáng kể kích thước của tập tin đầu ra JS của chúng tôi.

Vì lý do đó, chúng tôi đang sử dụng ngmin trong quá trình xây dựng của mình, nhưng nó dường như không giải quyết được vấn đề này, mặc dù nó đã từng phục vụ chúng tôi rất tốt trong quá khứ.

Vì vậy, để gỡ lỗi vấn đề này, tôi đã bật bản đồ nguồn trong tác vụ grunt uglify của chúng tôi. Chúng được tạo tốt và Chrome không tải các bản đồ từ máy chủ. Tuy nhiên, tôi vẫn nhận được cùng một thông báo lỗi không hữu ích, mặc dù tôi có ấn tượng rằng bây giờ tôi sẽ thấy tên ban đầu của nhà cung cấp.

Làm cách nào để Chrome sử dụng bản đồ nguồn để cho tôi biết vấn đề ở đây là nhà cung cấp nào hoặc cách khác, làm cách nào để tìm ra nhà cung cấp theo cách khác?


Bạn có thể thử thêm các nhận xét riêng biệt vào mọi tệp nguồn JS (nếu chưa phải là trường hợp như vậy) và sử dụng tùy chọn keepComments của UglifyJS: điều này sẽ cung cấp cho bạn ý tưởng về tệp nào chứa mã không chính xác.
JB Nizet

Bạn có tình cờ sử dụng trang trí không? Tôi thấy rằng ngmin dường như không viết lại trình trang trí đúng cách khi tôi đã sử dụng nó trước đây, dẫn đến lỗi như của bạn.
dherman

@JBNizet: Tôi thích ý tưởng này, nhưng việc thêm chỉ thị đó vào các tùy chọn dường như không có tác dụng gì.
Der Hochstapler

@dherman: Bạn có thể cho tôi một ví dụ về trình trang trí được không? Tôi không chắc họ sẽ như thế nào trong bối cảnh này.
Der Hochstapler

Xem github.com/gruntjs/grunt-contrib-uglify (nếu bạn sử dụng grunt). Giá trị của tùy chọn phải là "tất cả".
JB Nizet

Câu trả lời:


193

Tôi vẫn muốn biết làm thế nào tôi có thể tìm thấy vị trí trong mã nguồn của chúng tôi đã gây ra sự cố này, nhưng tôi đã có thể tìm thấy sự cố theo cách thủ công.

Đã có một hàm điều khiển được khai báo trên phạm vi toàn cục, thay vì sử dụng .controller()lệnh gọi trên mô-đun ứng dụng.

Vì vậy, có một cái gì đó như thế này:

function SomeController( $scope, i18n ) { /* ... */ }

Điều này hoạt động tốt với AngularJS, nhưng để làm cho nó hoạt động đúng với mangling, tôi đã phải thay đổi nó thành:

var applicationModule = angular.module( "example" );
function SomeController( $scope, i18n ) { /* ... */ }
applicationModule.controller( "SomeController", [ "$scope", "i18n", SomeController ] );

Sau khi kiểm tra thêm, tôi thực sự tìm thấy các trường hợp của nhiều bộ điều khiển hơn cũng gây ra sự cố. Đây là cách tôi tìm thấy nguồn của tất cả chúng theo cách thủ công :

Trước hết, tôi cho rằng việc kích hoạt tính năng làm đẹp đầu ra trong các tùy chọn uglify là khá quan trọng. Đối với nhiệm vụ khó chịu của chúng tôi có nghĩa là:

options : {
    beautify : true,
    mangle   : true
}

Sau đó, tôi đã mở trang web của dự án trong Chrome với DevTools đang mở. Dẫn đến lỗi như lỗi dưới đây được ghi lại:

nhập mô tả hình ảnh ở đây

Phương thức trong dấu vết cuộc gọi mà chúng tôi quan tâm, là phương thức tôi đã đánh dấu bằng mũi tên. Đây là providerInjectortronginjector.js . Bạn sẽ muốn đặt một điểm ngắt ở đó nó ném một ngoại lệ:

nhập mô tả hình ảnh ở đây

Khi bạn chạy lại ứng dụng bây giờ, điểm ngắt sẽ được nhấn và bạn có thể nhảy lên ngăn xếp cuộc gọi. Sẽ có một cuộc gọi từ bên invoketronginjector.js , có thể nhận ra từ chuỗi "Mã thông báo chèn không chính xác":

nhập mô tả hình ảnh ở đây

Các localstham số (đọc sai để dtrong mã của tôi) đưa ra một ý tưởng khá tốt về những đối tượng trong nguồn của bạn là vấn đề:

nhập mô tả hình ảnh ở đây

Xem nhanh grepnguồn của chúng tôi tìm thấy nhiều trường hợp modalInstance, nhưng từ đó, thật dễ dàng tìm thấy điểm này trong nguồn:

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

Cái nào phải được thay đổi thành:

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

Trong trường hợp biến không chứa thông tin hữu ích, bạn cũng có thể nhảy lên thêm ngăn xếp và bạn nên thực hiện lệnh gọi invokemà biến đó sẽ có thêm gợi ý:

nhập mô tả hình ảnh ở đây

Ngăn điều này xảy ra lần nữa

Bây giờ hy vọng bạn đã tìm ra vấn đề, tôi cảm thấy rằng tôi nên đề cập đến cách tốt nhất để tránh điều này xảy ra lần nữa trong tương lai.

Rõ ràng, bạn chỉ có thể sử dụng các chú thích mảng inline ở khắp mọi nơi, hoặc (tùy thuộc vào sở thích của bạn) $injectchú thích bất động sản và chỉ đơn giản là cố gắng không để quên nó trong tương lai. Nếu bạn làm như vậy, hãy đảm bảo bật chế độ tiêm phụ thuộc nghiêm ngặt để phát hiện sớm các lỗi như thế này.

Coi chừng! Trong trường hợp bạn đang sử dụng Angular Batarang, Nghiêm ngặtDI có thể không phù hợp với bạn, vì Angular Batarang đưa mã không có chú thích vào của bạn (Batarang không tốt!).

Hoặc bạn có thể để ng-annotate chăm sóc nó. Tôi thực sự khuyên bạn nên làm như vậy, vì nó loại bỏ rất nhiều khả năng mắc sai lầm trong lĩnh vực này, như:

  • Thiếu chú thích DI
  • Chú thích DI chưa hoàn thành
  • Chú thích DI sai thứ tự

Giữ cho các chú thích được cập nhật chỉ đơn giản là một nỗi đau và bạn không cần phải làm điều đó nếu nó có thể được thực hiện tự động. ng-annotate thực hiện chính xác điều đó.

Nó sẽ tích hợp độc đáo vào quy trình xây dựng của bạn với grunt-ng-annotategulp-ng-annotate .


12
Đây là một bài viết tuyệt vời, được viết cẩn thận. Tôi mới gặp vấn đề này, có vẻ là một vấn đề nằm sâu trong ngmin ở đâu đó. Mẹo của bạn đã giúp tôi biết nơi để tìm. Cuối cùng, tôi chỉ "array-ified" tất cả các tham số góc của mình và vấn đề đã biến mất. Tất cả các bản dựng trước đó đều tốt và không có gì thay đổi đáng kể. Tôi đã không thêm bất kỳ chức năng toàn cục nào - nó chỉ ngừng hoạt động, một cách bí ẩn, bằng cách xáo trộn một số bộ điều khiển / chỉ thị / dịch vụ / bộ lọc?
zenocon

Đây là một nguồn trợ giúp tuyệt vời. Tôi không biết bạn cũng phải sử dụng cú pháp mảng (nội tuyến) cho các chức năng khác, như giải quyết bộ định tuyến, .run, .config, v.v.
VDest

4
Trong trường hợp của tôi, đó là bộ điều khiển trong chỉ thị. Nếu trong biến 'd' bạn sẽ thấy $ attr, đó có thể là vấn đề tương tự. Bạn nên bọc các tham số trong dấu ngoặc nhọn cho bộ điều khiển chỉ thị bên trong. điều khiển: [ "$ phạm vi", function ($ phạm vi) {...}] thay vì điều khiển: function ($ phạm vi) {...}
alex Naumov

Cảm ơn bạn rất nhiều vì đã viết và giải pháp bằng cách sử dụng ký hiệu mảng / tiêm phụ thuộc an toàn cho tham chiếu hàm var. Tôi cũng gặp lỗi này và nhờ giải pháp của bạn, tôi đã có thể tiếp tục tiến lên. bạn rock!
Frankie Loscavio

1
Mỗi khi tôi có vấn đề này, tôi lại đọc nó và muốn bỏ phiếu cho nó một lần nữa. Btw, đây là làm thế nào để cài đặt phiên bản ngụmuglify({ output : { beautify : true }})
Eugene Gluhotorenko

30

Cú ghi bàn của Oliver Salzburg thật tuyệt vời. Đã ủng hộ.

Mẹo cho những ai có thể mắc phải lỗi này. Lỗi của tôi chỉ đơn giản là do quên chuyển vào một mảng cho bộ điều khiển chỉ thị:

XẤU

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

TỐT

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

2
Đây là một sự cố táo tợn ... Uglify đã không gây ra điều này cho tôi cho đến khi có bản cập nhật gần đây!
SamMorrowDrums

Vấn đề của tôi cũng vậy, nhưng hóa ra thứ tôi cần thêm là /* @ngInject */trước hàm. Có vẻ như để làm phần tiêm phức tạp mà không cần phải gõ từng module bao gồm (Tôi đang sử dụng Yeoman)
Nicholas Blasgen

25

sử dụng ng-precision-di với ng-app

Nếu bạn đang sử dụng Angular 1.3, bạn có thể cứu mình khỏi thế giới bị tổn thương bằng cách sử dụng lệnh ngStrictDi với ngApp:

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

Bây giờ - thu nhỏ trước - bất kỳ thứ gì không sử dụng chú thích sẽ làm nổ tung bảng điều khiển của bạn bạn có thể nhìn thấy tên của tên quái vật mà không cần tìm kiếm qua các dấu vết ngăn xếp bị xáo trộn.

Theo tài liệu:

ứng dụng sẽ không gọi được các hàm không sử dụng chú thích hàm rõ ràng (và do đó không phù hợp để rút gọn)

Một báo trước , nó chỉ phát hiện rằng có những chú thích, không phải là các chú thích là hoàn tất.

Ý nghĩa:

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

Sẽ không hiểu rằng ThingB không phải là một phần của chú thích.

Tín dụng cho mẹo này sẽ thuộc về ng-annotate folks, được khuyên dùng thay vì ngMin hiện không được dùng nữa.


Điều này cần nhiều lượt ủng hộ hơn. Điều này rất tốt để gỡ lỗi một ứng dụng chưa bao giờ sử dụng ngInject hoặc cú pháp mảng chuỗi.
Michael Pearson

11

Để giảm thiểu góc cạnh, tất cả những gì bạn cần làm là thay đổi khai báo của bạn thành "chế độ" khai báo "mảng", ví dụ:

Từ:

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

Đến

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

Làm thế nào để khai báo các dịch vụ nhà máy?

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

Tôi biết. Đó là lý do tại sao chúng tôi sử dụng ngmin. Tôi nghi ngờ rằng nó có vấn đề với một số phần nguồn của chúng tôi hoặc các phần phụ thuộc của nó. Đó là lý do tại sao tôi đang cố gắng giải quyết tận gốc vấn đề này.
Der Hochstapler

1
Khuyến nghị của tôi là bạn tạo mã của mình theo cách này. Vì vậy, bạn có thể sử dụng bất kỳ bộ thu nhỏ nào
Dalorzo 10/02

3
Tôi đang tạo mã của chúng tôi theo cách này. Nhưng chúng ta có những phụ thuộc bên ngoài mà không. ngmin đã giải quyết vấn đề này tốt cho chúng tôi trong quá khứ. Tôi cho rằng một thay đổi gần đây đã tạo ra vấn đề này. Bây giờ tôi muốn tìm nguồn gốc của vấn đề này để tôi có thể sửa nó đúng cách trong mã của chúng tôi, phần phụ thuộc của chúng tôi hoặc có thể trong chính ngmin.
Der Hochstapler

Kể từ khi những âm thanh vấn đề giống như một cụ rất để một thành phần hoặc mã đặc biệt khó có thể cung cấp hướng dẫn, ít nhất là từ cuối của tôi
Dalorzo

ngmin không yêu cầu bạn sử dụng chế độ khai báo mảng, nó bổ sung rất nhiều khai báo vô ích.
Nanocom

8

Tôi vừa gặp sự cố tương tự và đã giải quyết nó bằng cách thay thế ngmin (hiện không được dùng nữa) bằng ng-annotate cho tác vụ xây dựng grunt của mình.

Có vẻ như góc yeoman cũng đã được cập nhật để sử dụng ng-annotate kể từ lần cam kết này: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

Tuy nhiên, nếu bạn đang sử dụng phiên bản cũ hơn của yeoman angle như tôi, chỉ cần thay ng-min bằng ng-annotate trong package.json của bạn:

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

chạy npm install(sau đó tùy chọn npm prune) và làm theo các thay đổi trong cam kết chỉnh sửa Gruntfile.js.


7

để biết tên biến ban đầu là gì, bạn có thể thay đổi cách uglify xử lý các biến:

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

và bây giờ lỗi rõ ràng hơn nhiều

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)

BIÊN TẬP

Rõ ràng là bây giờ ...

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

bây giờ mỗi biến được chuyển thành một giá trị duy nhất cũng chứa giá trị ban đầu ... chỉ cần mở javascript được rút gọn và tìm kiếm "a_orig_ $ stateProvider_91212" hoặc bất cứ thứ gì ... bạn sẽ thấy nó trong ngữ cảnh ban đầu ...

không thể dễ dàng hơn ...


4

Cũng đừng quên resolvetài sản của tuyến đường. Nó cũng phải được định nghĩa là mảng:

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

Điều này đã xảy ra với tôi khi tôi thêm một loạt các giải pháp vào các tuyến đường của mình. Bạn đã có thể giúp tôi tiết kiệm hàng giờ gỡ lỗi đau đớn, cảm ơn.
Paul McClean

3

Với máy phát điện-gulp-góc:

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

}

Viết / ** @ngInject * / trước mỗi bộ điều khiển, dịch vụ, chỉ thị.


2

Một cách khắc phục nhanh chóng và sai lầm cho điều này nếu bạn không yêu cầu Uglify để mangle / rút ngắn tên biến của mình là đặt mangle = false trong Gruntfile của bạn

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

Điều này có thể giải quyết vấn đề, nhưng kích thước bản dựng kết quả sẽ lớn hơn vì mangle bị tắt.
NotABot

vẫn còn nhỏ hơn là không xấu chút nào
mjwrazor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.