为什么Closure Compiler会破坏这个AngularJS脚本?

时间:2013-01-06 17:00:00

标签: javascript playframework-2.0 angularjs google-closure-compiler

我正在使用Play Framework 2.0(Scala)测试AngularJs。 Play使用Closure来最小化Javascript文件。

我的文件如下:

// Define a Module 'todoList' for Angular that will load the views. In this example the views are very simple, it's just to show
// the concept
angular.module('todoList', ['taskDoneFilter', 'todoServices']).
    config(['$routeProvider', function($routeProvider) {
        $routeProvider.
            when('/all', {templateUrl: 'assets/angular/all.html',   controller: TodoCtrl}).
            when('/task/:id', {templateUrl: 'assets/angular/task.html', controller: TaskDetailCtrl}).
            otherwise({redirectTo: '/all'});
    }]);


// This filter allows us to convert strings. In this case, it adds an extra tick besides a task indicating if it's done or no
angular.module('taskDoneFilter', []).filter('checkmark', function() {
    return function(input) {
        return input ? '\u2713' : '\u2718';
    };
});


// When running tests with Jasmine the jsRoutes object is not defined, which means we need to use a default route for the http call below
// This kind of defeats the purpose of retrieving the routes via Play instead of hardcoding them, as we need a fallback for the tests
// but I decided to leave the code just to see that we have the possibility, in case I find a way to improve this.
var tasksUrl = '/tasks/all';
if(!(typeof jsRoutes === "undefined")) {
  tasksUrl = jsRoutes.controllers.Application.tasks().url ;
}

// Definition of a Service, that stores all the REST requests independently from the controllers, facilitating change
angular.module('todoServices', ['ngResource']).
    factory('All', function ($resource) {
        return $resource(tasksUrl, {}, {
            //The data model is loaded via a GET request to the app
            query: {method: 'GET', params: {}, isArray: true}
        });
    })
    .factory('Task', function ($resource) {
        return $resource('tasks', {}, {
            add: {method: 'POST'}
        });
    });

/**
 * This is the controller behind the view, as declared by ng-controller
 * All references to methods and data model in the view map to this controller
 * @param $scope model data injected into the controller
 * @constructor
 */
var TodoCtrl = ['$scope', 'All', 'Task', function($scope, All, Task) {
    // We use the service to query for the data
    $scope.todos = All.query();

    //when submitting the form, this is called. Model in the form is referenced (todoText) and we add the task to
    //the data model
    $scope.addTodo = function() {
        var txt = $scope.todoText;
        $scope.todos.push({text: txt, done: false});
        Task.save({msg: txt});
        $scope.todoText = '';  //clear the input!
    };

    // calculates the remaining todos, automatically called when the model changes to update the view
    // notice the use of 'angular' component for functional approach
    $scope.remaining = function() {
        var count = 0;
        angular.forEach($scope.todos, function(todo) {
            count += todo.done ? 0 : 1;
        });
        return count;
    };

    //another acton triggered by click (in this case on an anchor), which archives completed tasks
    $scope.archive = function() {
        var oldTodos = $scope.todos;
        $scope.todos = [];
        angular.forEach(oldTodos, function(todo) {
            if (!todo.done) $scope.todos.push(todo);
        });
    };
}];

// Task details controller, used in the routes to provide a second view for the application
var TaskDetailCtrl = ['$scope', '$routeParams', function($scope, $routeParams) {
    $scope.id = $routeParams.id;
}];

但是当最小化时,它变成:

var module$todo={};angular.module("todoList",["taskDoneFilter","todoServices"]).config(["$routeProvider",function($routeProvider){$routeProvider.when("/all",{templateUrl:"assets/angular/all.html",controller:TodoCtrl$$module$todo}).when("/task/:id",{templateUrl:"assets/angular/task.html",controller:TaskDetailCtrl$$module$todo}).otherwise({redirectTo:"/all"})}]);angular.module("taskDoneFilter",[]).filter("checkmark",function(){return function(input){return input?"\u2713":"\u2718"}});
var tasksUrl$$module$todo="/tasks/all";if(!(typeof jsRoutes==="undefined"))tasksUrl$$module$todo=jsRoutes.controllers.Application.tasks().url;angular.module("todoServices",["ngResource"]).factory("All",function($resource){return $resource(tasksUrl$$module$todo,{},{query:{method:"GET",params:{},isArray:true}})}).factory("Task",function($resource){return $resource("tasks",{},{add:{method:"POST"}})});
var TodoCtrl$$module$todo=["$scope","All","Task",function($scope,All,Task){$scope.todos=All.query();$scope.addTodo=function(){var txt=$scope.todoText;$scope.todos.push({text:txt,done:false});Task.save({msg:txt});$scope.todoText=""};$scope.remaining=function(){var count=0;angular.forEach($scope.todos,function(todo){count+=todo.done?0:1});return count};$scope.archive=function(){var oldTodos=$scope.todos;$scope.todos=[];angular.forEach(oldTodos,function(todo){if(!todo.done)$scope.todos.push(todo)})}}];
var TaskDetailCtrl$$module$todo=["$scope","$routeParams",function($scope,$routeParams){$scope.id=$routeParams.id}];

然后它停止工作。请注意:

var module$todo={};

var TodoCtrl$$module$todo=

打破了应用。

任何人都知道为什么会发生这种情况?

2 个答案:

答案 0 :(得分:10)

您的All& Task服务不是'缩小安全'。您必须使用array notation

angular.module('todoServices', ['ngResource']).
    factory('All', ['$resource', function ($resource) {
        return $resource(tasksUrl, {}, {
            //The data model is loaded via a GET request to the app
            query: {method: 'GET', params: {}, isArray: true}
        });
    }])
    .factory('Task', ['$resource', function ($resource) {
        return $resource('tasks', {}, {
            add: {method: 'POST'}
        });
    }]);

另外,使用angular.module(...).controller()

定义您的控制器
angular.module(...).controller('TodoCtrl', ['$scope', 'All', 'Task', function($scope, All, Task) {
}]);

答案 1 :(得分:0)

...如果你有一个更大的应用程序,你可以通过启用strictDi(bootstrap调用选项或ng-app属性标记中的ng-strict-di属性)找到你没有使用命名引用的位置。