Today I've adopting Browserify for my AngularJS project, but there is something that's very unclear to me. In all examples and blog posts I've seen stuff like this:
require('./messages');
angular.module('sling', ['sling.messages']);
exports = angular.module('sling.messages', [])
.controller('MessagesListCtrl', require('./MessagesListCtrl'));
module.exports = function() {
// ...
});
Sure, this works, but why do this? I've implemented it like this and that works absolutely fine too and feels more normal for an AngularJS project:
require('./messages');
angular.module('sling', ['sling.messages']);
angular.module('sling.messages', []);
require('./MessagesListCtrl');
angular.module('sling.messages').controller('MessagesListCtrl', function() {
// ...
});
In other words, I'm completely skipping the exports/module.exports, only using require
to basically include the files with the controllers, services, filter, etc.
Am I doing this right? I mean it all works, but am I going to be in trouble later on?
The main (and honestly only) reason to use Browserify is if you want to have CommonJS modules (i.e. NodeJS modules) in the browser. A CommonJS module stays out of the global scope by having an implicit 'module' scope. You choose what to expose from the module scope (usually the entry point or primary function of your module) into by augmenting the 'exports' object that every module has.
So a 'real' CommonJS module looks like this.
File A:
// a.js
function doSomething() {
console.log("I am doing something");
}
module.exports = doSomething
File B:
// b.js
doSomething();
// Exception - attempt to call a non-existent function
File C:
// c.js
var doSomething = require('a');
doSomething();
// logs "I am doing something"
In the browser which has no module scope, a.js
would be augmenting the global scope with the doSomething function, since it's declared as a global. Browserify works around this by wrapping each bundled module into a function wrapper, and supplying an 'exports' object to the included modules as an argument to this wrapper.
Enter AngularJS. You've got two approaches you can use here, of which I'm assuming from the fact that you're not using require('angular') is the first:
I tend to prefer the second approach because it's kind of weird to use Browserify to give you module scope and then make the major dependency of your project a window global.
However, AngularJS already has its own dependency-injection driven module system. When you declare angularJS components, you're attaching them to module objects which themselves have been attached to the angular
object. This means that the exports
object for your angularJS module files is essentially redundant in the case of Angular, since as long as the file executes then the angular
object will be augmented with your module and components.
You still need to 'require' the files since otherwise Browserify won't bundle them, they'll never execute, and they'll never augment the angular
object with your modules. But you don't need to add anything to the exports for Angular, since the angular
object is your exports.
So why did I spend all this time explaining how CommonJS modules and exports work? Because hopefully the other reason why you are using Browserify is to allow you to make use of modules hosted on NPM in your browser application. Most of those modules are non-angular commonJS modules, meaning their functionality is exposed via an exports. In this case it's important to capture their exports in a variable when you require them, such as I'm doing in c.js
above. Similarly, if you write some modules and release them to NPM, your users are going to expect you'll be adding the entry point to your module to the exports
object of the file declared as main in your package.json
.