Angular.module缩小bug

时间:2013-06-21 15:16:32

标签: javascript angularjs minify uglifyjs

有最艰难的时间试图弄清楚为什么缩小不起作用。

我已经通过数据对象注入了我的提供者之前在网上提供的众多建议的功能,但仍然是“未知的提供者: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);
    }])

任何建议都有很大的意义!

8 个答案:

答案 0 :(得分:139)

我之前使用Grunt.js Uglify插件遇到了这个问题。

其中一个选项是 mangle

uglify: {
  options: {
    mangle: false
  },

我相信我会在“像字符串”上运行正则表达式函数并对它们进行微调。

例如:

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

会变成:

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

禁用它 - 此功能对Angular不起作用。

编辑:

更确切地说,正如@JoshDavidMiller所解释的那样:

Uglify mangle只变形变量,这实际上是导致AngularJS问题的原因。也就是说,问题在于注入而不是定义。

function MyCtrl($scope, myService)会被修改为function MyCtrl(a, b),但字符串内的服务定义永远不会被改变。

  • 在运行ng-min之前运行uglify可以解决此问题。

答案 1 :(得分:50)

问题

来自AngularJS: The Bad Parts

  

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-annotatengmin更快更稳定(现已弃用),它有很多工具的插件:


从AngularJS 1.3开始,ngApp中还有一个名为 ngStrictDi 的新参数:

  

如果app元素上存在此属性,则注入器将为   在" strict-di"中创建模式。这意味着应用程序将失败   调用不使用显式函数注释的函数(和   因此不适合缩小),如Dependency Injection guide中所述,有用的调试信息将有助于跟踪   这些错误的根源。

答案 2 :(得分: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

答案 3 :(得分:9)

我使用grunt,ngmin和uglify有类似的问题。

我按顺序运行了这个过程:concat,ngmin,uglify

我继续从角度获取$ injector错误,直到我在uglify选项中添加了mangle:false - 然后一切都被修复了。

我还尝试将这些例外添加到uglify中:

 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']);

};

答案 4 :(得分:5)

AndrewM96对ng-min的建议是正确的。

对齐和空白对Uglify和Angular都很重要。

答案 5 :(得分:3)

我有类似的问题。并通过以下方式解决了它。在运行uglify之前,我们需要运行一个名为gulp-ng-annotate的Gulp模块。 所以我们安装那个模块

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

然后在Gulpfile.js中执行require

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

在你的usemin任务中做这样的事情

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

这解决了我。

[编辑:修正错别字]

答案 6 :(得分:2)

Uglify可以选择禁用特定文件的修改:

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

https://github.com/gruntjs/grunt-contrib-uglify#reserved-identifiers

答案 7 :(得分:2)

这很难调试,因为许多服务的名称相同(主要是e或a)。这不会解决错误,但会为您提供未解析服务的名称,这使您可以在uglified输出中跟踪代码中的位置,最后使您能够解决问题:

进入Uglify2 lib/scope.jsnode_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++