AngularJs 缩小过程
AngularJs minification process
我正在完成一个 Web 应用程序,一切都很顺利。
我使用 Grunt 将我所有的 .js 文件合并到一个唯一的文件中,这就是我在 index.html 文件中用来加载代码的文件。
问题出在我使用 .min 时。 grunt 使用 'grunt-contrib-uglify' 任务生成的文件版本。
当我重新加载页面时,出现以下错误:
angular.js:38Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.5.5/$injector/modulerr?p0=myapp&p1=Error%…ogleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.5.5%2Fangular.min.js%3A39%3A222)
我一直在 Google 上阅读相关内容,但没有成功。
我该如何解决这个问题?
编辑:
这是一个典型的文件控制器(都具有相同的结构):
(function() {
var app = angular.module("post", []);
var controllers = {};
controllers.postCtrl = ['$scope', '$rootScope', 'myFactory', function($scope, $rootScope, myFactory) {
$scope.loading = {state:false};
$scope.filters = $scope.filters || myFactory.authors;
$scope.init = function() {
var idx = myFactory.get_author_by_index(Number($('input[name="author"]').val()));
$scope.filterSelected = $scope.filters[idx];
angular.element(document).ready(function () {
angular.forEach($('div.general_page_content').find('a'), function(value, index) {
$(value).attr('target', "_new");
})
angular.forEach($('div.general_page_content').find('iframe'), function(value, index) {
$(value).attr("width", "100%");
})
angular.forEach($('div.general_page_content').find('img'), function(value, index) {
$(value).attr("width", "100%").css('width', '100%');
})
myFactory.containerResize();
});
}
$rootScope.$on('loading', function(evt, value) {
$scope.loading.state = value;
});
$rootScope.$on('autocomplete:focus', function(ev) {
$scope.search_focus = true;
});
$rootScope.$on('autocomplete:blur', function(ev) {
$scope.search_focus = false;
});
$scope.showSocialShare = function(ev) {
$scope.url = decodeURIComponent($('input[name="url"]').val());
$scope.text = decodeURIComponent($('input[name="text"]').val());
$scope.img = decodeURIComponent($('input[name="img"]').val());
myFactory.showSocialShare($scope, ev);
};
$scope.favorite_post = function(ev, id, title) {
myFactory.favorite_post($scope, ev, id, title);
}
$scope.fetchPostsChange = function(selected) {
document.location = '/blog/?author='+selected.id;
}
$scope.search = function(text) {
document.location = '/blog/?search='+encodeURIComponent(text);
}
$scope.go_to_favorites_post = function() {
document.location = '/blog/archive/';
}
$scope.init();
}];
app.controller(controllers);
})();
更新:
我只取了两个.js 文件并处理它们以缩小它并检查是否出现相同的错误。奇怪的是,只考虑两个文件,出现了同样的错误,所以我粘贴了缩小的文件,以便您能够检测到问题所在。
!function(){angular.module("myapp",["ngMaterial","ngMessages","ngStorage","toaster","ngMdIcons","lvl.services","smart-table","angularGrid","ngFileUpload","angular-timeline","header","dashboard","sidebar","autocomplete","timeline","sidebarCollection","myappFactory","objectCtrl","homeCtrl","Collections","Collection","posts","post","model","postArchive","720kb.socialshare","services","footer"]).config(function(a,b,c){a.theme("default").primaryPalette("lime").accentPalette("grey").warnPalette("red"),a.theme("darkTheme").primaryPalette("lime").accentPalette("grey").warnPalette("red").dark(),b.enabled(!1),c.get("user")})}(),function(){var a=angular.module("autocomplete",[]),b={},c={};b.autocompleteCtrl=["$http","$scope","$mdBottomSheet","$sessionStorage","myappFactory",function(a,b,c,d,e){b.init=function(){b.session=d,angular.isUndefined(b.session.advance_search)&&(b.session.advance_search={select_all:!0,show_cost:!0,show_free:!0,items:[{name:"Thingiverse",selected:!0},{name:"Youmagine",selected:!0},{name:"MyMinifactory",selected:!0},{name:"Cults 3D",selected:!0},{name:"Pinshape",selected:!0},{name:"Turbosquid",selected:!0},{name:"Shapeways",selected:!0},{name:"GrabCAD",selected:!0},{name:"CGTrader",selected:!0},{name:"Threeding",selected:!0}]})},b.querySearch=function(c){var d=c.trim();return d&&d.length>2?(b.isFetching=!0,a.get(e._myapp_link+"/api/index.php/myapp/autocomplete/"+encodeURIComponent(d)).then(function(a){return a.data})):void 0},b.collectionSearch=function(c){var d=c.trim();return d&&d.length>2?(b.isFetching=!0,a.get(e._myapp_link+"/api/index.php/myapp/collection_search/"+encodeURIComponent(d)).then(function(a){return a.data})):void 0},b.search=function(a){var c="";b.session.advance_search.show_cost&&!b.session.advance_search.show_free?c+=" free:0 ":!b.session.advance_search.show_cost&&b.session.advance_search.show_free&&(c+=" free:1 "),angular.forEach(b.session.advance_search.items,function(a,d){(b.session.advance_search.select_all||a.selected)&&(c+=" plataforma:"+a.name)}),window.location="/?search="+encodeURIComponent(a)+"¶ms="+Base64.encode(c)},b.go_to_collection=function(a){window.location="/collections/"+encodeURIComponent(a)},b.showAdvancedSearch=function(){c.show({templateUrl:"/advanced_search_sheet.html",controller:"ListBottomSheetCtrl"})},b.init()}],b.ListBottomSheetCtrl=["$scope","$mdBottomSheet","$sessionStorage","myappFactory",function(a,b,c,d){a.session=c,a.toggle_all_sites=function(){a.session.advance_search.select_all=!a.session.advance_search.select_all,a.session.advance_search.select_all&&angular.forEach(a.session.advance_search.items,function(a,b){a.selected=!0})},a.toggle_advance_search=function(b){if(a.session.advance_search.select_all)a.session.advance_search.items[b].selected=!0,d.showMessage({msg:"Uncheck 'All repositories' first!"});else if(a.session.advance_search.items[b].selected=!a.session.advance_search.items[b].selected,!a.session.advance_search.items[b].selected){var c=0;angular.forEach(a.session.advance_search.items,function(a,b){a.selected&&++c}),c||(a.session.advance_search.items[b].selected=!0,d.showMessage({msg:"There must be at least 1 respository selected!"}))}},a.free_cost_checked=function(b){var c="cost"==b?!a.session.advance_search.show_cost:!a.session.advance_search.show_free;c?"cost"==b?a.session.advance_search.show_cost=!0:a.session.advance_search.show_free=!0:"cost"==b?a.session.advance_search.show_free?a.session.advance_search.show_cost=!1:d.showMessage({msg:"Free and Price cannot be unchecked!"}):"free"==b&&(a.session.advance_search.show_cost?a.session.advance_search.show_free=!1:d.showMessage({msg:"Free and Price cannot be unchecked!"}))}}],c.myEnter=function(){return function(a,b,c){b.bind("keydown keypress",function(b){13===b.which&&(a.$apply(function(){a.search(a.searchText)}),b.preventDefault())})}},c.onBlur=["$rootScope","$mdUtil","$timeout",function(a,b,c){return{require:"^mdAutocomplete",link:function(d,e,f,g){c(function(){var c=(e.find("input"),e[0],g.blur),h=g.focus;g.blur=function(){c.call(g),b.nextTick(function(){a.$broadcast("autocomplete:blur"),d.$eval(f.mdBlur,{$mdAutocomplete:g})})},g.focus=function(){h.call(g),b.nextTick(function(){a.$broadcast("autocomplete:focus"),d.$eval(f.mdFocus,{$mdAutocomplete:g})})}})}}}],a.controller(b).directive(c)}();
如果缩小,每个模块的注入都必须命名。所以之前你可能有过:
app.factory('myFactory', function($route) {
});
现在你也必须 name/declare 它们,否则 angular 不知道要注入什么:
app.factory('myFactory', ['$route', function($route) {
}]);
为什么?
Minification 将所有内容都变成小变量。所以我们的工厂变成:
app.factory('myFactory', function(a) {
a.<functioncall>
});
Angular 不知道 "a" 是什么,因此必须告知:
app.factory('myFactory', ['$route', function(a) {
a.<functioncall>
}]);
所以它现在知道 and a= $route 等等。
正如您在 Google 上肯定发现的那样,该错误取决于 Variable Mangling
https://github.com/gruntjs/grunt-contrib-uglify#mangle。
所以,当你 mangle $rootScope
变成 a
并且,当然,angular 依赖注入 无法解决它:
angular
.module('test', [])
.run(function($injector) {
console.log(
"$rootScope exists?",
$injector.has('$rootScope')
);
try {
// mangle $rootscope => a
$injector.get('a');
} catch(e) {
console.log('a exists?', e.message);
}
})
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
<section ng-app="test"></section>
有很多方法可以解决这个问题:
- 禁用变量重整(不是一个好方法,但却是一个解决方案)。
-
一个。数组表示法:someModule.run(["$rootScope", function(a) {}]);
b。 $注入 属性: runFn.$inject = ['$rootScope']; function runFn(a) {}; someModule.run(runFn);
使用 ngAnnotate 在构建时进行注释。我建议你这个选项,因为你不需要关心注释...
Important thing:
Always run your code in angular strict di
mode, that gives you the opportunity of control each annotation issue.
我正在完成一个 Web 应用程序,一切都很顺利。
我使用 Grunt 将我所有的 .js 文件合并到一个唯一的文件中,这就是我在 index.html 文件中用来加载代码的文件。
问题出在我使用 .min 时。 grunt 使用 'grunt-contrib-uglify' 任务生成的文件版本。
当我重新加载页面时,出现以下错误:
angular.js:38Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.5.5/$injector/modulerr?p0=myapp&p1=Error%…ogleapis.com%2Fajax%2Flibs%2Fangularjs%2F1.5.5%2Fangular.min.js%3A39%3A222)
我一直在 Google 上阅读相关内容,但没有成功。
我该如何解决这个问题?
编辑:
这是一个典型的文件控制器(都具有相同的结构):
(function() {
var app = angular.module("post", []);
var controllers = {};
controllers.postCtrl = ['$scope', '$rootScope', 'myFactory', function($scope, $rootScope, myFactory) {
$scope.loading = {state:false};
$scope.filters = $scope.filters || myFactory.authors;
$scope.init = function() {
var idx = myFactory.get_author_by_index(Number($('input[name="author"]').val()));
$scope.filterSelected = $scope.filters[idx];
angular.element(document).ready(function () {
angular.forEach($('div.general_page_content').find('a'), function(value, index) {
$(value).attr('target', "_new");
})
angular.forEach($('div.general_page_content').find('iframe'), function(value, index) {
$(value).attr("width", "100%");
})
angular.forEach($('div.general_page_content').find('img'), function(value, index) {
$(value).attr("width", "100%").css('width', '100%');
})
myFactory.containerResize();
});
}
$rootScope.$on('loading', function(evt, value) {
$scope.loading.state = value;
});
$rootScope.$on('autocomplete:focus', function(ev) {
$scope.search_focus = true;
});
$rootScope.$on('autocomplete:blur', function(ev) {
$scope.search_focus = false;
});
$scope.showSocialShare = function(ev) {
$scope.url = decodeURIComponent($('input[name="url"]').val());
$scope.text = decodeURIComponent($('input[name="text"]').val());
$scope.img = decodeURIComponent($('input[name="img"]').val());
myFactory.showSocialShare($scope, ev);
};
$scope.favorite_post = function(ev, id, title) {
myFactory.favorite_post($scope, ev, id, title);
}
$scope.fetchPostsChange = function(selected) {
document.location = '/blog/?author='+selected.id;
}
$scope.search = function(text) {
document.location = '/blog/?search='+encodeURIComponent(text);
}
$scope.go_to_favorites_post = function() {
document.location = '/blog/archive/';
}
$scope.init();
}];
app.controller(controllers);
})();
更新:
我只取了两个.js 文件并处理它们以缩小它并检查是否出现相同的错误。奇怪的是,只考虑两个文件,出现了同样的错误,所以我粘贴了缩小的文件,以便您能够检测到问题所在。
!function(){angular.module("myapp",["ngMaterial","ngMessages","ngStorage","toaster","ngMdIcons","lvl.services","smart-table","angularGrid","ngFileUpload","angular-timeline","header","dashboard","sidebar","autocomplete","timeline","sidebarCollection","myappFactory","objectCtrl","homeCtrl","Collections","Collection","posts","post","model","postArchive","720kb.socialshare","services","footer"]).config(function(a,b,c){a.theme("default").primaryPalette("lime").accentPalette("grey").warnPalette("red"),a.theme("darkTheme").primaryPalette("lime").accentPalette("grey").warnPalette("red").dark(),b.enabled(!1),c.get("user")})}(),function(){var a=angular.module("autocomplete",[]),b={},c={};b.autocompleteCtrl=["$http","$scope","$mdBottomSheet","$sessionStorage","myappFactory",function(a,b,c,d,e){b.init=function(){b.session=d,angular.isUndefined(b.session.advance_search)&&(b.session.advance_search={select_all:!0,show_cost:!0,show_free:!0,items:[{name:"Thingiverse",selected:!0},{name:"Youmagine",selected:!0},{name:"MyMinifactory",selected:!0},{name:"Cults 3D",selected:!0},{name:"Pinshape",selected:!0},{name:"Turbosquid",selected:!0},{name:"Shapeways",selected:!0},{name:"GrabCAD",selected:!0},{name:"CGTrader",selected:!0},{name:"Threeding",selected:!0}]})},b.querySearch=function(c){var d=c.trim();return d&&d.length>2?(b.isFetching=!0,a.get(e._myapp_link+"/api/index.php/myapp/autocomplete/"+encodeURIComponent(d)).then(function(a){return a.data})):void 0},b.collectionSearch=function(c){var d=c.trim();return d&&d.length>2?(b.isFetching=!0,a.get(e._myapp_link+"/api/index.php/myapp/collection_search/"+encodeURIComponent(d)).then(function(a){return a.data})):void 0},b.search=function(a){var c="";b.session.advance_search.show_cost&&!b.session.advance_search.show_free?c+=" free:0 ":!b.session.advance_search.show_cost&&b.session.advance_search.show_free&&(c+=" free:1 "),angular.forEach(b.session.advance_search.items,function(a,d){(b.session.advance_search.select_all||a.selected)&&(c+=" plataforma:"+a.name)}),window.location="/?search="+encodeURIComponent(a)+"¶ms="+Base64.encode(c)},b.go_to_collection=function(a){window.location="/collections/"+encodeURIComponent(a)},b.showAdvancedSearch=function(){c.show({templateUrl:"/advanced_search_sheet.html",controller:"ListBottomSheetCtrl"})},b.init()}],b.ListBottomSheetCtrl=["$scope","$mdBottomSheet","$sessionStorage","myappFactory",function(a,b,c,d){a.session=c,a.toggle_all_sites=function(){a.session.advance_search.select_all=!a.session.advance_search.select_all,a.session.advance_search.select_all&&angular.forEach(a.session.advance_search.items,function(a,b){a.selected=!0})},a.toggle_advance_search=function(b){if(a.session.advance_search.select_all)a.session.advance_search.items[b].selected=!0,d.showMessage({msg:"Uncheck 'All repositories' first!"});else if(a.session.advance_search.items[b].selected=!a.session.advance_search.items[b].selected,!a.session.advance_search.items[b].selected){var c=0;angular.forEach(a.session.advance_search.items,function(a,b){a.selected&&++c}),c||(a.session.advance_search.items[b].selected=!0,d.showMessage({msg:"There must be at least 1 respository selected!"}))}},a.free_cost_checked=function(b){var c="cost"==b?!a.session.advance_search.show_cost:!a.session.advance_search.show_free;c?"cost"==b?a.session.advance_search.show_cost=!0:a.session.advance_search.show_free=!0:"cost"==b?a.session.advance_search.show_free?a.session.advance_search.show_cost=!1:d.showMessage({msg:"Free and Price cannot be unchecked!"}):"free"==b&&(a.session.advance_search.show_cost?a.session.advance_search.show_free=!1:d.showMessage({msg:"Free and Price cannot be unchecked!"}))}}],c.myEnter=function(){return function(a,b,c){b.bind("keydown keypress",function(b){13===b.which&&(a.$apply(function(){a.search(a.searchText)}),b.preventDefault())})}},c.onBlur=["$rootScope","$mdUtil","$timeout",function(a,b,c){return{require:"^mdAutocomplete",link:function(d,e,f,g){c(function(){var c=(e.find("input"),e[0],g.blur),h=g.focus;g.blur=function(){c.call(g),b.nextTick(function(){a.$broadcast("autocomplete:blur"),d.$eval(f.mdBlur,{$mdAutocomplete:g})})},g.focus=function(){h.call(g),b.nextTick(function(){a.$broadcast("autocomplete:focus"),d.$eval(f.mdFocus,{$mdAutocomplete:g})})}})}}}],a.controller(b).directive(c)}();
如果缩小,每个模块的注入都必须命名。所以之前你可能有过:
app.factory('myFactory', function($route) {
});
现在你也必须 name/declare 它们,否则 angular 不知道要注入什么:
app.factory('myFactory', ['$route', function($route) {
}]);
为什么?
Minification 将所有内容都变成小变量。所以我们的工厂变成:
app.factory('myFactory', function(a) {
a.<functioncall>
});
Angular 不知道 "a" 是什么,因此必须告知:
app.factory('myFactory', ['$route', function(a) {
a.<functioncall>
}]);
所以它现在知道 and a= $route 等等。
正如您在 Google 上肯定发现的那样,该错误取决于 Variable Mangling
https://github.com/gruntjs/grunt-contrib-uglify#mangle。
所以,当你 mangle $rootScope
变成 a
并且,当然,angular 依赖注入 无法解决它:
angular
.module('test', [])
.run(function($injector) {
console.log(
"$rootScope exists?",
$injector.has('$rootScope')
);
try {
// mangle $rootscope => a
$injector.get('a');
} catch(e) {
console.log('a exists?', e.message);
}
})
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
<section ng-app="test"></section>
有很多方法可以解决这个问题:
- 禁用变量重整(不是一个好方法,但却是一个解决方案)。
-
一个。数组表示法:
someModule.run(["$rootScope", function(a) {}]);
b。 $注入 属性:
runFn.$inject = ['$rootScope']; function runFn(a) {}; someModule.run(runFn);
使用 ngAnnotate 在构建时进行注释。我建议你这个选项,因为你不需要关心注释...
Important thing: Always run your code in
angular strict di
mode, that gives you the opportunity of control each annotation issue.