GithubHelp home page GithubHelp logo

nvdnkpr / scaleapp Goto Github PK

View Code? Open in Web Editor NEW

This project forked from flosse/scaleapp

0.0 2.0 0.0 1.46 MB

scaleApp is a JavaScript framework for scalable One-Page-Applications

Home Page: http://www.scaleapp.org/

License: MIT License

scaleapp's Introduction

What is scaleApp?

scaleApp is a tiny JavaScript framework for scalable One-Page-Applications / Single-Page-Applications. The framework allows you to easily create complex web applications.

Build Status Dependency Status NPM version

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.

scaleApp architecture

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 the 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 (static) API to 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 / 9k min / 3.5k 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 MVC
  • i18n - multi language UIs
  • permission - take care of method access
  • state - Finite State Machine
  • submodule - cascade modules
  • dom - DOM manipulation
  • strophe - XMPP communication
  • modulestate - event emitter for init and destroy
  • util - helper methods like mixin, uniqueId etc.
  • ls - list modules, instances & plugins

You can easily define your own plugin (see plugin section).

Download

Latest stable 0.4.x version

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>

If you're going to use it with node:

npm install scaleapp --save
var sa = require("scaleapp");

or use bower:

bower install scaleapp

Create a core

First of all create a new core instance:

var core = new scaleApp.Core();

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 === sandbox.options)            // true
      (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
});

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 to
  • data : the data itself
  • cb : callback method

The emit function is accessible through the sandbox:

sandbox.emit( "myEventTopic", myData );

You can also use the shorter method alias emit.

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);

And you can remove a callback function from all channels

sandbox.off(callback);

Or remove all subscriptions from a channel:

sandbox.off("channelName");

Flow control

Series

var task1 = function(next){
  setTimeout(function(){next(null, "one");},0);
};

var task2 = function(next){
  next(null, "two");
};

scaleApp.util.runSeries([task1, task2], function(err, results){
  // result is ["one", "two"]
});

Waterfall

var task1 = function(next){
  setTimeout(function(){
    next(null, "one", "two");
  },0);
};

var task2 = function(res1, res2, next){
  // res1 is "one"
  // res2 is "two"
  next(null, "yeah!");
};

scaleApp.util.runWaterfall([task1, task2], function(err, result){
  // result is "yeah!"
});

Plugins

There are some plugins available within the plugins folder. For more information look at the plugin README.

Register plugins

A single plugin can be registered with it option object in that way:

core.use(plugin,options);

If you want to register multiple plugins at once:

core.use([
  plugin1,
  plugin2,
  { plugin: plugin3, options: options3 }
]);

Write your own plugin

It's easy:

