“Bilinmeyen sağlayıcı: aProvider <- a” Orijinal sağlayıcıyı nasıl bulabilirim?


100

AngularJS uygulamamın küçültülmüş (UglifyJS aracılığıyla) sürümünü yüklediğimde, konsolda aşağıdaki hatayı alıyorum:

Unknown provider: aProvider <- a

Şimdi, bunun değişken adı karıştırmasından kaynaklandığını anlıyorum. Unmangled versiyonu gayet iyi çalışıyor. Ancak, ben do it ölçüde bizim JS çıktı dosyasının boyutunu azaltır olarak, değişken Cendereleme faydalanmak istiyoruz.

Bu nedenle, oluşturma sürecimizde ngmin kullanıyoruz , ancak geçmişte bize iyi hizmet vermesine rağmen bu sorunu çözmüyor gibi görünüyor.

Bu yüzden, bu sorunu gidermek için, çirkin homurtu görevimizde kaynak haritalarını etkinleştirdim. Onlar sadece para cezası oluşturulur ve Chrome yapar sunucudan haritalar yükleyin. Yine de, sağlayıcının orijinal adını şimdi görmem gerektiği izlenimi altında olsam da, yine de aynı yardımcı olmayan hata mesajını alıyorum.

Burada sorunun hangi sağlayıcı olduğunu söylemek için Chrome'un kaynak haritalarını kullanmasını nasıl sağlayabilirim veya alternatif olarak sağlayıcıyı başka bir şekilde nasıl bulabilirim?


Her JS kaynak dosyasına farklı yorumlar eklemeyi deneyebilir (halihazırda böyle değilse) ve UglifyJS'nin preserveComments seçeneğini kullanabilirsiniz: bu size hangi dosyanın yanlış kodu içerdiği konusunda bir fikir verecektir.
JB Nizet

Dekoratör kullanıyor musunuz? Geçmişte kullandığımda ngmin'in dekoratörleri düzgün bir şekilde yeniden yazmadığını ve bu da sizinki gibi hatalarla sonuçlandığını fark ettim.
dherman

@JBNizet: Fikri beğendim ama seçeneklere bu yönergeyi eklemenin bir etkisi yok gibi görünüyor.
Der Hochstapler

@dherman: Bana bir dekoratör örneği verebilir misiniz? Bu bağlamda ne olacaklarından emin değilim.
Der Hochstapler

Github.com/gruntjs/grunt-contrib-uglify adresine bakın (grunt kullanıyorsanız). Seçeneğin değeri "tümü" olmalıdır.
JB Nizet

Yanıtlar:


193

Bu soruna neden olan yeri kaynak kodumuzda nasıl bulabileceğimi hâlâ öğrenmek isterdim, ancak o zamandan beri sorunu manuel olarak bulabildim.

.controller()Uygulama modülünde bir çağrı kullanmak yerine genel kapsamda bildirilen bir denetleyici işlevi vardı .

Yani şöyle bir şey vardı:

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

Bu, AngularJS için gayet iyi çalışıyor, ancak karıştırmayla doğru çalışmasını sağlamak için şu şekilde değiştirmem gerekiyordu:

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

Daha ileri testlerden sonra, aslında sorunlara da neden olan daha fazla denetleyicinin örneklerini buldum. Hepsinin kaynağını manuel olarak bu şekilde buldum :

Her şeyden önce, çirkinleştirme seçeneklerinde çıktı güzelleştirmeyi etkinleştirmenin oldukça önemli olduğunu düşünüyorum. Homurdanan görevimiz için:

options : {
    beautify : true,
    mangle   : true
}

Daha sonra proje web sitesini Chrome'da DevTools açık olarak açtım. Bu, aşağıdaki gibi bir hatanın günlüğe kaydedilmesine neden olur:

görüntü açıklamasını buraya girin

Çağrı izlemede ilgilendiğimiz yöntem, okla işaretlediğim yöntemdir. Bu providerInjectoriçindeinjector.js . Bir istisna oluşturduğu bir kesme noktası yerleştirmek isteyeceksiniz:

görüntü açıklamasını buraya girin

Şimdi uygulamayı yeniden çalıştırdığınızda, kesme noktası vurulacak ve çağrı yığınını atlayabilirsiniz. Bir çağrı olacak invokeiçindeinjector.js dize "belirteç Yanlış enjeksiyon" dan tanınabilir:

görüntü açıklamasını buraya girin

localsParametresi (hiç mangled dbenim kodunda) problemdir Kaynağınıza hangi nesne hakkında bir fikir verir:

görüntü açıklamasını buraya girin

