Skip to content

Commit

Permalink
Middleware support
Browse files Browse the repository at this point in the history
  • Loading branch information
ohager committed Feb 11, 2017
1 parent f57de49 commit d39b22a
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 10 deletions.
51 changes: 44 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ Furthermore, __nanoflux__ uses a pure functional approach as a performant soluti

- Extremely tiny implementation
- No dependencies at all
- Pure Functional approach (totally event less)
- Support for full Flux using full stack of ActionProvider/Creator, Dispatcher, and Stores
- Support for a simplified 'fluxy' concept, where Dispatcher is also ActionProvider
- Interoperable/Chainable Stores
- Multiple Dispatchers
- Built in ActionCreator (*new*)
- Quite fast (*recently optimized*)
- Built in ActionCreator
- Quite fast
- CommonJS, RequireJS ready
- Middleware support (*new, since 1.1.0*)

> Hint: Have a look at [nanoflux-fusion](https://github.com/ohager/nanoflux-fusion), which is an upcoming extension for
> Hint: Have a look at [nanoflux-fusion](https://github.com/ohager/nanoflux-fusion), which is an extension for
*nanoflux* providing a even more comfortable API inspired by [redux](http://redux.js.org/)


Expand All @@ -45,9 +45,10 @@ A *Store* and/or an *ActionProvider* is not part of their library, and therefore
And even a bit smaller than __nanoflux__. The developer gains more liberty on implementation decisions, but for the costs of more work.
For example, it is left to the developer how stores and actions may interoperate, p.e. common approaches base on event emitters.

In this point __nanoflux__ offers slightly less flexibility with its a pure functional approach only - at least regarding
the dispatcher-store-binding - but is more comfortable.

In this point __nanoflux__ offers slightly less flexibility with its convention based the dispatcher-store-binding, but is more comfortable.

Since version 1.1.0 __nanoflux__ provides a middleware, which allows something like a payload data transformation pipeline, or dispatch inspection for logging, or debugging tools.

# Size
__nanoflux__ is a really tiny implementation, although it offers *much* more comfort than the reference implementation from Facebook.

Expand Down Expand Up @@ -162,6 +163,42 @@ The following example demonstrates the 'full' Flux approach, using ActionProvide
}
```


## Middleware Example

Applying middleware is as simple as licking ice cream on the beach:

```javascript
function Logger(){
var log = [];

return function(handlerName, args){
log.push({
handler: handlerName,
payload : args
}
)
}
}

// somewhere in your app --- using the fluxy approach for sake of simplicity
// ...
var dispatcher = NanoFlux.createDispatcher(null, ["action1", "action2"]);
NanoFlux.use(new Logger(), dispatcher);

dispatcher.action1({foo:"fromAction1"});
/* Log is: [{handler: "onAction1", payload: [{foo:"fromAction1"}]}] */

dispatcher.action2({foo:"fromAction2"});
/* Final Log is:
[
{handler: "onAction1", payload: [{foo:"fromAction1"}]}
{handler: "onAction2", payload: [{foo:"fromAction2"}]}
]
*/

```

# Getting nanoflux

You may pick the library directly from ``./dist``, use ``npm install nanoflux``, or use ``bower install nanoflux``
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "nanoflux",
"description": "nanoflux is a very lightweight (about 3 KiB!) agnostic full Flux implementation.",
"version": "1.0.8",
"version": "1.1.0",
"author": "Oliver Hager",
"email": "oliver@devbutze.com",
"private": false,
Expand Down
2 changes: 2 additions & 0 deletions spec/dispatcher-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,7 @@ describe("Dispatcher Creation", function () {
expect(typeof(dispatcher.action1)).toBe("function");
expect(typeof(dispatcher.action2)).toBe("function");
});

});

// @endif
80 changes: 80 additions & 0 deletions spec/nanoflux-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,83 @@ describe("NanoFlux Advanced Techniques", function () {
});

});


describe("Nanoflux Middleware", function(){

beforeEach(function(){
NanoFlux.reset();
});

it("should use a single middleware for a fluxy dispatcher", function () {
var dispatcher = NanoFlux.createDispatcher(null, "action1");

var testMiddleware = function(storeHandlerName, args){
expect(storeHandlerName).toBe("onAction1");
expect(args[0]).toEqual({foo: "bar"});
};
NanoFlux.use(testMiddleware, dispatcher);

dispatcher.action1({foo:"bar"})
});

it("should use multiple middlewares for a fluxy dispatcher", function () {
var dispatcher = NanoFlux.createDispatcher(null, "action1");

var testMiddleware1 = function(storeHandlerName, args){
expect(storeHandlerName).toBe("onAction1");
expect(args[0]).toEqual({foo: "bar"});
};

var testMiddleware2 = function(storeHandlerName, args){
expect(storeHandlerName).toBe("onAction1");
expect(args[0]).toEqual({foo: "bar"});
};

NanoFlux.use(testMiddleware1, dispatcher);
NanoFlux.use(testMiddleware2, dispatcher);

dispatcher.action1({foo:"bar"})
});

function TestMiddleware(){

var noCalls = 1;

return function(handlerName, args){
if(noCalls === 1){
expect(handlerName).toBe("onAction1");
expect(args[0]).toEqual({foo: "fromAction1"});
}
if(noCalls === 2){
expect(handlerName).toBe("onAction2");
expect(args[0]).toEqual({foo: "fromAction2"});
}
noCalls++;
}
}

it("should use middleware with action creators", function () {
var dispatcher = NanoFlux.getDispatcher();

function ActionProvider(dispatcher){
this.action1 = function(data){
dispatcher.dispatch('action1',data);
};
}
var actions1 = new ActionProvider(dispatcher);
NanoFlux.use(new TestMiddleware(), dispatcher);
actions1.action1({foo:"fromAction1"});
});


it("should use single middleware for a multiple actions", function () {
var dispatcher = NanoFlux.createDispatcher(null, ["action1","action2"]);

NanoFlux.use(new TestMiddleware(), dispatcher);

dispatcher.action1({foo:"fromAction1"});
dispatcher.action2({foo:"fromAction2"});
});

});
14 changes: 14 additions & 0 deletions src/dispatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function Dispatcher(actions) {
this.__stores = [];
this.__handlerMapCache = {};
this.__isDispatching = false;
this.__middlewares = [];

var createActionList = function (actionArray) {

Expand Down Expand Up @@ -42,6 +43,8 @@ Dispatcher.prototype.__callAction = function(){
var handler = this.__getHandlerName(arguments[0]);
var args = Array.prototype.slice.call(arguments,1);

this.__callMiddleware(handler, args);

for (var i = 0; i < this.__stores.length; ++i) {
var store = this.__stores[i];
if(store[handler]){
Expand All @@ -56,6 +59,17 @@ Dispatcher.prototype.__registerAction = function (actionName) {
}
};


Dispatcher.prototype.__callMiddleware = function(actionName, data){
for (var i = 0; i < this.__middlewares.length; ++i) {
this.__middlewares[i].call(null, actionName, data);
}
};

Dispatcher.prototype.addMiddleware = function(fn){
this.__middlewares.push(fn);
};

Dispatcher.prototype.connectTo = function (storeArray) {

var stores = guaranteeArray(storeArray);
Expand Down
10 changes: 8 additions & 2 deletions src/nanoflux.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ module.exports = {

getActions: function(name){
return actionCreatorFactory.getActions(name);
}

},
use : function(fn,dispatcher){
if(!dispatcher){
dispatcherFactory.getDispatcher().addMiddleware(fn);
}else{
dispatcher.addMiddleware(fn);
}
}
};

0 comments on commit d39b22a

Please sign in to comment.