Minification and Annotation

Minification and Annotation

ng-annotate

[Style Y100]
  • Use ng-annotate for Gulp or Grunt and comment functions that need automated dependency injection using /* @ngInject */

    Why?: This safeguards your code from any dependencies that may not be using minification-safe practices.

    Why?: ng-min is deprecated

    I prefer Gulp as I feel it is easier to write, to read, and to debug.

    The following code is not using minification safe dependencies.

    angular
        .module('app')
        .controller('AvengersController', AvengersController);
    
    /* @ngInject */
    function AvengersController(storage, avengerService) {
        var vm = this;
        vm.heroSearch = '';
        vm.storeHero = storeHero;
    
        function storeHero() {
            var hero = avengerService.find(vm.heroSearch);
            storage.save(hero.name, hero);
        }
    }
    

    When the above code is run through ng-annotate it will produce the following output with the $inject annotation and become minification-safe.

    angular
        .module('app')
        .controller('AvengersController', AvengersController);
    
    /* @ngInject */
    function AvengersController(storage, avengerService) {
        var vm = this;
        vm.heroSearch = '';
        vm.storeHero = storeHero;
    
        function storeHero() {
            var hero = avengerService.find(vm.heroSearch);
            storage.save(hero.name, hero);
        }
    }
    
    AvengersController.$inject = ['storage', 'avengerService'];
    

    Note: If ng-annotate detects injection has already been made (e.g. @ngInject was detected), it will not duplicate the $inject code.

    Note: When using a route resolver you can prefix the resolver’s function with /* @ngInject */ and it will produce properly annotated code, keeping any injected dependencies minification safe.

    // Using @ngInject annotations
    function config($routeProvider) {
        $routeProvider
            .when('/avengers', {
                templateUrl: 'avengers.html',
                controller: 'AvengersController',
                controllerAs: 'vm',
                resolve: { /* @ngInject */
                    moviesPrepService: function(movieService) {
                        return movieService.getMovies();
                    }
                }
            });
    }
    

    Note: Starting from Angular 1.3 you can use the ngApp directive’s ngStrictDi parameter to detect any potentially missing minification safe dependencies. When present the injector will be created in “strict-di” mode causing the application to fail to invoke functions which do not use explicit function annotation (these may not be minification safe). Debugging info will be logged to the console to help track down the offending code. I prefer to only use ng-strict-di for debugging purposes only. <body ng-app="APP" ng-strict-di>

Use Gulp or Grunt for ng-annotate

[Style Y101]
  • Use gulp-ng-annotate or grunt-ng-annotate in an automated build task. Inject /* @ngInject */ prior to any function that has dependencies.

    Why?: ng-annotate will catch most dependencies, but it sometimes requires hints using the /* @ngInject */ syntax.

    The following code is an example of a gulp task using ngAnnotate

    gulp.task('js', ['jshint'], function() {
        var source = pkg.paths.js;
    
        return gulp.src(source)
            .pipe(sourcemaps.init())
            .pipe(concat('all.min.js', {newLine: ';'}))
            // Annotate before uglify so the code get's min'd properly.
            .pipe(ngAnnotate({
                // true helps add where @ngInject is not used. It infers.
                // Doesn't work with resolve, so we must be explicit there
                add: true
            }))
            .pipe(bytediff.start())
            .pipe(uglify({mangle: true}))
            .pipe(bytediff.stop())
            .pipe(sourcemaps.write('./'))
            .pipe(gulp.dest(pkg.paths.dev));
    });
    
    

Back to Table of Contents