Click here to Skip to main content
15,887,596 members
Articles / Programming Languages / Javascript

The Best Module System for AngularJS Applications

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
24 Mar 2015CPOL3 min read 12.8K   4   2
The best Module System for AngularJS applications

I was working on a small and simple application built with AngularJS the other day. As with most applications like this, I start with a single JavaScript file called app.js and no module system.

In the past, I've used RequireJS with AngularJS. It's an awful mistake. It leads to a big jump in complexity with no benefits. Angular apps don't work well with AMDs, so really you are using RequireJS to combine files into one big file.

I'm sure there's a good analogy with hammers and nails. Something like:

It's like banging nails into your face with a hammer.

Maybe a bit extreme. But those who've used the two together may well be nodding sagely.

I've also used Browserify. I prefer this approach, the syntax is cleaner. But it's still a pain.

Ideally, I'd like to use ECMA6 modules. So another approach is to just use ECMA6 module syntax and then compile your code with something like Traceur. But that requires quite a bit of tooling, slows down your pipeline and you're still not really using modules.

I think the best approach is this one from Jeff Dicky on his post Best Practices for Building Angular.js Apps. Just forget all of the module stuff and concatenate only.

Start with this:

myproject  
 - app/
 - css/
 - vendor/
 - index.html

Or whatever your preferred structure is. Then stick your main file in app/:

myproject  
 - app/
   - app.js
 - css/
 - vendor/
 - index.html

Your app.js file should define your main Angular module:

JavaScript
angular.module('app', []);

Now just go ahead and concatenate everything in your app/ folder. Structure it however you want:

myproject  
 - app/
   - components/
   - home/
   - profile/
   - app.js
 - css/
 - vendor/
 - index.html

Concat will put everything in the top level folder (i.e. app.js) first. As long as you don't put anything else in your top level folder (that comes before 'a' alphabetically) then it doesn't matter where you put your other files, as long as you define them without referencing any globals. So define your components like this:

JavaScript
angular.module('app').controller('SomeController', function() {  
  // something
});

No fuss no muss. No requires, no exports.

If you need a new service, write it and save it. Same for directives or controllers or filters. Add the source file and it's included, no messing around.

Keep it simple, don't force another module system on top of angular's, you don't get much benefit. And wait patiently until ECMA6 moves more into the mainstream and we can start using native modules. There's less and less point in investing in some super-sophisticated complex fancy module system for a framework which in vNext will throw it all away and for a language which will finally get native modules.

Words for Gulpers

If you are a gulp user, here's how a pipeline might look to concat your JavaScript:

JavaScript
var gulp = require('gulp');  
var jshint = require('gulp-jshint');  
var stylish = require('jshint-stylish');  
var uglify = require('gulp-uglify');  
var rename = require('gulp-rename');  
var sourcemaps = require('gulp-sourcemaps');  
var concat = require('gulp-concat');  
var ngAnnotate = require('gulp-ng-annotate');

//  Hints and builds all JavaScript.
gulp.task('js', function() {

  return gulp.src(['./client/app/**/*.js'])
    .pipe(jshint())
    .pipe(jshint.reporter(stylish))
    .pipe(jshint.reporter('fail'))
    .pipe(sourcemaps.init({loadMaps: true}))
      .pipe(concat('app.js'))
      .pipe(gulp.dest('./client/dist'))
      .pipe(ngAnnotate())
      .pipe(uglify())
      .pipe(rename({suffix: '.min'}))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./client/dist/'));
});

Watch your app JavaScript folder and when it changes, you'll hint everything, concat into a single distribution folder, annotate and uglify, as well as building full sourcemaps.

What About Other Stuff?

For vendor code (jQuery, Bootstrap, whatever), don't bother trying to be smart and require or import it. Just include it in your app with script tags. I wouldn't go to the effort at trying to force some kind of smart module system on a language that doesn't really support it - if you can get away with avoiding it, do so.

This is not an encouragement to be sloppy, this is just the easiest way to deal with the issue. The number of hours I've wasted tracking down 'bugs' which were subtle issues to do with require.js or type-os has definitely made the approach above my preferred approach.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United Kingdom United Kingdom
Follow my blog at www.dwmkerr.com and find out about my charity at www.childrenshomesnepal.org.

Comments and Discussions

 
QuestionWhat about if you don't use gulp Pin
Sacha Barber24-Mar-15 20:11
Sacha Barber24-Mar-15 20:11 
AnswerRe: What about if you don't use gulp Pin
Dave Kerr24-Mar-15 21:47
mentorDave Kerr24-Mar-15 21:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.