grepKaynağımız üzerinden hızlı bir şekilde birçok örnek bulur modalInstance, ancak oradan itibaren bu noktayı kaynakta bulmak kolaydı:

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

Hangisi şu şekilde değiştirilmelidir:

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

Değişkenin yararlı bilgiler içermemesi durumunda, yığında daha da yukarı atlayabilirsiniz ve invokeek ipuçlarına sahip olması gereken bir çağrıya basmanız gerekir:

görüntü açıklamasını buraya girin

Bunun tekrar olmasını önleyin

Şimdi umarım sorunu bulduğunuza göre, bunun gelecekte tekrar olmasını en iyi nasıl önleyebileceğimi belirtmem gerektiğini hissediyorum.

Açıkçası, yalnızca satır içi dizi açıklamasını her yerde veya (tercihinize bağlı olarak) $injectözellik açıklamasını kullanabilir ve gelecekte bunu unutmamaya çalışabilirsiniz. Bunu yaparsanız, bu gibi hataları erken yakalamak için sıkı bağımlılık ekleme modunu etkinleştirdiğinizden emin olun .

Dikkat et! Angular Batarang kullanıyorsanız, StrictDI sizin için çalışmayabilir, çünkü Angular Batarang sizin kodunuza açıklama yapılmamış kod enjekte eder (kötü Batarang!).

Veya ng-annotate'in ilgilenmesine izin verebilirsiniz . Bu alandaki birçok hata potansiyelini ortadan kaldırdığı için bunu yapmanızı şiddetle tavsiye ederim, örneğin:

  • DI ek açıklaması eksik
  • DI ek açıklaması eksik
  • DI ek açıklaması yanlış sırada

Ek açıklamaları güncel tutmak sadece baş belasıdır ve otomatik olarak yapılabiliyorsa bunu yapmak zorunda kalmamalısınız. ng-annotate tam olarak bunu yapar.

Grunt-ng-annotate ve gulp-ng-annotate ile yapım sürecinize güzel bir şekilde entegre edilmelidir .


12
Bu, özenle yazılmış harika bir yazı. Bu konuyla yeni karşılaştım, bir yerlerde ngmin'in derinliklerinde bir sorun gibi görünüyor. İpuçlarınız nereye bakacağımı bilmeme yardımcı oldu. Sonunda, tüm açısal parametrelerimi "diziye göre düzenledim" ve sorun ortadan kalktı. Tüm önceki yapılar ng-küçültüldü ve hiçbir şey önemli ölçüde değişmedi. Herhangi bir global işlev eklemedim - sadece bazı denetleyici / yönerge / hizmet / filtreyi karıştırarak gizemli bir şekilde çalışmayı durdurdu?
zenocon

Bu büyük bir yardım kaynağıydı. Yönlendirici çözümleme, .run, .config, vb. Gibi diğer işlevler için de dizi (satır içi) sözdizimini kullanmanız gerektiğini bilmiyordum.
VDest

4
Benim durumumda direktifte kontrolördü. Eğer 'd' değişkeninde $ attr göreceksiniz, bu muhtemelen aynı sorundur. İç yönerge denetleyicisi için parametreleri dizi parantezlerine sarmalısınız. controller: ["$ kapsam", işlev ($ kapsam) {...}] yerine controller: function ($ kapsam) {...}
alex naumov

Var işlevi referansı için güvenli bağımlılık enjeksiyonu / dizi gösterimi kullanan yazmanız ve çözümünüz için çok teşekkür ederiz. Ben de bu hatayı aldım ve çözümünüz sayesinde ilerlemeye devam edebildim. harikasın!
Frankie Loscavio

1
Bu konuyu her aldığımda bunu tekrar okudum ve buna tekrar oy vermek istiyorum. Btw, işte uglify({ output : { beautify : true }})
gulp

30

Oliver Salzburg'un yazımı harikaydı. Olumlu oy verildi.

Bu hatayı alabilecek herkes için ipucu. Benimki basitçe bir yönerge denetleyicisi için bir dizide geçmeyi unutmaktan kaynaklanıyordu:

KÖTÜ

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

İYİ

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

2
Bu çok arsız bir şeydi ... Uglify, son bir güncellemeye kadar benim için buna neden olmuyordu!
SamMorrowDrums

Sorunum aynıydı, ancak eklemem gereken şeyin /* @ngInject */işlevden önce olduğu ortaya çıktı . Dahil edilen her modülü
yazmaya

25

ng-app ile ng-tight-di kullanma

Angular 1.3 kullanıyorsanız ngApp ile ngStrictDi direktifini kullanarak kendinizi yaralı bir dünya kurtarabilirsiniz:

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

