Неизвестный провайдер: aProvider ‹- a Как найти исходного провайдера?

Когда я загружаю минимизированную (через UglifyJS) версию моего приложения AngularJS, я получаю в консоли следующую ошибку:

Unknown provider: aProvider <- a

Теперь я понимаю, что это связано с искажением имени переменной. Неисправленная версия работает нормально. Однако я действительно хочу использовать изменение имен переменных, так как это значительно уменьшает размер нашего выходного файла JS.

По этой причине мы используем ngmin в нашем процессе сборки, но, похоже, это не решает эту проблему. проблема, хотя она хорошо служила нам в прошлом.

Итак, чтобы отладить эту проблему, я включил исходные карты в нашей задаче uglify grunt. Они генерируются просто отлично, и Chrome действительно загружает карты с сервера. Тем не менее, я все еще получаю то же самое бесполезное сообщение об ошибке, хотя у меня сложилось впечатление, что теперь я должен увидеть исходное имя поставщика.

Как заставить Chrome использовать исходные карты, чтобы сказать мне, какой провайдер здесь проблема, или, наоборот, как я могу узнать провайдера другим способом?


person Der Hochstapler    schedule 10.02.2014    source источник
comment
Вы можете попробовать добавить отдельные комментарии к каждому исходному файлу JS (если это еще не так) и использовать параметр saveComments UglifyJS: это даст вам представление о том, какой файл содержит неправильный код.   -  person JB Nizet    schedule 11.02.2014
comment
Вы случайно не пользуетесь декораторами? Я обнаружил, что ngmin, похоже, не переписывает декораторы должным образом, когда я использовал его в прошлом, что приводит к ошибкам, подобным вашим.   -  person dherman    schedule 11.02.2014
comment
@JBNizet: мне нравится эта идея, но добавление этой директивы к параметрам, похоже, не дает никакого эффекта.   -  person Der Hochstapler    schedule 11.02.2014
comment
@dherman: Не могли бы вы привести пример декораторов? Я не уверен, что они будут в этом контексте.   -  person Der Hochstapler    schedule 11.02.2014
comment
См. github.com/gruntjs/grunt-contrib-uglify (если вы используете grunt) . Значение опции должно быть all.   -  person JB Nizet    schedule 11.02.2014
comment
@JBNizet: Да, я использую grunt. Я просматривал документацию и использую "all". Вот почему я смущен тем, что не получаю ожидаемого результата. Я также добавил beautify:true к параметрам, чтобы получить более четкий вывод. Хотя вообще без комментариев. Несмотря на это, я не уверен, как определить проблемный источник с точки, в которой возникла ошибка.   -  person Der Hochstapler    schedule 11.02.2014
comment
Извините, я никогда не использовал эту опцию. Я просто знал, что он существует, прочитав документацию. Вы можете попробовать обмануть Uglify, объявив уникальную строку в начале каждого файла: var foo = "I'm in file Foo.js";   -  person JB Nizet    schedule 11.02.2014
comment
Или вы можете опубликовать ссылку на исходный код здесь. Не должно быть так сложно найти причину проблемы. В Chrome есть довольно хороший редактор кода, который помогает читать минимизированный исходный код. Тогда это просто вопрос отслеживания того, где возникает исключение.   -  person Michał Miszczyszyn    schedule 11.02.2014
comment
@JBNizet: Да, проблема, которая у меня все еще есть, заключается в том, что даже если бы я мог пометить все файлы, я не могу определить, какой файл вызывает проблему с точки, в которой возникает ошибка. Стек вызовов представляет собой беспорядок искаженных переменных, и я не могу проанализировать точку в источнике, которая на самом деле вызывает ошибку. Даже с улучшенным исходным кодом и несколькими точками останова я не смог найти источник проблемы. Вся иерархия вызовов на данный момент кажется очень сложной.   -  person Der Hochstapler    schedule 11.02.2014
comment
@Miszy: К сожалению, я не могу опубликовать здесь исходный код, так как это не публичный проект. Я знаю, где выбрасывается исключение. Но я не знаю, как определить местоположение проблемного источника оттуда, так как код, который оценивает определения Angular, довольно сложный.   -  person Der Hochstapler    schedule 11.02.2014
comment
@OliverSalzburg Вот пример из документации angular: docs.angularjs.org/api/ AUTO.$provide#methods_decorator   -  person dherman    schedule 11.02.2014
comment
@dherman: А, понятно. Нет, мы не используем декораторы в нашем исходном коде, и быстрый grep также не выявил никаких применений в наших зависимостях.   -  person Der Hochstapler    schedule 11.02.2014
comment
Вы можете проверить... заголовок ="неизвестный провайдер как найти исходного провайдера"> stackoverflow.com/questions/21688681/   -  person Deepak Patil    schedule 17.04.2014
comment
ngAnnotate не работает из-за нового способа определения компонентов angular 1.5: github.com/olov/ng-annotate/issues/   -  person Michael Trouw    schedule 06.04.2016


