最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular-ui-router breaks when uglified with gulp - Stack Overflow

programmeradmin4浏览0评论

I have the following simple angular.js app, following best practices outlined here.

angular
  .module('myApp', ['ui.router']);

(function() {
    function routes($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/404");

        $stateProvider
            .state('createCluster', {
                url: '/create-cluster',
                templateUrl: 'templates/create-cluster.html'
            })
    }

    angular
        .module('myApp')
        .config(routes);
})();

I am using gulp to concat all JavaScript files, including angular-ui-router.js and run everything through uglify after. When I uglify though, I am getting:

Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:unpr] Unknown provider: e

When I remove the uglification, everything works. How can I get uglification to not break ui-router?

Here is my gulp task:

gulp.task('uglify-js', function () {
  gulp.src(['client/js/libraries/**/*.js', 'client/js/source/**/*.js'])
    .pipe(concat('app'))
    .pipe(ngAnnotate())
    .pipe(uglify())
    .pipe(rename({ extname: ".min.js" }))
    .pipe(gulp.dest('client/js'))'
});

I have the following simple angular.js app, following best practices outlined here.

angular
  .module('myApp', ['ui.router']);

(function() {
    function routes($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/404");

        $stateProvider
            .state('createCluster', {
                url: '/create-cluster',
                templateUrl: 'templates/create-cluster.html'
            })
    }

    angular
        .module('myApp')
        .config(routes);
})();

I am using gulp to concat all JavaScript files, including angular-ui-router.js and run everything through uglify after. When I uglify though, I am getting:

Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:unpr] Unknown provider: e

When I remove the uglification, everything works. How can I get uglification to not break ui-router?

Here is my gulp task:

gulp.task('uglify-js', function () {
  gulp.src(['client/js/libraries/**/*.js', 'client/js/source/**/*.js'])
    .pipe(concat('app'))
    .pipe(ngAnnotate())
    .pipe(uglify())
    .pipe(rename({ extname: ".min.js" }))
    .pipe(gulp.dest('client/js'))'
});
Share Improve this question edited Jul 15, 2017 at 7:08 Preview 35.8k10 gold badges95 silver badges113 bronze badges asked Jul 25, 2014 at 21:25 JustinJustin 45.4k81 gold badges213 silver badges310 bronze badges 4
  • Have you read the section on minification in the post that you linked to? The problem is that the minification changes the names of the things you inject. – Sunil D. Commented Jul 25, 2014 at 21:35
  • 1 change .config(routes); to .config(['$stateProvider', '$urlRouterProvider', routes]); so you'll tell Angular which dependencies to inject for each parameter. In that way, you will not lose the parameter matching when you minify – Luis Masuelli Commented Jul 25, 2014 at 21:36
  • Shouldn't .pipe(ngAnnotate()) does this for me? See my grunt file. – Justin Commented Jul 25, 2014 at 21:36
  • @Justin by grunt you mean gulp, right? – Josh C. Commented Jul 25, 2014 at 22:00
Add a comment  | 

6 Answers 6

Reset to default 16

One simple thing to get this working without changing all your code is to set the mangle option of uglify to false like so :

gulp.task('uglify-js', function() {
  gulp.src(['client/js/libraries/**/*.js', 'client/js/source/**/*.js'])
    .pipe(concat('app'))
    .pipe(ngAnnotate())
    .pipe(uglify({ mangle: false }))
    .pipe(rename({ extname: '.min.js' }))
    .pipe(gulp.dest('client/js'));
});

That keeps the names so you will not have injections problems.

You should use ngannotate. This while preprocess your angular code to make it safe for uglify/minification. Ngannotate adds dependency annotations so the minifier doesn't break your dependency injection.

The angular documentation provides a note on this:

Since Angular infers the controller's dependencies from the names of arguments to the controller's constructor function, if you were to minify the JavaScript code for PhoneListCtrl controller, all of its function arguments would be minified as well, and the dependency injector would not be able to identify services correctly. We can overcome this problem by annotating the function with the names of the dependencies, provided as strings, which will not get minified.

Ngannotate does this process for you which keeps your code cleaner.

Ngmin is now deprecated and the github advises to use ngannotate. It is also faster than ngmin.

Try this so that minification don't mess up the injection:

var routes = function ($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise("/404");

    $stateProvider
        .state('createCluster', {
            url: '/create-cluster',
            templateUrl: 'templates/create-cluster.html'
        })
};

routes.$inject = ['$stateProvider','$urlRouterProvider'];

angular
    .module('myApp')
    .config(routes);

See the code being generated. A problem when minifying AngularJS is that the dependency injection is based on parameter names, and as such will break when minified.

For instance, this line

function routes($stateProvider, $urlRouterProvider) {

may end up looking like

function routes(a, b) {

and then Angular won't know which dependency to inject, and you will get the Unknown provider error.

To fix that, you can use the array syntax (see: Inline Array Annotation) instead.

['$dependencyA', '$dependencyB', function($dependencyA, $dependencyB)

because minified that will look like

['$dependencyA', '$dependencyB', function(a, b)

and then Angular knows what to do.

In your case, it will be something like

.config(['$stateProvider', '$urlRouterProvider', routes]);

Just found the solution.

Or, even better than manually specifying the dependancies using $inject, use the built in @ngInject helper in gulp ngAnnotate.

angular
    .module('myApp', [
        'ui.router'
    ]);

(function() {
    /**
     * @ngInject
     */
    function routes($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/404");

        $stateProvider
            .state('createCluster', {
                url: '/create-cluster',
                templateUrl: 'templates/create-cluster.html'
            })
    }

    angular
        .module('myApp')
        .config(routes);
})();

Don't forget your @ngInject comment above the function, I'm working on getting auto-function reference landed in a future version of ng-annotate, if you could join and +1 here that'd be awesome: https://github.com/olov/ng-annotate/issues/57

发布评论

评论列表(0)

  1. 暂无评论