core.use(function(core){
  core.helloWorld = function(){ alert("helloWorld"); };
};

Here a more complex example:

core.use(function(core, done){

  // extend the core
  core.myCoreFunction = function(){ alert("Hello core plugin") };
  core.myBoringProperty = "boring";

  // extend the sandbox class
  core.Sandbox.prototype.myMethod = function( /*...*/);

  // define a method that gets called when a module starts
  var onModuleInit = function(instanceSandbox, options, done){

    // e.g. define sandbox methods dynamically
    if (options.mySwitch){
      instanceSandbox.appendFoo = function(){
       core.getContainer.append("foo");
      };
    }

    // or load a something asynchronously
    core.myAsyncMethod(function(data){

      // do something...
      // now tell scaleApp that you're done
      done();
    });
  };

  // define a method that gets called when a module stops
  var onModuleDestroy = function(done){
    myCleanUpMethod(function(){
      done()
    });
  };

  // don't forget to return your methods
  return {
    init: onModuleInit,
    destroy: onModuleDestroy
  };

});

Use your own Sandbox

core.use(function(core){

  core.Sandbox = function(core, instanceId, options){

    var foo = function(){ /* ... */ };

    var myEmit = function(channel, data){
      core.emit(channel + '/' + instanceId, data);
    };

    // return your own public API
    return {
      foo: foo,
      emit: myEmit
    };

  };
});

Usage:

core.myCoreFunction() // alerts "Hello core plugin"

var MyModule = function(sandbox){
  init: function(){ sandbox.appendFoo(); },  // appends "foo" to the container
};

Build browser bundles

If you want scaleApp bundled with special plugins type

grunt custom[:PLUGIN_NAME]

e.g. cake custom:dom:mvc creates the file scaleApp.custom.js that contains scaleApp itself the dom plugin and the mvc plugin.

API

scaleApp

  • scaleApp.VERSION - the current version of scaleApp
  • scaleApp.Mediator - the Mediator class
  • scaleApp.Sandbox - the Sandbox class
  • scaleApp.Core - the Core class

Core

// use default sandbox
var core = new scaleApp.Core();

// use your own sandbox
var core = new scaleApp.Core(yourSandboxClass);
  • core.register(moduleName, module, options) - register a module
  • core.use(plugin, options) - register a plugin
  • core.use(pluginArray) - registers an array of plugins
  • core.boot(callback) - initialize plugins (will be executed automatically on ´start´)
  • core.start(moduleId, options, callback) - start a module
  • core.stop(instanceId, callback) - stop a module

Mediator

// create a mediator
var mediator = new scaleApp.Mediator();

// create a mediator with a custom context object
var mediator = new scaleApp.Mediator(context);

// create a mediator with cascaded channels
var mediator = new scaleApp.Mediator(null, true);
  • mediator.emit(channel, data, callback)
  • mediator.on(channel, callback, context)
  • mediator.off(channel, callback)
  • mediator.installTo(context)
// subscribe
var subscription = mediator.on(channel, callback, context);
  • subscription.detach - stop listening
  • subscription.attach - resume listening

Sandbox

var sandbox =  new scaleApp.Sandbox(core, instanceId, options)` - create a Sandbox
  • sandbox.emit is mediator.emit
  • sandbox.on is mediator.on
  • sandbox.off is mediator.off

Changelog

v0.4.0 (07-2013)

  • added a Core class that can be instantiated (var core = new scaleApp.Core();)
  • new plugin API (scaleApp.plugins.register moved to core.use)
    • support asynchronous plugins
    • added boot method to initialize asynchronous plugins
  • changed API
    • startAll() is now start()
    • stopAll() is now stop()
    • the API is now chainable (e.g. core.use(X).register("foo",bar).start("foo"))
    • removed setInstanceOptions
    • removed unregister and unregisterAll
    • dropped subscribe, unsubscribe and publish from Mediator API (use on, off and emit instead)
    • the methods lsModules, lsInstances, lsPlugins moved to the ls plugin
    • the destroy method of a module is now optional
    • the callback property of the start option object was removed. Use the modulestate plugin instead
  • plugins
    • new submodule plugin
    • improved permission and i18n
    • new modulestate plugin to emit events on module state changes
  • cleaner code
  • Mediator: do not clone objects any more (do it manually instead)
  • test with mocha, chai, sinon, karma and PhantomJS instead of buster.js

v0.3.9 (12-2012)

  • grunt as build systemt
  • added waterfall flow control method
  • improved permission plugin
  • improved state plugin (thanks to Strathausen)
  • added xmpp (stropje.js) plugin
  • added a simple clock module
  • added bower support
  • added this changelog

v0.3.8 (08-2012)

  • bug fixes
  • added support for async. callback of the publish method
  • added amd support

v0.3.7 (07-2012)

  • bug fixes
  • added permission plugin
  • ported specs to buster.js
  • support for global i18n properties

v0.3.6 (03-2012)

  • support for async. and sync. module initialization

v0.3.5 (03-2012)

  • simpified Mediator code

v0.3.4 (03-2012)

  • bugfixes
  • added lsModules and lsInstances
  • improved README

v0.3.3 (02-2012)

  • run tests with jasmine-node instead of JSTestDriver
  • added travis testing
  • improved README

v0.3.2 (01-2012)

  • bugfixes
  • improved Mediator

v0.3.0 (11-2011)

  • ported to Coffee-Script
  • removed jQuery dependency

v0.2.0 (07-2011)

  • bugfixes
  • improvements

v0.1.0 (02-2011)

  • first release

Testing

npm test

Demo

WARNING: the demo is totally out of date!

You can try out the sample application that is build on scaleApp. Also have a look at the source code.

Licence

scaleApp is licensed under the MIT license. For more information have a look at LICENCE.txt.

scaleapp's People

Contributors

flosse avatar strathausen avatar svnlto avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.