AngularJS Script Loading

Browserify? Require.js? Concat w/ Sourcemaps? An alternative approach…

Kent C. Dodds
5 min readJul 12, 2014

IMPORTANT NOTE: I now use webpack and, as awesome as this was, it has some serious shortcomings. My experience with webpack has been SO much better! I even made an egghead.io series on Angular and Webpack for Modular Applications.

I just read a medium post by @dickeyxxx about simplifying your Angular app’s script loading by simply leveraging Angular’s built-in module system and simply concatenating your source for dev and making source maps in favor over browserify or requirejs which can be more complicated. I’d like to suggest an alternative approach to accomplishing the same thing which I think may be even simpler.

The problem: Loading Scripts

What we’re really trying to accomplish here is two fold:

  1. Make sure all our files load in the right order
  2. Prevent the need for us to write script tags for every file by hand…

With the way Angular is currently. It pretty much takes care of #1 for us with its dependency injection and module system. (I’m pretty sure) that all you need to do is make sure that the module is created before you attempt to register anything on it (directives, services, controllers, etc.) and any of a module’s dependencies also need to be loaded. Other than that, it doesn’t really matter what order things load.

So, taking those constraints into consideration, we just need to make sure that the files we need are loaded into the browser while we’re developing. Putting in the scripts by hand is madness. All we really want is to say: “Hey browser, take all of the JavaScript files in this directory, and load them up will yah?” How many projects do you have where you aren’t loading every JavaScript file? Sure there are bower_components and other vendor files, but those are a separate animal. If you’re not loading all the files you are writing into the browser then what the heck is it doing in your repo?

As a side, at work, we use require to load all of our files. I know requirejs is more than just loading scripts, but please tell me how manually writing and maintaining this:

require('app.js');
require('main/MainCtrl');
require('github/GitHubService');
require('candy/FavoriteCandyService');
// go on forever...

Is any less of a nightmare than manually writing this:

<script src="app.js"></script>
<script src="main/MainCtrl.js"></script>
<script src="github/GitHubService.js"></script>
<script src="candy/FavoriteCandyService.js"></script>
<!-- go on forever... -->

Our app is riddled with the former, and I don’t really see that being much better than the latter…

A Solution: Grunt (or gulp, or whatever) + Jade (or ejs or whatever)

In my naivety, I created my own little node program that adds a script tag to my index.html for all the files in my project’s folder. It works great and my output looks like a huge html file with a billion script tags in it, but I don’t care, because what I have to maintain is very small and it works like a charm.

If you want, here’s how I’m doing it in a side project. Some of it is dependant on how I’ve structured my project, so you may have some differences in how you implement it, but I’d recommend trying it out :-)

Here’s my index.jade:

https://gist.github.com/kentcdodds/780e95c5d0a59cc6d912

and part of my Gruntfile.js

https://gist.github.com/kentcdodds/4c002b44cb0f0e59fa73

In the grunt config, you’ll notice a reference to “getIndexData.” This is the main magic of how things are automatically loaded. You’ll notice that vendor files (bower_components) are specifically added. Don’t know how you could get around that… But then I glob for everything using the constraints mentioned above. See it below:

https://gist.github.com/kentcdodds/cada16d48fb415b1f25b

I hope this is helpful for you. It’s certainly simpler for me to simply run “grunt jade” than worry about requiring stuff all over my code.

Compare/Contrast Million Scripts method with Concat & Sourcemap method

This is where I further convince you of my lack of knowledge…

The concat & Sourcemap method that @dickeyxxx recommends is awesome. I’d like to just write some of my thoughts to compare/contrast these two methods:

  1. They both accomplish the same task: Once you have it up and running, you don’t have to worry about writing/maintaining madness (require statements etc.)
  2. Concat & Sourcemap needs to run every time you change anything. I’m not certain how long that takes, but if it takes much time, then you’re stuck waiting for that task to run before you refresh your browser, which could be annoying. Especially if you’re compiling from CoffeeScript or TypeScript already. But, this may be such a negligible amount of time that this is simply a difference, neither good nor bad. Million Scripts only needs to run when you add/remove a file.
  3. Million Scripts requires the browser to load a ton of scripts every time you refresh whereas Concat & Sourcemap only needs the loading of one file (+ the sourcemap). Each of these is good and bad. I believe the browser only loads 6 files at once, so it may take a second longer to load the Million Scripts method. However, locally (where you should be doing this) that’s probably a non-issue. With Concat & Sourcemap, the browser has to split the parse the sourcemap and split it up. If you have a few vendor files in there, this may take a second too…

Conclusion

Hurray for multiple solutions to the same problem! I hope there’s always more than one way to do complex things because it makes it possible for you to evaluate the solutions and pick the one that works best for your situation.

Disclaimer: The largest codebase I’ve tried this on is about 5,000 lines of Angular JavaScript. Not sure how it scales… But I expect it would scale about as well as anything else…

Another Note: This is obviously just for development purposes. When you’re going to production, you’re going to want to concat and minify your source, yada yada yada. Loading 100 js files in the browser is not the best idea in the world…

TestingJavaScript.com Learn the smart, efficient way to test any JavaScript application.

--

--

Kent C. Dodds

Making software development more accessible · Husband, Father, Latter-day Saint, Teacher, OSS, GDE, @TC39 · @PayPalEng @eggheadio @FrontendMasters · #JS