UNPKG

4.44 kBMarkdownView Raw
1horse
2=====
3
4horse is a couple of helper classes that can be used to help you build isomorphic
5applications for io.js / node. It abstracts routing and rendering helpers so
6that you can plug in a rendering system, bind links, and have an application
7that works anywhere.
8
9The vast bulk of your application will live in your routes file (`routes.jsx`
10in the example below), your API library, and your views - and will be shared
11between the server and the client. horse's job is to get out of the way so that
12you don't care where the code is running, and yet you get both server-side and
13client-side rendering.
14
15A Brief Overview
16----------------
17
18```
19 ======================================
20 Your App
21
22 +---------+ +---------------+
23 | koa | | html5 history |
24 +---------+ | api |
25 | +---------------+
26 req req
27 | | render and
28 \ / wait for new route
29 ------------------------ event
30 | ^
31 v |
32 ====================================== |
33 +--------------+ |
34 | horse/App.js | |
35 +--------------+ |
36 | |
37 v |
38 ==================================== |
39 Your App's Routes |
40 |
41 +---------------+ |
42 | route handler | -> yield { body: reactElement }
43 | | -> throw MissingAuthenticationError();
44 +---------------+
45```
46
47The App has an instance of an Express-like request router that it uses to map
48requests to the appropriate handling function, and is run on both the client-
49and server- side. It's meant to abstract just enough boilerplate out of the
50way so that you can do your own custom stuff.
51
52An example usage might be like: (es6 incoming)
53
54`routes.jsx`
55
56```javascript
57// This is used both client- and server- side, and simply sets up an app with
58// routes; in this case, returning React elements.
59
60import Layout from '../layouts/layout.jsx';
61import Index from '../pages/index.jsx';
62
63function setupRoutes(app) {
64 app.router.get('/', function *() {
65 this.layout = Layout;
66
67 var user = yield db.getUser(1);
68 this.props = { user };
69
70 this.body = <Index {...this.props} />;
71 });
72}
73
74export default setupRoutes;
75```
76
77
78`server.es6.js`
79
80```javascript
81import koa from 'koa';
82import React from 'react';
83
84import {App} from 'horse';
85import setupRoutes from './setupRoutes';
86
87var server = koa();
88
89var app = new App();
90setupRoutes(app);
91
92server.use(function *(next) {
93 yield app.route(this, function () {
94 var Layout = this.layout;
95
96 this.body = react.renderToStaticMarkup(
97 <Layout>{this.body}</Layout>
98 );
99 });
100}
101```
102
103`client.es6.js`
104
105```javascript
106import React from 'react';
107import {ClientApp} from 'horse';
108
109import setupRoutes from './setupRoutes';
110
111import jQuery as $ from 'jquery';
112
113var app = new ClientApp();
114setupRoutes(app);
115
116var $mountPoint = document.getElementById('app-container');
117
118$(function() {
119 $('body').on('click', 'a', function(e) {
120 var $link = $(this);
121
122 var ctx = app.buildContext($link.attr('href'));
123 yield app.route(ctx);
124
125 React.render(ctx.body, $mountPoint);
126 });
127});
128
129```
130
131
132Final Notes
133-----------
134
135Default events:
136
137```
138app.on('route:start', function(ctx){})
139app.on('route:end', function(ctx){})
140app.on('route:end', function(error, ctx, app){})
141```
142
143You can also add an array of request start / end functions that operate per
144request, instead of globally on the app:
145
146```
147app.startRequest.push(function(app, server) {
148 if (server) { console.log('started on the server'); }
149});
150
151app.endRequest.push(function(app, server) {
152 if (server) { console.log('started on the server'); }
153});
154```
155
156
157* This is all written using ES6, so you'll need to use a transpiler; I like
158[babel](http://babeljs.io). To get babel to work with npm modules, you'll
159need to turn off `ignore npm` and add `.es6.js` to the transpiled files, like
160so:
161
162```
163require('babel/register')({
164 ignore: false,
165 only: /.+(?:(?:\.es6\.js)|(?:.jsx))$/,
166 extensions: ['.js', '.es6.js', '.jsx' ],
167 sourceMap: true,
168});
169```
170
171* Tested with iojs 1.0.0 and later and node 0.10.30 and later.