Skip to content

Commit 006c296

Browse files
committed
added director for routing
1 parent 60b421b commit 006c296

File tree

9 files changed

+176
-31
lines changed

9 files changed

+176
-31
lines changed

comments.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[{"key":"1","author":"Dagobert Duck","text":"This is one comment"},{"key":"2","author":"Donald Duck","text":"This is *another* comment"}]
1+
[{"key":"1","author":"Dagobert Duck","text":"This is one comment"},{"key":"2","author":"Donald Duck","text":"This is *another* comment"},{"author":"","text":""},{"author":"adsdas","text":"asdasda"}]

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"react": "~0.8.0",
1717
"showdown": "aslansky/showdown",
1818
"shoe": "0.0.15",
19-
"node-bourbon": "1.0.0"
19+
"node-bourbon": "1.0.0",
20+
"director": "~1.2.2"
2021
},
2122
"devDependencies": {
2223
"gulp-util": "~2.2.12",

readme.md

+142-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,142 @@
1-
# [gulp](http://gulpjs.com/), [libSass](http://libsass.org/)/[Bourbon](http://bourbon.io/), [React](http://facebook.github.io/react/index.html) and [shoe](https://github.com/substack/shoe) playground
1+
# [gulp](http://gulpjs.com/), [browserify](http://browserify.org/), [node-sass](https://github.com/andrew/node-sass)/[Bourbon](http://bourbon.io/), [React](http://facebook.github.io/react/index.html) and [shoe](https://github.com/substack/shoe) playground
2+
3+
## Why?
4+
5+
I wanted to play with some newer stuff. So I decided to have a look at the "newest" contenders in the web dev playground.
6+
7+
## What?
8+
9+
* [gulp](http://gulpjs.com/) the streaming task runner for node. Previously I used [grunt](http://gruntjs.com/) and it is great. But there is one problem ... it gets really slow with bigger problems. Especially in combination with [sass](http://sass-lang.com/)/[compass](http://compass-style.org/).
10+
* [browserify](http://browserify.org/) allows you to use node.js-style requires in the browser and [npm](https://npmjs.org/) as the package manager. For me it is easier to use than [require.js](http://requirejs.org/) because of a much simpler configuration.
11+
* [node-sass](https://github.com/andrew/node-sass) uses [libSass](http://libsass.org/) to process sass/scss files into css. Because it is written in node.js and uses the c bindings it is much faster than the ruby [sass](http://sass-lang.com/) executable.
12+
* [Bourbon](http://bourbon.io/) is a mixing library for sass which is much simpler and more lightweight than [compass](http://compass-style.org/) but also has the most stuff I need.
13+
* [React](http://facebook.github.io/react/index.html) is a library for building user interfaces that uses a virtual DOM diff implementation for higher performance.
14+
* [shoe](https://github.com/substack/shoe) is a library to use streams over [sockjs](https://github.com/sockjs/sockjs-node). I used it to replace ajax request. Just for fun ...
15+
16+
## Source code
17+
18+
You can find the source code on [github](https://github.com/aslansky/react-stack-playground).
19+
20+
## Learnings
21+
22+
* [gulp](http://gulpjs.com/) is great. The one thing that makes it more useful than grunt for me is the configuration that is done in pure javascript. No ~~obscure~~ complex configuration object like in grunt. To define a task you just need to create code like this:
23+
24+
```
25+
gulp.task('styles', function () {
26+
return gulp.src('./src/scss/main.scss')
27+
.pipe(sass({
28+
outputStyle: gulp.env.production ? 'compressed' : 'expanded',
29+
includePaths: ['./src/scss'].concat(bourbon),
30+
errLogToConsole: gulp.env.watch
31+
}))
32+
.pipe(gulp.dest('./dist/css'));
33+
});
34+
```
35+
Also because of the use of streams gulp seems to be much faster than grunt. The only upside I could see at the time is the lack of plugins. The grunt ecosystem of plugin is bigger and more mature.
36+
You can find more on grunt vs gulp [here](http://www.shaundunne.com/gulp-is-the-new-black/).
37+
38+
* [browserify](http://browserify.org/) is awesome. Together with npm you get a nice package management system that just works without much configuration. Also the use of module.exports and require in a node.js way for me looks cleaner than the amd syntax of [require.js](http://requirejs.org/). To get started you just need to have a package.json and a task in your gulpfile.js
39+
40+
```
41+
"dependencies": {
42+
"react": "~0.8.0",
43+
"showdown": "aslansky/showdown",
44+
"shoe": "0.0.15"
45+
}
46+
```
47+
```
48+
gulp.task('scripts', function() {
49+
return gulp.src('./src/js/app.js', {read: false})
50+
.pipe(browserify({
51+
insertGlobals : false,
52+
transform: ['reactify'],
53+
extensions: ['.jsx'],
54+
debug: !gulp.env.production
55+
}))
56+
.pipe(gulpif(gulp.env.production, uglify({
57+
mangle: {
58+
except: ['require', 'export', '$super']
59+
}
60+
})))
61+
.pipe(gulp.dest('./dist/js'));
62+
});
63+
```
64+
After that you can start using require in your javascript.
65+
66+
```
67+
var React = require('react');
68+
var CommentBox = require('./jsx/comment-box');
69+
```
70+
or write modules with module.exports
71+
72+
```
73+
/** @jsx React.DOM */
74+
'use strict';
75+
76+
var React = require('react/addons');
77+
var Comment = require('./comment');
78+
var ReactTransitionGroup = React.addons.TransitionGroup;
79+
80+
module.exports = React.createClass({
81+
render: function() {
82+
var commentNodes = this.props.data.map(function (comment, i) {
83+
return <Comment key={i} author={comment.author}>{comment.text}</Comment>;
84+
});
85+
return (
86+
<ReactTransitionGroup transitionName="comment">
87+
{commentNodes}
88+
</ReactTransitionGroup>
89+
);
90+
}
91+
});
92+
```
93+
94+
* with [node-sass](https://github.com/andrew/node-sass) and without the need for installing any ruby dependencies your project can stay in plain javascript. So no extra installations needed. Also node-sass seems to process scss files much faster then ruby sass. The downside of node-sass that not all mixins or mixin libries are compatible. Especially [compass](http://compass-style.org/) doesn't work with it.
95+
96+
* [Bourbon](http://bourbon.io/) is a neat little mixin library for sass that is compatible with node-sass. It has all the features I need. In my view the documentation is better than compass' and with [Bourbon Neat](http://neat.bourbon.io/) it also has a nice grid framework. Because Bourbon is plain scss there are no compatibility issues between versions like I had to experience with ruby sass and compass.
97+
98+
* I chose to just play with React's [Tutorial](http://facebook.github.io/react/docs/tutorial.html) implementation of a comment box. The use of components makes the code really readable and with JSX there is a easy to understand syntax for templating. You don't need to use JSX but it makes the source code of the components even more understandable. For example the comment form looks like this:
99+
100+
```
101+
/** @jsx React.DOM */
102+
'use strict';
103+
104+
var React = require('react');
105+
106+
module.exports = React.createClass({
107+
handleSubmit: function() {
108+
var author = this.refs.author.getDOMNode().value.trim();
109+
var text = this.refs.text.getDOMNode().value.trim();
110+
this.props.onCommentSubmit({author: author, text: text});
111+
this.refs.author.getDOMNode().value = '';
112+
this.refs.text.getDOMNode().value = '';
113+
return false;
114+
},
115+
render: function() {
116+
return (
117+
<div className="commentForm">
118+
<form className="commentForm" onSubmit={this.handleSubmit}>
119+
<input type="text" placeholder="Your name" ref="author" />
120+
<textarea placeholder="Say something..." ref="text"></textarea>
121+
<button type="submit">Post</button>
122+
</form>
123+
</div>
124+
);
125+
}
126+
});
127+
```
128+
129+
* Because I wanted to use Websockets instead of ajax with the react tutorial and all the new information I got about streams by using gulp, I decided to use [shoe](https://github.com/substack/shoe). The browser implementation is straight forward. Open a stream to the server an then wait for data to come. If you want to send data to the server, just write to the stream.
130+
131+
```
132+
var stream = shoe('/comments');
133+
this.stream.on('data', function (data) {
134+
this.setState({data: JSON.parse(data)});
135+
});
136+
this.stream.write(JSON.stringify(comment));
137+
```
138+
If you want to know more about the server side have a look [here](https://github.com/aslansky/react-stack-playground/blob/master/server/index.js). The [shoe documentation](https://github.com/substack/shoe) also has some nice examples.
139+
140+
## Conclusion
141+
142+
First of all, it is fun to play with new things. You should try it sometimes. Second, the experience was great. All the libraries and tools work nice together and I can imagine building a web application with this stack. The next thing I want to look into, is how to combine [director](https://github.com/flatiron/director) with React to have a router for a single page site.

server/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ module.exports = function(port, lrport) {
4444
sendFile(stream);
4545
});
4646

47-
sock.install(app.listen(port), '/comments');
47+
sock.install(app.listen(port), '/api');
4848
gutil.log('Listening on', port + ' / ' + lrport);
4949

5050
return {

src/js/app.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
11
'use strict';
22

33
var React = require('react');
4+
var director = require('director');
45
var CommentBox = require('./jsx/comment-box');
6+
var router = director.Router().init();
7+
var shoe = require('shoe');
8+
var stream = shoe('/api');
59

6-
React.renderComponent(
10+
var app = React.renderComponent(
711
CommentBox({
8-
url: 'comments.json',
9-
pollInterval: 2000
12+
stream: stream,
13+
page: router.getRoute(0)
1014
}),
1115
document.getElementById('content')
1216
);
17+
18+
stream.on('data', function (data) {
19+
app.setState({data: JSON.parse(data)});
20+
});
21+
22+
router.on('/:state', function (page) {
23+
app.setState({page: page});
24+
});

src/js/jsx/comment-box.jsx

+8-13
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,25 @@
44
var React = require('react');
55
var CommentList = require('./comment-list');
66
var CommentForm = require('./comment-form');
7-
var shoe = require('shoe');
7+
var ReactTransitionGroup = React.addons.TransitionGroup;
88

99
module.exports = React.createClass({
10-
loadCommentsFromServer: function() {
11-
this.stream.on('data', function (data) {
12-
this.setState({data: JSON.parse(data)});
13-
}.bind(this));
14-
},
1510
handleCommentSubmit: function(comment) {
16-
this.stream.write(JSON.stringify(comment));
11+
this.props.stream.write(JSON.stringify(comment));
1712
},
1813
getInitialState: function() {
19-
return {data: []};
20-
},
21-
componentWillMount: function() {
22-
this.stream = shoe('/comments');
23-
this.loadCommentsFromServer();
14+
return {
15+
page: this.props.page,
16+
data: []
17+
};
2418
},
2519
render: function() {
2620
return (
2721
<div className="commentBox">
2822
<h1>Comments</h1>
2923
<CommentList data={this.state.data} />
30-
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
24+
{this.state.page !== 'write' ? <a className="button" href="#/write">Write comment</a> : ''}
25+
{this.state.page === 'write' ? <CommentForm onCommentSubmit={this.handleCommentSubmit} /> : ''}
3126
</div>
3227
);
3328
}

src/js/jsx/comment-form.js

+5-7
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@ module.exports = React.createClass({
1414
},
1515
render: function() {
1616
return (
17-
<div className="commentForm">
18-
<form className="commentForm" onSubmit={this.handleSubmit}>
19-
<input type="text" placeholder="Your name" ref="author" />
20-
<textarea placeholder="Say something..." ref="text"></textarea>
21-
<button type="submit">Post</button>
22-
</form>
23-
</div>
17+
<form className="commentForm" onSubmit={this.handleSubmit}>
18+
<input type="text" placeholder="Your name" ref="author" />
19+
<textarea placeholder="Say something..." ref="text"></textarea>
20+
<button type="submit">Post</button>
21+
</form>
2422
);
2523
}
2624
});

src/js/jsx/comment.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ module.exports = React.createClass({
99
render: function() {
1010
return (
1111
<div key={this.props.key} className="comment">
12-
<h2 className="commentAuthor">
13-
{this.props.author}
14-
</h2>
12+
<h2 className="commentAuthor">{this.props.author}</h2>
1513
<span dangerouslySetInnerHTML={{__html: converter.makeHtml(this.props.children.toString())}} />
1614
</div>
1715
);

src/scss/main.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ textarea {
3434
height: 100px;
3535
}
3636

37-
button {
37+
a.button, button {
3838
@include button;
3939
}
4040

0 commit comments

Comments
 (0)