Şimdi - Ön küçültme - şey gelmez konsolu esecek ek açıklamaları kullanmak ve cenderelenmesini yığın izleri ile avcılık olmadan kahrolası adını görebilirsiniz.

Dokümanlara göre:

uygulama, açık işlev açıklaması kullanmayan (ve bu nedenle küçültme için uygun olmayan) işlevleri çağırmada başarısız olur

Bir uyarı , yalnızca ek açıklamaların olduğunu algılar , ek açıklamaların tamamlandığını değil.

Anlamı:

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

ThingB'nin ek açıklamanın parçası olmadığı anlaşılmayacaktır.

Bu ipucu için kredi , artık kullanımdan kaldırılan ngMin yerine tavsiye edilen ng-açıklama yapan kişilere gider.


Bunun daha fazla oylamaya ihtiyacı var. Bu, ngInject veya dize dizisi sözdizimini hiç kullanmayan bir uygulamada hata ayıklamak için harikadır.
Michael Pearson

11

Açıyı küçültmek için tek yapmanız gereken, bildiriminizi "dizi" bildirimi "moduna" değiştirmektir, örneğin:

Kimden:

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

İçin

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

Fabrika hizmetleri nasıl beyan edilir?

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

Biliyorum. Bu yüzden ngmin kullanıyoruz. Kaynağımızın bir kısmı veya bağımlılıkları ile ilgili bir sorunu olduğundan şüpheleniyorum. Bu yüzden bu sorunun kökenine inmeye çalışıyorum.
Der Hochstapler

1
Benim tavsiyem, kodunuzu bu şekilde oluşturmanızdır. Böylece herhangi bir minifier kullanabilirsiniz
Dalorzo

3
Ben am bu şekilde bizim kodunu oluşturmak. Ama olmayan dış bağımlılıklarımız var. ngmin, geçmişte bu sorunu bizim için iyi çözdü. Son bir değişikliğin bu sorunu yarattığını varsayıyorum. Şimdi bu sorunun kaynağını bulmak istiyorum, böylece kodumuzda, bağımlılığımızda veya muhtemelen ngmin'in kendisinde düzgün bir şekilde düzeltebilirim.
Der Hochstapler

Sorun, belirli bir bileşene veya koda çok özel bir konu gibi göründüğünden, en azından benim açımdan, rehberlik sağlamak zordur
Dalorzo

ngmin, dizi bildirimi kipini kullanmanızı gerektirmez, pek çok yararsız bildirim ekler.
Nanocom

8

Sadece aynı sorunu yaşadım ve basitçe, grunt oluşturma görevim için ngmin'i (artık kullanımdan kaldırıldı) ng-annotate ile değiştirerek çözdüm.

Görünüşe göre yeoman angular, bu işlemden itibaren ng-annotate kullanacak şekilde güncellendi: https://github.com/yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

Ancak benim gibi yeoman angular'ın daha eski bir sürümünü kullanıyorsanız, paketinizdeki ng-min yerine ng-annotate yazmanız yeterlidir.json:

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

çalıştırın npm install(ardından isteğe bağlı olarak npm prune) ve düzenleme taahhüdündeki değişiklikleri izleyin Gruntfile.js.


7

orijinal değişkenin adının ne olduğunu bilmek için değişkenlerin çirkinleşmesinin değişkenleri nasıl karıştırdığını değiştirebilirsiniz:

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

ve şimdi hata çok daha açık

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)

DÜZENLE

Şimdi çok açık ...

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

şimdi her değişken, orijinali de içeren benzersiz bir değere karıştırılır ... sadece küçültülmüş javascript'i açın ve "a_orig_ $ stateProvider_91212" veya her neyse arayın ... onu orijinal bağlamında göreceksiniz ...

daha kolay olamazdı ...


4

Ayrıca resolverotanın özelliğini de unutmayın . Ayrıca dizi olarak tanımlanmalıdır:

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

Bu, rotalarıma bir sürü çözüm eklediğimde başıma geldi. Beni saatlerce acı verici hata ayıklamadan kurtardınız, teşekkürler.
Paul McClean

3

Jeneratör-yudum açılı:

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

}

Her denetleyiciden, hizmetten, yönergeden önce / ** @ngInject * / yazın .


2

Uglify'nin değişken adlarınızı karıştırmasını / kısaltmasını istemiyorsanız, bunun için hızlı ve kirli bir düzeltme Gruntfile'ınızda mangle = false ayarlamaktır.

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

Bu sorunu çözebilir, ancak ortaya çıkan yapı boyutu, mangle devre dışı bırakıldığı için daha büyük olacaktır.
NotA

hala hiç çirkinleşmemekten daha küçük
mjwrazor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.