Read time: 5 minutes
Angular JS is great for building SPA (Single page application). However, if you made a more complex app than a simple "Hello world" you know that the number of modules tend to grow really fast. There are controllers, models, services, directives, filters and you need to keep the app structure as friendly as you can. In this way other developers and even you, can reason about the app easily.
Another aspect of having lots of scripts included is performance, the browser is loading them asynchronous, but if there are too many of them the process is overwhelming and this means latency that will bother the users.
In this post we explore one way of keeping the application structured in a logical way, easy to understand and maintain, and serving the application to the browser in one single file. To demonstrate this, I have built an application with a couple of modules separated by functionality.
The following technologies are required:
- Angular JS - because there is all about it.
- Bootstrap - to make our app more fancy and user friendly.
- Grunt - used to minify the application in one file and automate this process.
As a demo I have built a simple application that searches repositories or users on github and displays the results.
- You can find the github repository for the demo app here.
Below you can find a pen which serves as a live demo:
See the Pen Angular demo - search repos on github by Cioban Andrei (@andr3imir) on CodePen.
In the demo above I modified the code structure to work in the codepen way, so it is only for the sake of having a live demo. You should look at the structure on github repository.
So we have the app, we have a live demo, let’s get into details.
In this post you can find the installation guidance for the required tools on Ubuntu, but if you follow the links you'll find detailed information about how to install them on different operating systems.
You have to:
- install a stable version of Node.js:
> sudo apt-get install nodejs
Here you can get in trouble because there is a conflict between nodejs and another package called node. Read here how to deal with it.
Check if nodejs and npm are installed, go to your command line and type:
> node -v > npm -v
If for some reason npm is not installed run:
> sudo apt-get install npm
Our application structure is looking like this:
css |____style.css static |___githubApp |___constants |___Config.js |___controller |___MainCtrl.js |___directive |___Enter.js |___Trim.js |___filter |___Offset.js |___model |___Github.js |___service |___UtilsService.js |___app.js |___app.min.js //the resulting file after minifying our angular app Gruntfile.js index.html package.json
Let’s explain the configuration files:
package.json – in this file we have to define dependencies for our application.
{ "name": "AngularJS---github-search-demo", "description": "Angular demo app - search repos on github", "author": "Andrei Cioban", "version": "0.1.0", "devDependencies": { "grunt": "~0.4.4", "grunt-contrib-uglify": "latest", "grunt-contrib-watch": "latest" } }
We defined the name , author, version and devDependencies of our application . Save this file and let npm to do some magic:
> npm install
Now npm is installing all defined dependencies:
grunt - the JavaScript task runner
grunt-contrib-uglify - grunt plugin for minifying our app
grunt-contrib-watch - grunt plugin for watching over our app sources and push the changes to minified file
Gruntfile.js– in this field we configure grunt and the required plugins.
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*\n <%= pkg.name %>\n <%= pkg.author %>\n <%= grunt.template.today("yyyy-mm-dd") %> \n*/\n' }, build: { files: { 'static/app.min.js': 'static/githubApp/**/*.js' } } }, watch: { scripts: { files: 'static/githubApp/**/*.js', tasks: ['uglify'] } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-watch'); };
We defined the configuration file package.json from which we get the project details. The uglify plugin - in which we get all files from static directory that have the extension js and concatenate them in the static/app.min.js file. The watch plugin - in which we watch over all files from static directory that have the extension js and run the uglify task whenever a file changes.
Before using the tools that we’ve just installed and configured let's talk about how angular modules have to be defined so we can minify them without breaking the application.
If we define our modules in this way.
This is bad for minification
var githubApp = angular.module('githubApp', []); githubApp.controller('MainCtrl', function($scope,Config){ // initialize values $scope.searchTerm = Config.searchTerm; $scope.categories = Config.searchCategories; $scope.searchCategory = Config.searchCategories[0].name; // .... });
After minification it will look like this:
var githubApp=angular.module("githubApp",[]);githubApp.controller("MainCtrl",function(e,d){e.searchTerm = d.searchTerm; //...})
We see that the $scope and Config module were replaced by 'e' and 'd ' and now angular has no idea that these variables are in fact $scope and Config.
Let’s see now how to define modules that play nice with minification.
This is good for minification
var githubApp = angular.module('githubApp', []); githubApp.controller('MainCtrl', ['$scope', 'Config', function($scope,Config){ // initialize values $scope.searchTerm = Config.searchTerm; $scope.categories = Config.searchCategories; $scope.searchCategory = Config.searchCategories[0].name; // .... }]);
We injected the dependencies as string using inline annotation and these will be preserved after minification.
We are almost there, let’s minify our application. From command line go to the project root directory where the Gruntfile.js resides and run the following command:
> grunt uglify
Grunt will grab all the js files from target directory (our app directory) and minify them in app.min.js file.
Next, run the following command to watch over app sources and roll the changes to app.min.js:
> grunt watch
All you have to do now is to include only the minified version in the main view (index.html) and structure your app as ever feels right for you. Grunt grabs the changes and puts them in the minified file.
Happy coding!
UPDATE: I've just published a new article here on ASSIST's blog, it's about "Modern Web Development Tools Used in 2015", have a look if you're interested.