Ответы (9)


Я все еще хотел бы знать, как я мог найти место в нашем исходном коде, которое вызвало эту проблему, но с тех пор я смог найти проблему вручную.

В глобальной области действия была объявлена ​​функция контроллера вместо использования вызова .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. Вы захотите разместить точку останова, где она выдает исключение:

введите здесь описание изображения

Теперь, когда вы снова запустите приложение, будет достигнута точка останова, и вы сможете перейти вверх по стеку вызовов. Будет выполнен вызов из invoke в injector.js, узнаваемый по строке «Неверный токен инъекции»:

введите здесь описание изображения

Параметр locals (искаженный до d в моем коде) дает довольно хорошее представление о том, какой объект в вашем исходном коде является проблемой:

введите здесь описание изображения

Быстрый grep по нашему источнику находит много экземпляров modalInstance, но, идя оттуда, было легко найти это место в источнике:

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

Что нужно изменить на:

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

В случае, если переменная не содержит полезной информации, вы также можете прыгнуть выше по стеку и нажать на вызов invoke, который должен иметь дополнительные подсказки:

введите здесь описание изображения

Не допустить повторения этого

Теперь, когда вы, надеюсь, нашли проблему, я чувствую, что должен упомянуть, как лучше всего избежать повторения этого в будущем.

Очевидно, вы могли бы просто везде использовать аннотацию встроенного массива или ( в зависимости от ваших предпочтений) $inject аннотация свойства и просто постарайтесь не забыть об этом в будущем. Если вы это сделаете, обязательно включите строгий режим внедрения зависимостей. , чтобы отловить подобные ошибки на ранней стадии.

Осторожно! Если вы используете Angular Batarang, StrictDI может вам не подойти, так как Angular Batarang внедряет в ваш код без аннотаций (плохой Batarang!).

Или вы можете позволить ng-annotate позаботиться об этом. Я настоятельно рекомендую это сделать, так как это устраняет множество потенциальных ошибок в этой области, например:

  • Отсутствует аннотация DI
  • Аннотация DI неполная
  • Аннотация DI в неправильном порядке

Поддержание аннотаций в актуальном состоянии — это просто заноза в заднице, и вам не нужно делать это, если это можно сделать автоматически. ng-annotate делает именно это.

Он должен хорошо интегрироваться в процесс сборки с помощью grunt-ng-annotate и gulp-ng-annotate.

