Angular.module minification bug

前端 未结 8 858
情深已故
情深已故 2020-11-28 03:50

Having the darnedest time trying to figure out why minification is not working.

I have injected via an array object my providers prior the function per numerous sugg

相关标签:
8条回答
  • 2020-11-28 03:59

    I had a similar issue using grunt, ngmin and uglify.

    I ran the process in this order: concat, ngmin, uglify

    I was continuing to get the $injector error from angular until I added in the uglify options mangle: false - then everything was fixed.

    I also tried to add the exceptions to uglify like this:

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

    But to no avail...

    Here is my gruntFile.js for further clarification:

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

    };

    0 讨论(0)
  • 2020-11-28 04:01

    I got same error. However, for me, the problem is directives' controller declaration. You should do this instead.

    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

    0 讨论(0)
  • 2020-11-28 04:05

    I had a similar problem. And solved it the following way. We need to run a Gulp module called gulp-ng-annotate before we run uglify. So we install that module

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

    Then do the require in Gulpfile.js

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

    And in your usemin task do something like this

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

    That solved it for me.

    [EDIT: Fixed typos]

    0 讨论(0)
  • 2020-11-28 04:05

    Uglify has an option to disable mangling on specific files:

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

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

    0 讨论(0)
  • Problem

    From AngularJS: The Bad Parts:

    Angular has a built in dependency injector that will pass appropriate objects to your function based on the names of its parameters:

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

    Here, the names of the parameters $scope and $window will be matched against a list of known names, and corresponding objects get instantiated and passed to the function. Angular gets the parameter names by calling toString() on the function, and then parsing the function definition.

    The problem with this, of course, is that it stops working the moment you minify your code. Since you care about user experience you will be minifying your code, thus using this DI mechanism will break your app. In fact, a common development methodology is to use unminified code in development to ease debugging, and then to minify the code when pushing to production or staging. In that case, this problem won’t rear its ugly head until you’re at the point where it hurts the most.

    (...)

    Since this dependency injection mechanism doesn’t actually work in the general case, Angular also provides a mechanism that does. To be sure, it provides two. You can either pass along an array like so:

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

    Or you can set the $inject property on your constructor:

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

    Solution

    You can use ng-annotate for auto adding annotations required for minifying:

    ng-annotate adds and removes AngularJS dependency injection annotations. It is non-intrusive so your source code stays exactly the same otherwise. No lost comments or moved lines.

    ng-annotate is faster and stabler than ngmin (which is now deprecated) and it has plugins for many tools:

    • grunt-ng-annotate
    • gulp-ng-annotate
    • browserify-annotate

    Starting from AngularJS 1.3 there's also a new param in ngApp called ngStrictDi:

    if this attribute is present on the app element, the injector will be created in "strict-di" mode. This means that the application will fail to invoke functions which do not use explicit function annotation (and are thus unsuitable for minification), as described in the Dependency Injection guide, and useful debugging info will assist in tracking down the root of these bugs.

    0 讨论(0)
  • 2020-11-28 04:17

    I ran into this problem before with Grunt.js Uglify plugin.

    One of the options are mangle

    uglify: {
      options: {
        mangle: false
      },
    

    Which I believe runs regex functions on "like strings" and minifys them.

    For example:

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

    Would become:

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

    Disable it --- this feature doesn't play nice with Angular.

    Edit:

    To be more precise as @JoshDavidMiller explains:

    Uglify mangle only mangles like variables, which is what actually causes the AngularJS problem. That is, the problem is in injection and not definition.

    function MyCtrl($scope, myService) would get mangled to function MyCtrl(a, b), but the service definition inside of a string should never get altered.

    • Running ng-min before running uglify solves this problem.
    0 讨论(0)
提交回复
热议问题