RequireJS is a great module loading tool and it has great optimization techniques. When you combine RequireJS with GruntJS you get some really powerful tools; but the AngularJS optimization is still somewhat lacking.
A few key tools you can leverage to make your AngularJS apps blazing fast and clean are:
When writing AngularJS controllers/services/directives you often end up with a HUGE constructor to make the code optimizer safe. I ended up with something like this quite a bit:
return app.controller('WorkspaceCtrl', ['$rootScope', '$scope', '$route', 'DashboardModel', 'dashboards', 'reports', 'workspaces', '$modal', 'growl',
function WorkspaceCtrl($rootScope, $scope, $route, DashboardModel, dashboards, reports, workspaces, $modal, growl){
//.. controller code here ...
}]);
Nasty right? This is where ng-min comes into play. ng-min will allow you to write:
return app.controller('WorkspaceCtrl', function($rootScope, $scope, $route, DashboardModel, dashboards, reports, workspaces, $modal, growl){
//.. controller code here ...
});
and at built time it will translate it to the above for you for correct compliation.
Angular has powerful templating options, but they are loaded on demand. This can be optimal but if you are like me and have a ton of different templates nested and very modular this can kill your application performance.
html2js combined with grunt can scan your 'views' folder and create all the precomplied html templates for you in a single file utilizing Angular's templateCache
. The end result is a file full of templates that look something like this:
angular.module("views/app.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("views/app.html",
"<section class=\"main app\">....</section>");
}]);
Later I take that file templates.js
and add it to the inital download of the app code.
Heres my GruntJS setup for the above options:
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-html2js');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.loadNpmTasks('grunt-wrap');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
requirejs: {
compile: {
options: {
name: 'main',
out: 'app.min.js',
insertRequire: ['main'],
wrap: true,
separateCSS: true,
mainConfigFile: 'main.js',
preserveLicenseComments: false,
optimize: 'uglify2',
uglify2:{
mangle: false
},
include: ['lib/require/require'],
deps: ['templates'],
onBuildRead: function (moduleName, path, contents) {
return require('ngmin').annotate(contents);
},
pragmas: {
production: true
},
compile: {
options: {
paths: {
'templates':'empty:',
}
}
}
}
}
},
html2js: {
main: {
options: {
htmlmin: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
removeComments: true,
removeEmptyAttributes: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true
},
base: './'
},
src: ['views/**/*.html'],
dest: 'templates.js'
}
},
wrap: {
basic: {
src: ['templates.js'],
dest: 'templates.js',
options: {
wrapper: ['define(["app"], function (app) {\n',
'\n app.requires.push("templates-main"); });']
}
}
}
});
grunt.registerTask('default', ['html2js', 'wrap', 'requirejs']);
return grunt;
};
Type grunt
and your app is optimized for awesomeness.