person Der Hochstapler    schedule 14.02.2014
comment
Это фантастическая рецензия, написанная с осторожностью. Я только что столкнулся с этой проблемой, кажется, проблема где-то глубоко в ngmin. Ваши советы помогли мне понять, где искать. В конце концов, я просто преобразовал все свои угловые параметры в массив, и проблема исчезла. Все предыдущие сборки ng-minified просто отлично, и ничего существенного не изменилось. Я не добавлял никаких глобальных функций — он просто загадочным образом перестал работать из-за искажения какого-то контроллера/директивы/службы/фильтра? - person zenocon; 08.05.2014
comment
Это был отличный источник помощи. Я не знал, что вы должны использовать синтаксис массива (встроенный) также для других функций, таких как разрешение маршрутизатора, .run, .config и т. д. - person VDest; 27.08.2014
comment
В моем случае это был контроллер в директиве. Если в переменной 'd' вы увидите $attr, это, вероятно, та же проблема. Вы должны заключить параметры в скобки массива для внутреннего контроллера директив. контроллер: [$scope, function($scope){...}] вместо контроллера: function($scope){...} - person alex naumov; 24.09.2014
comment
Большое спасибо за вашу запись и решение с использованием безопасной инъекции зависимостей/обозначения массива для ссылки на функцию var. У меня тоже была эта ошибка, и благодаря вашему решению я смог продолжить движение вперед. ты жжешь! - person Frankie Loscavio; 21.10.2014
comment
Каждый раз, когда у меня возникает эта проблема, я снова читаю это и хочу снова проголосовать за это. Кстати, вот как настроить версию gulp uglify({ output : { beautify : true }}) - person Eugene Gluhotorenko; 11.11.2015
comment
изменено app.run(function($httpBackend){//.......}; на app.run(['$httpBackend',function($httpBackend){//......}]; - person Aakash; 17.11.2015
comment
Отключение углифьера, добавление ng-strict-di в строку ng-app: <body ng-app="lacote" ng-strict-di> И angular подскажет, где проблема! исправить и вернуть Uglify - person PyWebDesign; 01.02.2016
comment
Я не сталкивался с этой проблемой в прошлом, но только что столкнулся с ней при сборке с использованием $provider и $filterProvider в моем app.js. Я использовал ng-annotate все это время и пытался добавить полную форму прямого впрыска, но это все равно не сработало. Единственный способ, которым я смог решить эту проблему, состоял в том, чтобы отключить опцию mangle uglify (облом). - person David Rhoderick; 29.09.2016
comment
@ArtlyticalMedia Иногда ng-annotate не распознает функцию, требующую аннотации. Мы всегда используем @ngAnnotate JSDoc для каждой функции, которую мы ожидаем аннотировать. - person Der Hochstapler; 29.09.2016
comment
Привет, я всегда включал строгий режим и обычно не получал ошибок по этому поводу. Но когда я использую плагин webpack uglify, у него всегда возникает ошибка «неизвестный провайдер». - person runchu; 12.06.2019
comment
Я не могу проголосовать за вас достаточно. Большое спасибо за подробный ответ! - person Freego; 19.03.2021

Рецензия Оливера Зальцбурга была фантастической. Проголосовал.

Совет для тех, у кого может быть эта ошибка. Мой был просто вызван тем, что вы забыли передать массив для директивного контроллера:

ПЛОХОЙ

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

ХОРОШО

return {
    restrict: "E",
    scope: {                
    },
    controller: ["$scope", ExampleDirectiveController],
    templateUrl: "template/url/here.html"
};
person Ash Clarke    schedule 15.10.2014
comment
Это было так дерзко... Uglify не вызывал этого до недавнего обновления! - person SamMorrowDrums; 07.12.2015
comment
Моя проблема была такой же, но оказалось, что мне нужно было добавить /* @ngInject */ перед функцией. Кажется, он выполняет сложную часть инъекции без необходимости вводить каждый включенный модуль (я использую Yeoman) - person Nicholas Blasgen; 12.04.2016

использовать ng-strict-di с ng-app

Если вы используете Angular 1.3, вы можете избавить себя от множества проблем, используя ngStrictDi директива с ngApp:

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

Теперь — предварительная минимизация — все, что не использует аннотации, взорвет вашу консоль, и вы сможете увидеть чертово имя, не просматривая искаженные трассировки стека.

Согласно документам:

приложение не сможет вызывать функции, которые не используют явную аннотацию функции (и, следовательно, не подходят для минимизации)

Одно предостережение: он обнаруживает только наличие существующих аннотаций, а не то, что аннотации завершены.

Имея в виду:

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

Не уловит, что ThingB не является частью аннотации.

Кредит за этот совет принадлежит ng-annotate, которые рекомендуются вместо устаревшего ngMin.

person Mark Fox    schedule 06.02.2015
comment
Это требует больше голосов. Это отлично подходит для отладки приложения, которое никогда не использовало ngInject или синтаксис массива строк. - person Michael Pearson; 08.07.2017

Чтобы минимизировать angular, все, что вам нужно сделать, это изменить ваше объявление на объявление «массива» «режим», например:

От:

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
    };
}]);
person Dalorzo    schedule 10.02.2014
comment
Я знаю. Вот почему мы используем ngmin. Я подозреваю, что у него проблема с какой-то частью нашего источника или его зависимостями. Вот почему я пытаюсь добраться до корня этой проблемы. - person Der Hochstapler; 11.02.2014
comment
Я рекомендую вам создавать свой код таким образом. Таким образом, вы можете использовать любой минификатор - person Dalorzo; 11.02.2014
comment
Я я создаю наш код таким образом. Но у нас есть внешние зависимости, которых нет. ngmin хорошо решал эту проблему для нас в прошлом. Я предполагаю, что недавнее изменение создало эту проблему. Теперь я хотел бы найти источник этой проблемы, чтобы правильно исправить ее в нашем коде, нашей зависимости или, возможно, в самом ngmin. - person Der Hochstapler; 11.02.2014
comment
Поскольку проблема кажется очень специфичной для конкретного компонента или кода, трудно дать рекомендации, по крайней мере, с моей стороны. - person Dalorzo; 11.02.2014
comment
ngmin не требует от вас использования режима объявления массива, он добавляет много бесполезных объявлений. - person Nanocom; 11.02.2014

