Manual Annotating for Dependency Injection

UnSafe from Minification

[Style Y090]
  • Avoid using the shortcut syntax of declaring dependencies without using a minification-safe approach.

    Why?: The parameters to the component (e.g. controller, factory, etc) will be converted to mangled variables. For example, common and dataservice may become a or b and not be found by AngularJS.

    /* avoid - not minification-safe*/
    angular
        .module('app')
        .controller('Dashboard', Dashboard);
    
    
    function Dashboard(common, dataservice) {
    }
    

    This code may produce mangled variables when minified and thus cause runtime errors.

    /* avoid - not minification-safe*/
    angular.module('app').controller('Dashboard', d);function d(a, b) { }
    

Manually Identify Dependencies

[Style Y091]
  • Use $inject to manually identify your dependencies for AngularJS components.

    Why?: This technique mirrors the technique used by ng-annotate, which I recommend for automating the creation of minification safe dependencies. If ng-annotate detects injection has already been made, it will not duplicate it.

    Why?: This safeguards your dependencies from being vulnerable to minification issues when parameters may be mangled. For example, common and dataservice may become a or b and not be found by AngularJS.

    Why?: Avoid creating in-line dependencies as long lists can be difficult to read in the array. Also it can be confusing that the array is a series of strings while the last item is the component’s function.

    /* avoid */
    angular
        .module('app')
        .controller('Dashboard',
            ['$location', '$routeParams', 'common', 'dataservice',
                function Dashboard($location, $routeParams, common, dataservice) {}
            ]);
    
    /* avoid */
    angular
      .module('app')
      .controller('Dashboard',
          ['$location', '$routeParams', 'common', 'dataservice', Dashboard]);
    
    
    function Dashboard($location, $routeParams, common, dataservice) {
    }
    
    /* recommended */
    angular
        .module('app')
        .controller('Dashboard', Dashboard);
    
    
    Dashboard.$inject = ['$location', '$routeParams', 'common', 'dataservice'];
    
    
    function Dashboard($location, $routeParams, common, dataservice) {
    }
    

    Note: When your function is below a return statement the $inject may be unreachable (this may happen in a directive). You can solve this by either moving the $inject above the return statement or by using the alternate array injection syntax.

    Note: ng-annotate 0.10.0 introduced a feature where it moves the $inject to where it is reachable.

    // inside a directive definition
    function outer() {
        return {
            controller: DashboardPanel,
        };
    
    
        DashboardPanel.$inject = ['logger']; // Unreachable
        function DashboardPanel(logger) {
        }
    }
    
    // inside a directive definition
    function outer() {
        DashboardPanel.$inject = ['logger']; // reachable
        return {
            controller: DashboardPanel,
        };
    
    
        function DashboardPanel(logger) {
        }
    }
    

Manually Identify Route Resolver Dependencies

[Style Y092]
  • Use $inject to manually identify your route resolver dependencies for AngularJS components.

    Why?: This technique breaks out the anonymous function for the route resolver, making it easier to read.

    Why?: An $inject statement can easily precede the resolver to handle making any dependencies minification safe.

    /* recommended */
    function config($routeProvider) {
        $routeProvider
            .when('/avengers', {
                templateUrl: 'avengers.html',
                controller: 'Avengers',
                controllerAs: 'vm',
                resolve: {
                    moviesPrepService: moviePrepService
                }
            });
    }
    
    
    moviePrepService.$inject = ['movieService'];
    function moviePrepService(movieService) {
        return movieService.getMovies();
    }