使用grunt uglify压缩Angularjs代码导致JS错误

14
在AngularJS中,我们使用依赖注入来传递参数。例如,
function checkInCtrl ($scope, $rootScope, $location, $http){
…..
….
}

当它被精简(minified)后,就变成了如下形式:

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

现在,Angular不会将a,b,c,d解释为$scope,$rootScope,$location和$http,整个代码无法工作。为此,AngularJS提供了一个解决方案,即

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

我们可以使用上述语法注入不同的依赖项。 这在我没有将一些自定义Angular服务用作依赖项时效果很好。 因此,举个例子,如果我有类似下面的内容:
function checkInCtrl ($scope, $rootScope, $location, $http){
…..
….
}

这个解决方案可以正常工作,但如果我有像这样的东西:
function checkInCtrl ($scope, $rootScope, $location, $http, customService){
…..
….
}

这里的customService类似于:

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

缩小版无法被angular正确解释。

由于我们必须开始项目开发活动,所以我们没有足够的时间来研究这个问题,并且我们开始使用未经缩小的控制器。因此,第一个问题是是否存在这样的问题与angular有关还是我犯了某些错误,导致它无法正常工作?如果存在这样的问题,解决方法是什么?


我在使用Gulp uglify插件时遇到了同样的问题,通过在gulp-uglify中设置“mangle:false”来解决了这个问题。 - Mohammad Kermani
4个回答

30
你需要使用基于字符串插入的语法,以确保缩小版本指向正确的依赖项:
function checkInCtrl ($scope, $rootScope, $location, $http){}

变成:

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

当你的代码被压缩混淆后,只有第二个会起作用。 - Jscti
如果您想深入了解AngularJS的依赖注入概念,我强烈建议您查看文档:http://docs.angularjs.org/guide/di 祝您愉快! - ngasull
谢谢Bixi,它有效了,也感谢你提供的链接 [link]thegreenpizza.github.io/2013/05/25/… 那里有很好的信息。还有Blint,感谢你提供AngularJS文档的链接。 - Navdeep
嘿@Bixi,还有一个问题。你分享的链接详细介绍了如何定义控制器、工厂、服务或指令以避免缩小后出现问题。但是当有多个模块且一个模块依赖于其他模块时,语法会是什么样子呢?那么angular.nodule('X',['Y','Z'])的语法会是什么样子呢?虽然我在这个项目中没有多个模块,但我想知道语法是否不同。 - Navdeep
1
非常感谢 @Cétia,您的回复帮助我解决了一个大问题,也让我知道了字符串注入的用途!再次感谢! - Youcef Moulahoum
显示剩余5条评论

10

Navdeep,

Bixi提供的解决方案可行。然而,更简单的方法是使用ngmin Grunt插件。使用此插件,您无需像所做的那样处理依赖注入,也不需要像Bixi那样使用特殊语法。

要使用它,请确保您拥有grunt-ngmin并在uglify之前调用它。

您的Gruntfile.js:

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

....

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

嗨李,这是实现Angular应用程序缩小的最简单方法。它也有效。所以谢谢。但我观察到的缺点是,缩小后的文件大小几乎是使用uglify创建的文件大小的两倍。 - Navdeep
我已经使用ngmin和未使用ngmin测试了我的项目,但似乎看不到区别。最终只有2个js文件:scripts.js和vendor.js,对吧?这两个文件中哪一个的大小差异最大? - suriyanto
嗨,李,我正在使用ngmin创建一个合并的丑化文件,其中包含所有我的控制器文件,因此生成的文件大小是使用uglify生成的文件大小的两倍。 - Navdeep

9

6
让uglify和minify工作起来,会揭示(就像在我的情况下一样)注入的变量从$ scope更改为“a”的地方。
例如: 这段代码:
controller: function($scope) {
        $scope.showValidation= false;
        this.showValidation = function(){
            $scope.showValidation = true;
        };
    }

经过代码压缩和混淆后变成:
controller:function(a){a.showValidation=!1,this.showValidation=function(){a.showValidation=!0}}

您得到错误是因为'a'与$scope不同。
解决方案是明确声明注入的变量:
controller: ['$scope', function($scope) {
        $scope.showValidation= false;
        this.showValidation = function(){
            $scope.showValidation = true;
        };
    }]

经过缩小和混淆后变成:
controller:["$scope",function(a){a.showValidation=!1,this.showValidation=function(){a.showValidation=!0}}]

现在,'a'被映射到$scope。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接