Angularjs minification using grunt uglify resulting in js error

26,269

Solution 1

You have to use the string-injection based syntax that ensure that the minified version points to the good dependancy :

function checkInCtrl ($scope, $rootScope, $location, $http){}

becomes :

['$scope', '$rootScope', '$location', '$http', function checkInCtrl ($scope, $rootScope, $location, $http){}]

Solution 2

Navdeep,

The suggested solution from Bixi will work. However the easier way is just to use ngmin Grunt plugin. Using this plugin, you don't need to handle the dependency injection like what you did and also no need for the special syntax like Bixi.

To use it, make sure you have grunt-ngmin and that you call it before uglify.

Your Gruntfile.js:

ngmin: {
  dist: {
    files: [{
      expand: true,
      cwd: '.tmp/concat/scripts',
      src: '*.js',
      dest: '.tmp/concat/scripts'
    }]
  }
},

....

grunt.registerTask('build', [
  'ngmin',
  'uglify',
]);

Solution 3

For info, ngMin has been deprecated. You should use ngAnnotate instead which works beautifully with grunt and gulp.

Solution 4

Getting uglify and minify to work will reveal (as it did in my case) places where injected variables are changed from something like $scope to 'a' Example: This code:

controller: function($scope) {
        $scope.showValidation= false;
        this.showValidation = function(){
            $scope.showValidation = true;
        };
    }

after minify and uglify becomes:

controller:function(a){a.showValidation=!1,this.showValidation=function(){a.showValidation=!0}}

And you get an error because 'a' is not the same as $scope.

Solution is to explicitly declare the injected variables:

controller: ['$scope', function($scope) {
        $scope.showValidation= false;
        this.showValidation = function(){
            $scope.showValidation = true;
        };
    }]

after minify and uglify becomes:

controller:["$scope",function(a){a.showValidation=!1,this.showValidation=function(){a.showValidation=!0}}]

Now 'a' is mapped to $scope.

Share:
26,269
Navdeep
Author by

Navdeep

Javascript Developer - Have excellent grip over javascript language. I have worked on nodejs, expressjs, socketio, phonegap, angularjs, sailsjs.

Updated on July 16, 2020

Comments

  • Navdeep
    Navdeep almost 4 years

    In angularjs we pass parameters as dependency injection. For example,

    function checkInCtrl ($scope, $rootScope, $location, $http){
    …..
    ….
    }
    

    So when it gets minified, it becomes like,

    function checkInCtrl(a,b,c,d){
    }
    

    Now a,b,c,d won’t be interpreted as $scope, $rootScope, $location, $http respectively by angular and whole code fails to work. For this angularjs has provided one solution, which is

    checkInCtrl.$inject = ['$scope', '$rootScope', $location', '$http'];
    

    we can inject different dependencies by using above syntax. This worked well till I didn’t use some custom angular service as dependency. So for example ,

    if I have something like

    function checkInCtrl ($scope, $rootScope, $location, $http){
    …..
    ….
    }
    

    It works with given solution, but if I have something like

    function checkInCtrl ($scope, $rootScope, $location, $http, customService){
    …..
    ….
    }
    

    Where customService is something like

    angular.module(customService, ['ngResource'])
                    .factory('abc', function($resource) {
                                    return $resource('/abc');
                    })
    

    It’s minified version doesn’t get interpreted properly by angular.

    As we had to start project development activities, we couldn’t spend enough time to look into matter and we started using controller without minifying them. So first question is whether there is such problem with angular or I made some mistake and due to which it didn't work? If such issue exist,what is solution to it?

  • Navdeep
    Navdeep about 10 years
    Hey Bixi, both 'checkInCtrl.$inject = ['$scope', '$rootScope', $location', '$http']' and '['$scope', '$rootScope', '$location', '$http', function checkInCtrl ($scope, $rootScope, $location, $http){}]' work the same way. I have used first one. The problem is when we use a custom service as one of the parameter in function
  • Jscti
    Jscti about 10 years
    Well when your code is uglified, only the second one will work
  • Navdeep
    Navdeep about 10 years
    The problem is when we use a custom service as one of the parameter in function otherwise first solution works, so are you saying solution suggested by you will work for custom service as well?
  • Jscti
    Jscti about 10 years
    Yeah, it's designed to handle custom or standard dependancies. Take a look here for example : thegreenpizza.github.io/2013/05/25/…
  • ngasull
    ngasull about 10 years
    If you'd like to understand AngularJS's dependency injection concepts deeply, I strongly recommend you to check the doc: docs.angularjs.org/guide/di Enjoy!
  • Navdeep
    Navdeep about 10 years
    Thanks Bixi, it works and thanks for the link [link]thegreenpizza.github.io/2013/05/25/… It has some good information. Blint, thanks for angularjs doc link as well.
  • Navdeep
    Navdeep about 10 years
    Hey Lee, This is the simplest way to achieve minification for an angular app. It also works. So thanks. But the drawback that I observed was that minified file size was almost double than the size of file created using uglify.
  • suriyanto
    suriyanto about 10 years
    I tested my project with both ngmin and without ngmin, but can't seem to see the difference. You ended up only with 2 js file: scripts.js and vendor.js, right? Which of these 2 files have the biggest size difference?
  • Navdeep
    Navdeep about 10 years
    Hey @Bixi, there is one more question. The link you shared has details of how to define a controller, a factory, a service or a directive to avoid problem after minification. But what would be syntax when there are multiple modules and one module is dependent on other. So what will be syntax for angular.nodule('X',['Y','Z'])? I don't have multiple modules in this project, but want to know if syntax is different.
  • Navdeep
    Navdeep about 10 years
    Hey Lee, I am creating one consolidated uglified file of all my controller files using ngmin and thus generated file is double in size than file generated using uglify.
  • Ankit Gupta
    Ankit Gupta over 9 years
    @Cétia I have another case,I have some third party API in which this is written domUtilityService.digest = function($scope) { } now $scope is minified into a and getting error,my minification tool is not annotating this,any idea about that?
  • Mohamed Ali
    Mohamed Ali about 7 years
    it's the first time for me to know what the string injection based syntax is for!
  • Youcef Moulahoum
    Youcef Moulahoum almost 6 years
    Thanks a lot @Cétia , your response helped me to face a big problem and also allow me to know what the string injection is used for ! thanks again !