У меня была такая же проблема, и я решил ее, просто заменив ngmin (теперь устаревший) на ng-annotate для моей задачи сборки grunt.

Похоже, что yeoman angular также был обновлен для использования ng-annotate с момента этой фиксации: /yeoman/generator-angular/commit/3eea4cbeb010eeaaf797c17604b4a3ab5371eccb

Однако, если вы используете более старую версию yeoman angular, как и я, просто замените ng-min на ng-annotate в вашем package.json:

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

запустите npm install (затем, при желании, npm prune) и следуйте изменениям в коммите, чтобы отредактировать Gruntfile.js.

person Xuwen    schedule 13.09.2014

чтобы узнать, каким было исходное имя переменной, вы можете изменить то, как 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++;
    [...]
  }
};

теперь каждая переменная преобразуется в уникальное значение, которое также содержит оригинал... просто откройте уменьшенный javascript и найдите "a_orig_$stateProvider_91212" или что-то еще... вы увидите его в исходном контексте...

проще некуда...

person user3338098    schedule 04.08.2015

Также не забывайте о свойстве resolve маршрута. Он также должен быть определен как массив:

$routeProvider.when('/foo', {
    resolve: {
        bar: ['myService1', function(myService1) {
            return myService1.getThis();
        }],
        baz: ['myService2', function(myService2) {
            return myService2.getThat();
        }]
    }
});
person Petr Felzmann    schedule 25.02.2015
comment
Это случилось со мной, когда я добавил кучу разрешений к своим маршрутам. Вы потенциально сэкономили мне часы мучительной отладки, спасибо. - person Paul McClean; 08.10.2015

С генератором-глотком-угловым:

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

}

Напишите /** @ngInject */ перед каждым контроллером, службой, директивой.

person Maxim Danilov    schedule 29.07.2016

Быстрое и грязное исправление для этого, если вам не требуется, чтобы Uglify искажал/сокращал ваши имена переменных, заключается в том, чтобы установить mangle = false в вашем Gruntfile

    uglify: {
        compile: {
            options: {
                mangle   : false,
                ...
            },
        }
    }
person Parris Varney    schedule 19.11.2015
comment
Это может решить проблему, но результирующий размер сборки будет больше, так как мангл отключен. - person NotABot; 02.01.2018
comment
все же меньше, чем вообще не уродовать - person mjwrazor; 09.05.2018