Помилка мініфікації Angular.module


82

Маючи найтемніший час, намагаючись зрозуміти, чому мініфікація не працює.

Я ввів через об'єкт масиву мої провайдери, які працювали перед функцією, за численними пропозиціями в Інтернеті, і все-таки "Невідомий постачальник: aProvider <- a"

Регулярні:

var app = angular.module('bpwApp', ['ui.bootstrap', 'ui', 'myTabs'])
    .config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){
    $routeProvider.
        when('/', {templateUrl: 'partials/home.jade', controller: HomeCtrl});

    $locationProvider.html5Mode(true);
    }])

Зменшене:

var app = angular.module('bpwApp', ['ui.bootstrap', 'ui', 'myTabs'])
    .config(['$routeProvider', '$locationProvider', function(a, b){
    a.
        when('/', {templateUrl: 'partials/home.jade', controller: HomeCtrl});

    b.html5Mode(true);
    }])

Будь-яка пропозиція буде дуже вдячна!


1
Що ви використовуєте для мініфікації коду? uglifyJS? Також перевірте: github.com/btford/ngmin ;)
AndreM96

Я використовував ngmin, все, що він робив, - це вишиковувати код у іншому форматі пробілів. Я спробував використовувати express-uglify як проміжне програмне забезпечення, але це не спрацьовувало, тому я спробував вручну, використовуючи онлайн-uglifier. У будь-якому випадку код закінчився однаковим.
BPWDevelopment

Крім того, чи немає зниклих ]? (до закриття ))
AndreM96

