AngularJS
with
RequireJS
Thomas Burleson
SiriusXM Satellite Radio
Preview
Take-away Summary
-
AngularJS injects instances
-
RequireJS injects Classes
RequireJS
Is it
needed
with AngularJS
?
Fast-dive into
RequireJS
concepts...
How
to use
RequireJS
with
AngularJS
?
Is RequireJS really needed ?
Option #1: Load all the code in one large Javascript file (or block)
var FlightDashboard = function( $scope, user, travelService ) { /* ... */ },
$QDecorator = function ($provide) { /* ... */ };
angular.module( "FlightServices", [ ] )
.config( $QDecorator )
.service( "user", function() { /* ... */ })
.service( "travelService", function( user, $q ) { /* ... */ })
.service( "weatherService", function( $q ) { /* ... */ })
angular.module( "FlightApp", [ "FlightServices" ] )
.controller( "flightDashboard", FlightDashboard );
... reasonable for simple apps.
See the code dependencies !
... for a simple app!
Option #2: Let's use Packages instead...
... but we still have to manually manage the loads ( aka imports )
What about large apps ?
Imagine the dependency complexities !
for real-world application code !
We need a
Package Dependency Manager
( aka Linker )
Fast-Dive into RequireJS !
4 Dependency Types
4 Great Features
3 Simple APIs
4 Types of Dependencies
Load
Dependency
Construction
Dependency
Runtime
Dependency
AngularJS Module Dependency
4 Great features using RequireJS
!
1) Package
Dependency
Manager
2) Injector ( note: this not AngularJS Injection )
3) Javascript File Loader
4) Concatenate / Uglify
RequireJS manages :
- Load dependency
- Runtime dependency
Angular JS manages :
- Construction dependency ( IoC )
- Angular Module dependency
3 Simple RequireJS APIs
1)
define
( )
- define dependencies & register factory function
2)
require
( )
-
callback function to be invoked; when
the tree of all define()s have completed
the tree of all define()s have completed
3)
requirejs
.
config
( )
- configure source paths & aliases
1.) define ( )
Creates Asynchronous Module Definitions
(
AMD
) so files
load in any order.
`
Ready
` handlers called when
dependencies resolve...
trigger
immediately if no dependencies.
`Ready` handlers
return values
which are stored by filename or ID...
Values
are injected into ready handlers of other AMD definitions.
-
Every file is wrapped in a define()
-
Every define() returns a value; cached in registry
1.)
define
( )
define(
[ ], // array of dependencies `paths` to other define() modules
function onReady( )
{ /** * Returns a value (Function, Constructor, String, Object, etc), */ } );
- The anonymous function is named onReady
-
onReady
is called immediately since no dependencies.
- onReady must return an Object ( Function, Class, or instance)
- The Object is stored in internal RequireJS registry
1.) define( ) with no dependencies :
define([ ], function ( ) { var supplant = function( template, values, pattern ) { pattern = pattern || /\{([^\{\}]*)\}/g; return template.replace(pattern, function(a, b) { var p = b.split('.'), r = values; try { for (var s in p) { r = r[p[s]]; } } catch(e){ r = a; } return (typeof r === 'string' || typeof r === 'number') ? r : a; }); }; return String.supplant = supplant;
});
- filename == ./mindspace/utils/supplant.js
-
Implicit dependency ID == mindspace/utils/supplant
1.)
define
( )
define(
[ 'mindspace/utils/supplant' ],
function onReady( supplant )
{
return XXX;
}
);
- Dependency on supplant.js file ( notice missing .js)
- Value returned from supplant.js define() is a Function
- Supplant() is only used within this AMD
- This AMD define( ) returns value XXX;
1.)
define
( )
with dependencies
:
define( [
'mindspace/utils/crypto/md5',
'utils/supplant'
],
function ( md5, supplant )
{
// Prepare the Gravatar Directive construction function
var Gravatar = function( ) { /*...*/ };
return Gravatar;
});
-
onReady arguments are injected Values; loaded by each dependent define()
-
Can use package
paths
as dependency
IDs
.
-
Can use use path `
alias
` notations also.
1.) define ( )
Builds a tree of dependencies
Builds a flat registry of values stored by module ID
Values are usually references to Class or Functions
But
NOTHING
happens until
require()
is used!
2.) require ( )
require( [ "main" ], function( app )
{
// Application has bootstrapped and started...
});
- Acts as the initialization or ROOT of the dependency tree.
- Starts the cascade of dependency checks and script loading
-
Starts the
cascade
of
define()
triggers
3.) requirejs.config ( )
require.config (
{
appDir : '',
baseUrl : './src', // relative to index.html
paths :
{
// Configure alias to full paths
'auth' : './quizzer/authentication',
'quiz' : './quizzer/quiz',
'utils' : './mindspace/utils'
}
});
- Configures locations to source & packages
- Configures aliases for define ( )
How to use RequireJS with AngularJS ?
So easy...
- Use define( ) around your modules...
-
Use define( ) around all your code...
-
Use requirejs.config( ) to set your paths
-
Use require( ) to launch your code to initialize AngularJS
AngularJS Controllers
define( [ 'utils/supplant' ], function ( supplant ) { var LoginController = function( session, authenticator, $scope, $log ) { $log.debug(
supplant( 'User {name}', session.user )
); }; return LoginController; });
-
RequireJS
is injecting Functions or Classes
-
AngularJS
is injecting
instances
of the classes
AngularJS Services
`quiz/delegates/QuizDelegate`
define([
'utils/Factory',
'quiz/builders/QuizBuilder',
'quiz/builders/ScoreBuilder'
],
function ( Factory, QuizBuilder, ScoreBuilder )
{
var quizBuilder = Factory.instanceOf( QuizBuilder ),
scoreBuilder = Factory.instanceOf( ScoreBuilder),
QuizDelegate = function ( $http, $q, $log ) { /* ... */ };
return [ "$http", "$q", "$log", QuizDelegate ];
}
);
RequireJS
is injecting
Classes
(definitions)
Instances
are constructed
external
to
AngularJS
to
be used within the
QuizDelegate
service...
AngularJS Modules
`quiz/QuizModule`
(function ( define, angular ) {
"use strict";
define([
'quiz/delegates/QuizDelegate',
'quiz/controllers/TestController',
'quiz/controllers/ScoreController'
],
function ( QuizDelegate, TestController, ScoreController )
{
var moduleName = "quizzer.Quiz";
angular.module( moduleName, [ ] )
.service( "quizDelegate", QuizDelegate )
.controller( "TestController", TestController )
.controller( "ScoreController", ScoreController );
return moduleName;
});
}( define, angular ));
AngularJS App
main.js
define([
'quiz/QuizModule',
'quiz/RouteManager',
'auth/AuthenticateModule'
],
function ( QuizModule, RouteManager, AuthenticateModule )
{
var appName = 'quizzer.OnlineTest',
depends = [ "ngRoute", AuthenticateModule, QuizModule ],
app = angular.module( appName, depends )
.config( RouteManager );
angular.bootstrap( document.getElementsByTagName("body")[0], [ appName ]);
return app;
}
);
GitHub Demo: Quizzler
Using Grunt
Build and Deploy
Supports RequireJS using grunt plugin
-
Deploy Uncompressed
-
Deploy Minified & Obfuscated
2 Secrets to Builds
(1) Configure Grunt RequireJS settings
requirejs: {
compile: {
options: {
baseUrl: "../client/src",
paths :
{
// Configure alias to full paths; relative to `baseURL`
'auth' : './quizzer/authentication',
'quiz' : './quizzer/quiz',
'utils' : './mindspace/utils'
},
out: '<%= buildDir %>/assets/js/quizzler.js',
name: 'main'
},
preserveLicenseComments : false,
optimize: "uglify"
}
}
2 Secrets to Builds
(2)
Configure Main launch point
head.js(
{ require : "./vendor/requirejs/require.js", size: "80196" },
{ angular : "./vendor/angular/angular.js", size: "551057" },
{ ngRoute : "./vendor/angular-route/angular-route.js", size: "30052" },
{ quizzler : "./assets/js/quizzler.js", size: "18762" }
)
.ready("ALL", function()
{
require( [ "main" ], function( app )
{
// Application has bootstrapped and started...
});
});
-
Load the
Uglified
app code in js/quizzler.js
- Use require( ) to trigger all define( ) & initialize AngularJS
AngularJS App
require( [ "main" ], function( ){ } );
define([
'quiz/QuizModule',
'quiz/RouteManager',
'auth/AuthenticateModule'
],
function ( QuizModule, RouteManager, AuthenticateModule )
{
var appName = 'quizzer.OnlineTest',
depends = [ "ngRoute", AuthenticateModule, QuizModule ],
app = angular.module( appName, depends )
.config( RouteManager );
angular.bootstrap( document.getElementsByTagName("body")[0], [ appName ]);
return app;
}
);
Demo
angularjs-Quizzler on GitHub
-
Development Build = 'grunt dev'
-
Production Build = 'grunt prod'
About ME
Thomas Burleson
-
email: ThomasBurleson @ Gmail.com
-
twitter: @ThomasBurleson
-
blog: www.solutionOptimist.com
- linkedIn: http://www.linkedin.com/in/ThomasBurleson
- code: https://github.com/ThomasBurleson
Need a senior, front-end architect ?
I am looking for the next great project...