Fluss is deprecated and not actively maintained anymore. It was a good learning experience but the core concepts are flawed. I'd suggest using Redux, Immutable and Bacon.
fluss is an application framework for the frontend and the backend. It is an interpretation of the flux architecture that establishes a unidirectional flow of data through the application.
fluss is written in ES6. Views created with React are the target but fluss has no dependencies whatsoever to React. Using other view technologies is possible.
Reach me on Twitter @drawableIO
- Streams: A simple stream implementation for reactive programming.
- Stores: An implementation of record stores and array stores for keeping application state. These provide reactive streams for updates. Stores can be nested. Stores provide an immutable proxy.
- Domains. They define a closed set of stores and actions. You can create several.
- Actions. Really simple. You need to provide the functions yourself or call a generic execution function on the domain.
- Plugins. Encapsulate all you need to perform an action and revert an action in one place.
The npm module of fluss provides commonjs.
This is beta software. I am still figuring out how things are best implemented so APIs and behavior may change. Bugs are likely, but there are some tests.
fluss is compiled to ES5 so you need a modern browser. It is tested on the latest Firefox (33+), Chrome (37+) and IE 10. It should work for ChromeApps, in NodeWebkit, Atomshell and the likes.
npm install fluss
See fluss-npm-module-usage on how to setup your project in various ways.
Use fluss in ES6
import Fluss from 'fluss'
Create stores ...
var todos = Fluss.Store.array();
todos.push(Fluss.Store.record( { title: "learn fluss...", completed: false } );
todos[0].complete = true;
todos.forEach(function(todo) {
console.log(todo.title + " is " + (todo.completed ? "done" : "active"));
});
Stores are reactive ...
todos.newItems
.forEach(function(update) {
console.log(update.value.title + " was added");
));
todos.push(Fluss.Store.record( { title: "make coffee...", completed: false } ));
// The console now reads
// make coffee... was added
Filtered (and mapped) stores are even more reactive (within limits)...
// todos may hold:
// { title: "learn fluss...", completed: true }
// { title: "make coffee...", completed: false }
completed = todos.filter(function(item) {
return item.completed;
})
completed.newItems.forEach(function(update) {
console.log(update.value.title + " was completed!");
});
// completed now holds
// { title: "learn fluss...", completed: true }
todos[1].completed = true;
// completed now holds:
// { title: "learn fluss...", completed: true }
// { title: "make coffee...", completed: true }
//
// And the console reads
// make coffee... was completed!
Create a domain to bundle state and action behaviour
class Application extends Fluss.Domain {
constructor() {
super();
this._todos = Fluss.Store.array();
}
Create a plugin...
class AddTodo extends Fluss.Plugin {
run(domain, action, title) {
domain.todos.push(Fluss.Store.record({ title: title, completed: false }));
}
}
... add it to your container...
var NEW_TODO:number = 1000; // Better use enums ;-)
application.wrap(NEW_TODO, new AddTodo());
... and execute the action
application.execute(NEW_TODO, "... and make an awesome app with it");
Extend your plugin to support UNDO/REDO
class AddTodo extends Fluss.Plugin {
run(domain, action, title) {
domain.todos.push(Fluss.Store.record({ title: title, completed: false}));
}
getMemento(domain, action) {
return container.todos.length
}
restoreFromMemento(domain, memento) {
container.todos.remove(memento, 1);
}
}
... and now you can undo actions
// Create a new Todo
domain.execute(NEW_TODO, "Never do unit tests again");
// Reconsider... and undo your last action
domain.undo();
Please see the tutorial. Attention: This is still based on the Typescript version. It also misses the latest changes, like the introduction of the domain object.
I don't know all implementations of flux so not all may apply to every implementation.
No event emitter in the classical sense is used. Change notifications from stores to the UI (or whomever) are transported using reactive streams. Reactive programming seems like a natural fit for React UIs - not because of the similarities in names.
The store just stores data - nothing else. Handling the actions is done in the plugin. The plugin manipulates the data in the store. The plugin even knows how to undo the action, i.e. what data changes to apply to get to an earlier state.
There are other implementations that do this as well. Basically you can create a domain, that defines the data and the actions that are performed on that data. Actions are executed on the domain. This allows you to have multiple domains in your application. Most relevant use case is separating UI state from Application state.
You need node, NPM, Babel, Gulp and Mocha installed globally.
Checkout the whole thing from github
git clone git://github.com/drawable/fluss.git
Go to the directory and do an
npm install
Now you should be able to compile the typescript with
gulp compile
and run the tests with
npm test
or
mocha
Building the npm module is done using
gulp module-build
It creates a directory build
with everything in it.
- Fix error that made Fluss.Tools unusable
This release ist not backwards compatible!
Converted from Typescript to ES6.
In order to simplify the API this contains breaking changes:
- Stream.createStream is now Stream.create
- The streamprovider is now in it's own submodule.
- Stream.createStreamProvider is now StreamProvider.create
- There is no dispatcher anymore. Instead of a singleton dispatching actions globally use Domain instances
- Plugins.BasePlugin is now it's own module Plugin
- Plugins.Container is now it's own module Domain. It is completely rewritten into a simpler implementation and handles action execution and undo handling itself
- Instead of Dispatcher.dispatchAction use aDomainInstance.execute
- There is no UndoManager anymore.
- Added: Stream.throttle, Stream.debounce, Stream.buffer
- API-Docs using TypeDoc
- Fixed issues with AMD where multiple usages of the module would lead to multiple module instances
- Proper library bindings for Typescript enabling development in AMD and CommonJS
Copyright © 2014, 2015 Stephan Smola