Був, я забув їх у цьому конкретному фрагменті. Це не змінює той факт, що "невідомий постачальник" все-таки трапляється :(
BPWDevelopment

2
Добре, ну, який онлайн-мініфер ти використовував? Це чудово працює з вашим кодом: marijnhaverbeke.nl/uglifyjs
AndreM96

Відповіді:


139

Я раніше стикався з цією проблемою з плагіном Grunt.js Uglify .

Одним з варіантів є мангл

uglify: {
  options: {
    mangle: false
  },

Я вважаю, що запускає функції регулярних виразів на "подібних рядках" і мініфіксує їх.

Наприклад:

angular.module("imgur", ["imgur.global","imgur.album"]);

Стане:

angular.module("a", ["a.global","a.album"]);

Вимкніть його --- ця функція погано грає з Angular.

Редагувати:

Якщо бути точнішим, як пояснює @JoshDavidMiller:

Зруйнуйте mangleлише mangles, як змінні, що насправді спричиняє проблему AngularJS. Тобто проблема полягає в ін’єкціях, а не у визначенні.

function MyCtrl($scope, myService)було б зіпсовано function MyCtrl(a, b), але визначення служби всередині рядка ніколи не повинно змінюватися.

  • Запуск ng-minперед запуском uglifyвирішує цю проблему.

3
Він оновив свій код. Його проблема полягала не в тому, що "$ locationProvider" став "b" або щось подібне. Це просто не спрацювало. Однак +1 за цю відповідь :)
AndreM96

1
Спасибі було важко знайти такий варіант.
reen

Я натрапив на те саме те саме, використовуючи кутовий завантажувальний ремінь + yeoman. Використовуючи кутовий генератор Yeoman, він створив distзбірку, яка мала б згадану помилку залежності "Невідомий постачальник". Налаштування mangle: falseвирішило проблему. (примітка: проблема була лише проблемою в gruntпобудованій, а distне в зручній для розробника appзбірці)
craigb

6
Є чи на mangle: true самому справі калічити «як струни»? Я майже впевнений, що це лише маніпулює змінні , що насправді спричиняє проблему AngularJS. Тобто проблема полягає в ін’єкціях, а не у визначенні. function MyCtrl($scope, myService)було б зіпсовано function MyCtrl(a, b), але визначення служби всередині рядка ніколи не повинно змінюватися. Запуск ng-minперед запуском uglifyвирішує цю проблему, чи не так?
Джош Девід Міллер,

1
ng-minв даний час припинено на користьng-annotate
Atav32

51

Проблема

Від AngularJS: Погані частини :

Angular має вбудований інжектор залежностей, який передаватиме відповідні об'єкти вашій функції на основі імен її параметрів:

function MyController($scope, $window) {
    // ...
}

Тут імена параметрів $scopeі $windowбудуть збігатись зі списком відомих імен, а відповідні об'єкти створюватимуть екземпляри та передаватимуться функції. Angular отримує імена параметрів, викликаючи toString()функцію, а потім аналізуючи визначення функції.

Проблема цього, звичайно, полягає в тому, що він перестає працювати в той момент, коли ви зменшуєте свій код . Оскільки ви дбаєте про взаємодію з користувачем, ви зменшите свій код, тому використання цього механізму DI зламає ваш додаток. Насправді, загальноприйнята методологія розробки полягає у використанні немініфікованого коду в розробці, щоб полегшити налагодження, а потім мінімізувати код під час надсилання на виробництво або постановку. У такому випадку ця проблема не випрямить свою потворну голову, поки ви не опинитеся в точці, де вона болить найбільше.

(...)

Оскільки цей механізм введення залежностей насправді не працює в загальному випадку, Angular також пропонує механізм, який працює. Безперечно, тут передбачено два. Ви можете передати масив приблизно так:

module.controller('MyController', ['$scope', '$window', MyController]);

Або ви можете встановити $injectвластивість у своєму конструкторі:

MyController.$inject = ['$scope', '$window'];

Рішення

Ви можете використовувати ng-annotateдля автоматичного додавання анотацій, необхідних для мініфікації:

ng-annotateдодає та видаляє анотації введення залежностей AngularJS. Він не нав'язливий, тому ваш вихідний код інакше залишається незмінним. Немає втрачених коментарів або перенесених рядків.

ng-annotateє швидшим і стабільнішим, ніж ngmin(який зараз застарів), і він має плагіни для багатьох інструментів:


Починаючи з AngularJS 1.3, є також новий параметр, який ngAppназивається ngStrictDi:

якщо цей атрибут присутній в елементі програми, інжектор буде створений у режимі "строго-ді". Це означає, що програма не зможе викликати функції, які не використовують явну анотацію функції (і, отже, непридатні для мініфікації), як описано в посібнику введення залежностей , а корисна інформація про налагодження допоможе відстежити корінь цих помилок.


1
+1 Просто перехід на grunt-ng-annotate вирішив цю проблему, і ngmin зараз уже застаріло, тож це ще одна причина для переходу.
Pier-Luc Gendreau

це було виправлення, яке я шукав днями!
jack.the.ripper

Я стикаюся з тією ж проблемою створення мініфікованого коду за допомогою browserify, angular та gulp-minify. Я видалив gulp minify і замінив його gulp-ng-annotate, код все ще мініфікований, але все ще не працює.
Dimitri Kopriwa

@BigDong, якщо ви використовуєте browserify, найкращий спосіб - це, мабуть, увімкнути ngStrictDi(щось на зразок <div ng-app="myApp" ng-strict-di />) і використовувати gulp-ng-annotateнавіть у своєму середовищі для розробки, щоб ви могли легко відстежувати ці помилки мініфікації.
Паоло Моретті

@PaoloMoretti Я спробував за допомогою ngStrictDi та gulp-ng-annotate, browserify може об'єднуватися, але код не мініфікований, чи не повинен це бути завданням ng-annotate?
Димитрій Копріва

22

Я отримав ту ж помилку. Однак для мене проблемою є декларація контролера директив. Ви повинні зробити це замість цього.

myModule.directive('directiveName', function factory(injectables) {
    var directiveDefinitionObject = {
      templateUrl: 'directive.html',
      replace: false,
      restrict: 'A',
      controller: ["$scope", "$element", "$attrs", "$transclude", "otherInjectables",
        function($scope, $element, $attrs, $transclude, otherInjectables) { ... }]
    };
    return directiveDefinitionObject;
  });

https://github.com/angular/angular.js/pull/3125


1
Дякую @angelokh! У мене була саме ця проблема. Я використовував controller: function ($scope) {}позначення.
jbasko

2
Це більше схоже на вирішення фактичної проблеми, ніж mangle: falseпропонується в інших відповідях, оскільки ми все ще хочемо мати змогу перекручувати імена.
jbasko

9

У мене була подібна проблема з використанням grunt, ngmin та uglify.

Я запустив процес у такому порядку: concat, ngmin, uglify

Я продовжував отримувати помилку інжектора $ з angular, поки не додав у uglify options mangle: false - тоді все було виправлено.

Я також намагався додати винятки, щоб углифікувати так:

 options: {
  mangle: {
     except: ['jQuery', 'angular']
  }
}

Але безрезультатно ...

Ось мій gruntFile.js для подальших роз’яснень:

module.exports = function(grunt) {
'use strict';
// Configuration goes here
grunt.initConfig({
    pkg: require('./package.json'),

    watch: {
        files: ['scripts/**/*.js', 'test/**/*spec.js', 'GruntFile.js'],
        tasks: ['test', 'ngmin']
    },

    jasmine : {
        // Your project's source files
        src : ['bower_components/angular/angular.js', 'bower_components/angular-mocks/angular-mocks.js', 'scripts/app.js', 'scripts/**/*.js' ],
        // Your Jasmine spec files

        options : {
            specs : 'test/**/*spec.js',
            helpers: 'test/lib/*.js'
        }
    },

    concat: {
      dist : {
          src: ['scripts/app.js', 'scripts/**/*.js'],
          dest: 'production/js/concat.js'
      }
    },

    ngmin: {
        angular: {
            src : ['production/js/concat.js'],
            dest : 'production/js/ngmin.js'
        }

    },

    uglify : {
        options: {
            report: 'min',
            mangle: false
        },
        my_target : {
            files : {
                'production/app/app.min.js' : ['production/js/ngmin.js']
            }
        }
    },

  docular : {
      groups: [],
      showDocularDocs: false,
      showAngularDocs: false
  }

});

// Load plugins here
grunt.loadNpmTasks('grunt-ngmin');
grunt.loadNpmTasks('grunt-docular');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-connect');

// Define your tasks here
grunt.registerTask('test', ['jasmine']);
grunt.registerTask('build', ['concat', 'ngmin', 'uglify']);
grunt.registerTask('default', ['test', 'build', 'watch']);

};


АГ ДЯКУЮ ДЯКУЮ! це заощадило мені стільки часу.
mylescc

5

Припущення AndrewM96 ng-minправильне.

Вирівнювання та пробіл мають значення як для Uglify, так і для Angular.


10
Здається, ng-min просто обробляє кутові файли, щоб вони були дружніми uglify. У процесі побудови ми використовуємо і те, і інше ( ng-minраніше uglify), і все ще мали проблему з потворним js.
craigb

4
Чому це позначено як відповідь? (Крім того, AndrewM96 повинен бути AndreM96)
Джей

хоча в документах ng-min звучить багатообіцяюче, це не вирішує проблему
special0ne

У @craigb така сама проблема. Можливо, це поєднання речей. Я також використовую RequireJS. В основному я роблю все, що змінюють функції ng-min, я повинен робити сам і все одно запускати ng-min, тоді як run потрібно будувати, а потім запускати uglify з mangle true. Здається, цей процес працює більшість разів.
escapedcat

3

У мене була подібна проблема. І вирішив це наступним чином. Нам потрібно запустити модуль Gulp, який називається gulp-ng-annotate, перш ніж запускати uglify. Отже, ми встановлюємо цей модуль

npm install gulp-ng-annotate --save-dev

Потім виконайте вимогу в Gulpfile.js

ngannotate = require(‘gulp-ng-annotate’)

І у вашому завданні usemin зробіть щось подібне

js: [ngannotate(), uglify(),rev()] 

Це вирішило це для мене.

[РЕДАКТУВАТИ: виправлені помилки]


gulp-MG-примітка повинна бути gulp-NG-примітка?
hally9k

Так, вибачте за помилку. Де читається mg-annotateзавждиng-annotate
Пауло Борральо Мартінс


2

Це дуже складно налагодити, оскільки багато служб називаються однаковими (переважно e або a). Це не допоможе вирішити помилку, але надасть вам назву невирішеної служби, яка дозволить вам відстежувати у понівеченому виведенні розташування в коді і, нарешті, дозволить вирішити проблему:

Зайдіть в lib/scope.jsUglify2 ( node_modules/grunt-contrib-uglify/node_modules/uglify-js/lib/scope.js) і замініть рядок

this.mangled_name = this.scope.next_mangled(options);

з

this.mangled_name = this.name + "__debugging_" + counter++
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.