An ExpressJS based React server made for hacking. Wired together with browserify, socket.io, and less CSS.
Also features:
- A basic Collection class with syncing from server to client
- Basic RPC message passing from client to server
Note:
- there is no persistence. The collections are kept only in memory, so will die with your app.
- this isn't intended as a production-ready server. It's just for quick hacks / prototypes.
- clone this repo
npm install
make run-example
This is a rather contrived example that wires together an 'app' that displays 'clocks' with an updating time pushed from the server. Clicking a button on the client will add a new clock to the list.
// index.js
var path = require('path');
var Server = require('simple-react-server').Server;
var collections = require('./shared/collections');
var rpcs = require('./shared/rpcs');
var server = new Server({
collections: collections,
rpcs: rpcs,
// Anything placed in here will be served from /
staticRoot: path.join(__dirname, 'client/public'),
// Anything in this folder will be available as css under /css/yourLessFileName.css
lessRoot: path.join(__dirname, 'client/less'),
// The root class for the browserfy bundle
clientAppPath: path.join(__dirname, 'client/app.js')
});
server.run();
// Handle RPC requests + update models
tick = () => setTimeout(() => {
collections.clocks.all().forEach((clock) => {
clock.time = new Date().toString();
clock.updates++;
collections.clocks.update(clock.id, clock);
});
tick();
}, 1000);
tick();
var idCounter = 0;
rpcs.addClock.invoke((options) => {
var id = idCounter++;
collections.clocks.add(id, {
id: id,
name: options.name,
time: new Date().toString()
});
});
// shared/collections.js
// Collection objects used to store models.
// Collection events: 'created', 'updated', 'deleted'.
// Collection methods:
// add(id, item), update(id, item), remove(id)
// item(id):Item, all():Item[], indexed():Object.<ID,Item>
// on(CB.<EventName, ID, Item>)
var Collection = require('simple-react-server').Collection;
module.exports = {
clocks: new Collection()
}
// shared/rpcs.js
// RPC methods used to send messages from the client to the server.
// Handle events on the server with:
// require('../shared/rpcs').addClock.invoke(function (request) { ... });
// Send events on the client with:
// require('../shared/rpcs').addClock({ ...request... });
var RPC = require('simple-react-server').RPC;
module.exports = {
addClock: new RPC()
}
// client/app.js
var AppView = require('./AppView.jsx');
var Client = require('simple-react-server').Client;
var collections = require('../shared/collections.js');
var rpcs = require('../shared/rpcs.js');
var client = new Client({ collections: collections, rpcs: rpcs });
client.render(AppView);
// client/AppView.jsx
var collections = require('../shared/collections.js');
var React = require('react');
var rpcs = require('../shared/rpcs.js');
class Clock extends React.Component {
render () { return <div>{this.props.name}: {this.props.time}</div> }
}
class AppView extends React.Component {
constructor () {
super();
this.state = { clocks: [] };
}
componentDidMount () {
collections.clocks.on('created', this.updateClocks.bind(this));
collections.clocks.on('updated', this.updateClocks.bind(this));
collections.clocks.on('deleted', this.updateClocks.bind(this));
}
updateClocks () { this.setState({ clocks: collections.clocks.all() }); }
// Send an RPC message to the server
addClock () { rpcs.addClock({ name: 'Foo clock' }); }
renderClocks () { this.state.clocks.map((clock) => <Clock {...clock} />); }
render () {
return <div>
<div className='clocks'>{this.renderClocks()}</div>
<button onClick={this.addClock.bind(this)}>Add clock</button>
</div>
}
};
module.exports = AppView;