ngDefine

A friendly integration of AngularJS into RequireJS powered applications

This project seamlessly integrates AngularJS into RequireJS based applications.

Overview

Using ngDefine you can leverage RequireJS to package AngularJS modules into reusable components.

ngDefine('my.module', [
  'jquery',
  './bar',
  'module:ngResource',
  'module:my.other.module:my-other-module'
], function(module, $) {

  // define the module
  module.value("foo", "bar");
});

ngDefine allows you to declare both plain RequireJS dependencies and AngularJS modules that get resolved using RequireJS before the module definition callback is called.

It instantiates the AngularJS module with dependencies to other modules that may be declared via module:[moduleName]:[moduleLocation].

The library supports minification that reduces module definitions to plain AngularJS / RequireJS.

Module Definition

AngularJS modules are defined via the ngDefine function:

ngDefine('app', function(module) {

  // module => { .., name: 'app', .. }
  module.value('foo', 'bar');
});

ngDefine

The function accepts a module name, an optional list of module dependencies and a module definition body. The list of dependencies may contain AngularJS module dependencies in the form module:{angularModuleName}[:{requireJsPath}].

The optional requireJsPath is used to map the AngularJS module to a RequireJS location. If no path is given, the RequireJS path is produced by replacing all . with /.

Full Example

ngDefine('app', [
  // require normal requireJS packages
  'angular',
  'jquery',

  // require package local files
  './foo',

  // require angular modules
  'module:ngResource:angular-resource',
  'module:my.module.bar:my-module/bar',
  'module:my.other.module:my-other-module',

  // require without a require js path -> locates the module under
  // foo/baz
  'module:foo.baz'
],
function(module, angular, jquery) {
  // callback gets passed the defined module as the first
  // parameter, all other objects defined by declared
  // dependencies follow at parameters 1..n

  module // --> { .., name: 'app', .. }

  // define module now
  module.value("foo", "bar");
});

Project Configuration

A require configuration using ngDefine / AngularJS may look as follows:

require({
  paths: {
    // include ngDefine script in path
    'ngDefine' : 'lib/ngDefine', 
    'angular' : 'lib/angular/angular',

    // optional dependencies
    'angular-resource' : 'lib/angular/angular-resource'
    'jquery' : 'lib/jquery/jquery'
  },
  shim: {
    'angular' : { deps: [ 'jquery' ], exports: 'angular' },
    'angular-resource': { deps: [ 'angular' ] }
  },
  packages: [
    // application package
    { name: 'app', location: 'app' },

    // other angular modules
    { name: 'my-module', location: 'lib/my-module' },
    { name: 'my-other-module', location: 'lib/my-other-module' }
  ]
});

The following piece of code may then be used to bootstrap the application:

// require ngDefine and all angular modules your app requires
require([ 'ngDefine', 'angular' ], function(ngDefine, angular) {

  // require the application
  require(['app'], function() {

    // bootstrap the application
    angular.bootstrap(document.body, ['app']);
  });
});

It ensures that ngDefine is loaded before the application modules are defined. Additionally it bootstraps the AngularJS application after the application and its dependencies have been resolved.

Minification

The library provides the script ngr.js that can be used to minify modules created using ngDefine. ngr.js is a wrapper to the RequireJS and works in NodeJS and browser environments.

To expose the script as the ngr task into grunt, use the following code snippet:

// project configuration
grunt.initConfig({
  // ...

  ngr: {
    minify: {
      // supports all options r.js understands
      options: {
        name : 'app/main',
        out: 'build/app.min.js'

        // path, shim and package configurations 
        // ...
      }
    }
  }
});

// sample task for ngDefine optimization
grunt.registerMultiTask('ngr', 'Minify app', function() {

  var done = this.async();

  var ngr = require('path/to/ngr.js');

  ngr.optimize(this.data.options, function() {
    done('success');
  }, function(e) {
    console.log('Error during minify: ', e);
    done(new Error('With failures: ' + e));
  });
});

FAQ

Why should I use RequireJS? After all, AngularJS includes a dependency injection mechanism, doesn't it?

AngularJS offers a dependency injection mechanism at runtime. When building applications a developer must know which script files to include into his application so that all runtime dependencies are met when the application is bootstrapped. AngularJS does not allow application developers to define these dependencies on the file level. However, that is exactly what RequireJS does.

ngDefine simply employs RequireJS and gives developers the ability to declare AngularJS modules and their dependencies in a portable way. This way the modules can be reused and external dependencies can easily be resolved.

ngDefine bridges the gap between RequireJS and AngularJS?

Not quite, read again. There is no gap between RequireJS and AngularJS, as both serve different purposes during different stages of the application lifecycle. ngDefine allows you to leverage the power of both technologies.

Can an application that uses ngDefine be minified?

Yes, minification can be done.

License

Use under terms of MIT license.