ScaleApp
scaleApp is a JavaScript framework for scalable and maintainable One-Page-Applications
Install / Use
/learn @flosse/ScaleAppREADME
What is scaleApp?
scaleApp is a tiny JavaScript framework for scalable and maintainable One-Page-Applications / Single-Page-Applications. The framework allows you to easily create complex web applications.
You can dynamically start and stop/destroy modules that acts as small parts of your whole application.
Architecture overview
scaleApp is based on a decoupled, event-driven architecture that is inspired by the talk of Nicholas C. Zakas - "Scalable JavaScript Application Architecture" (Slides). There also is a little Article that describes the basic ideas.

Module
A module is a completely independent part of your application. It has absolutely no reference to another piece of the app. The only thing the module knows is your sandbox. The sandbox is used to communicate with other parts of the application.
Sandbox
The main purpose of the sandbox is to use the facade pattern. In that way you can hide the features provided by the core and only show a well defined custom static long term API to your modules. This is actually one of the most important concept for creating mainainable apps. Change plugins, implementations etc. but keep your API stable for your modules. For each module a separate sandbox will be created.
Core
The core is responsible for starting and stopping your modules. It also handles the messages by using the Publish/Subscribe (Mediator) pattern
Plugin
Plugins can extend the core or the sandbox with additional features. For example you could extend the core with basic functionalities (like DOM manipulation) or just aliases the features of a base library (e.g. jQuery).
Features
- loose coupling of modules
- small (about 300 sloc / 8,7k min / 3.3k gz)
- no dependencies
- modules can be tested separately
- replacing any module without affecting other modules
- extendable with plugins
- browser and Node.js support
- flow control
- AMD & CommonJS support
- framework-agnostic
Extendable
scaleApp itself is very small but it can be extended with plugins. There already are some plugins available:
mvc- simple MVCi18n- multi language UIspermission- take care of method accessstate- Finite State Machinesubmodule- cascade modulesdom- DOM manipulationstrophe- XMPP communicationmodulestate- event emitter forinitanddestroyutil- helper methods likemixin,uniqueIdetc.ls- list modules, instances & plugins
You can easily define your own plugin (see plugin section).
Download
Latest stable 0.4.x version
or use the CDN:
<script src="//cdnjs.cloudflare.com/ajax/libs/scaleapp/0.4.4/scaleapp.min.js" ></script>
Old stable 0.3.x version
Note
There are some API changes in version 0.4.x (see Changelog). Docs for v0.3.9 can be found within the tar/zip file.
Unstable version
git clone git://github.com/flosse/scaleApp.git
Quick Start
Link scaleApp.min.js in your HTML file:
<script src="scaleApp.min.js"></script>
or use the CDN:
<script src="//cdnjs.cloudflare.com/ajax/libs/scaleapp/0.4.4/scaleapp.min.js" ></script>
If you're going to use it with node:
npm install scaleapp --save
var sa = require("scaleapp");
or use bower:
bower install scaleapp
Create your own Sandbox
First of all create your own sandbox. By doing that you're able to guarantee a stable maintainable API for your modules.
var MySandbox = function(core, instanceId, options, moduleId) {
// define your API
this.myFooProperty = "bar";
// e.g. provide the Mediator methods 'on', 'emit', etc.
core._mediator.installTo(this);
// ... or define your custom communication methods
this.myEmit = function(channel, data){
core.emit(channel + '/' + instanceId, data);
};
// maybe you'd like to expose the instance ID
this.id = instanceId;
return this;
};
// ... and of course you can define shared methods etc.
MySandbox.prototype.foo = function() { /*...*/ };
Create a core
Now create a new core instance with your sandbox:
var core = new scaleApp.Core(MySandbox);
Register modules
core.register( "myModuleId", function( sandbox ){
return {
init: function(){ /*...*/ },
destroy: function(){ /*...*/ }
};
});
As you can see the module is a function that takes the sandbox as a parameter
and returns an object that has two functions init and destroy (the latter is
optional).
Of course your module can be any usual class with those two functions.
var MyGreatModule = function(sandbox){
return {
init: function(){ alert("Hello world!"); }
destroy: function(){ alert("Bye bye!"); }
};
};
core.register("myGreatModule", MyGreatModule);
The init function is called by the framework when the module is supposed to
start. The destroy function is called when the module has to shut down.
Asynchronous initialization
You can also init or destroy you module in a asynchronous way:
var MyAsyncModule = function(sandbox){
return {
init: function(options, done){
doSomethingAsync(function(err){
// ...
done(err);
});
},
destroy: function(done){
doSomethingElseAsync(done);
}
};
};
core.register("myGreatModule", MyGreatModule);
core.start("myGreatModule", { done:function(){
alert("now the initialization is done");
}});
Start modules
After your modules are registered, start your modules:
core
.start( "myModuleId" )
.start( "anOtherModule", function(err){
// 'anOtherModule' is running now
});
Start options
You may also want to start several instances of a module:
core.start( "myModuleId", {instanceId: "myInstanceId" } );
core.start( "myModuleId", {instanceId: "anOtherInstanceId" });
All you attach to options is accessible within your module:
core.register( "mod", function(sandbox){
return {
init: function(opt){
(opt.myProperty === "myValue") // true
},
destroy: function(){ /*...*/ }
};
});
core.start("mod", {
instanceId: "test",
options: { myProperty: "myValue" }
});
If all your modules just needs to be instanciated once, you can simply starting them all:
core.start();
To start some special modules at once you can pass an array with the module names:
core.start(["moduleA","moduleB"]);
You can also pass a callback function:
core.start(function(){
// do something when all modules were initialized
});
Moreover you can use a separate sandbox for each instance:
var MySandbox = function(){/*...*/};
core.start("module", { sandbox: MySandbox });
Stopping
It's obvious:
core.stop("moduleB");
core.stop(); // stops all running instances
Publish/Subscribe
If the module needs to communicate with others, you can use the emit and
on methods.
emit
The emit function takes three parameters whereas the last one is optional:
topic: the channel name you want to emit todata: the data itselfcb: callback method
The emit function is accessible through the sandbox (as long as you exposed the Mediator methods of course):
sandbox.emit( "myEventTopic", myData );
on
A message handler could look like this:
var messageHandler = function( data, topic ){
switch( topic ){
case "somethingHappend":
sandbox.emit( "myEventTopic", processData(data) );
break;
case "aNiceTopic":
justProcess( data );
break;
}
};
... and it can listen to one or more channels:
sub1 = sandbox.on( "somthingHappend", messageHandler );
sub2 = sandbox.on( "aNiceTopic", messageHandler );
Or just do it at once:
sandbox.on({
topicA: cbA,
topicB: cbB,
topicC: cbC
});
You can also subscribe to several channels at once:
sandbox.on(["a", "b"], cb);
If you prefer a shorter method name you can use the alias on.
attache and detache
A subscription can be detached and attached again:
sub.detach(); // don't listen any more
sub.attach(); // receive upcoming messages
Unsubscribe
You can unsubscribe a function from a channel
sandbox.off("a-channel", callback);




