Last Updated: February 25, 2016
·
4.142K
· sevcsik

Sharing modules between NodeJS and AngularJS

Gist: https://gist.github.com/sevcsik/9207267

They say that one of the pros of NodeJS is that you use the same language on the back-end and the front-end, so it's easy to share code between them. This sounds great in theory, but in practice the synchronous dependency handling in NodeJS works completely different than any client-side frameworks (which are asynchronous).

Usually that means that you end up copy-pasting your code between your NodeJS sources and your client-side sources, or you use some tool like Browserify, which is brilliant, but they add an extra step in the build process and likely will conflict with the dependency handling of the framework of your choice (like AngularJS DI). I couldn't look in the mirror if I would call that code sharing.

Fortunately, with a couple of lines of boilerplate code you can write a module which works in NodeJS and AngularJS as well without any modification. I'm yet to find a way to document them seamlessly though.

// We will pass these to the wrapper function at the end of the file
(function(isNode, isAngular) {

// This wrapper function returns the contents of your module, 
// with dependencies
var SilverBulletModule = function(Bullet, Silver) {
  var SilverBullet = function() {
    // something awesome happens here
  };
  return SilverBullet;    
};

if (isAngular) {
  // AngularJS module definition
  angular.module('app.silverbullet', ['app.silver', 'app.bullet']).
    factory('SilverBullet', ['Bullet', 'Silver', SilverBulletModule]);
} else if (isNode) {
  // NodeJS module definition
  module.exports = SilverBulletModule(
    require('bullet.js'), 
    require('silver.js')
  );
}

})(typeof module !== 'undefined' && module.exports,
  typeof angular !== 'undefined');   

And that's it. No globals in the front-end, and dependencies will work. The isNode and isAngular vars are in the closure, so they can be used to switch between platform-dependent code blocks (such as angular.extend and node.extend).

Since you'd need the isAngular branch and the isNode branch anyway, and you'd also need the wrapper function on the front-end, there's only 4 additional lines needed make your module compatible with both -ends.

Porting to RequireJS should be similar, since they both use wrapper functions and dependencies as function arguments.