├── .gitignore
├── README.md
├── assets
└── style.css
├── client.js
├── package.json
└── server.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | assets/bundle.js
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-quickstart
2 |
3 | A minimal React project template which combines:
4 |
5 | * [react-router-component][] to provide HTML5 History routing and navigation
6 |
7 | * [react-async][] to create "asynchronous" React components
8 |
9 | * [express][] to serve pre-rendered React components, assets and provide API
10 |
11 | * [browserify][] to provide module system for a browser
12 |
13 | * [npm][] to install and manage server-side and client-side dependencies
14 |
15 | Every "page" in the application is **pre-rendered on server** so the user can
16 | see the UI before the client code is shipped to a browser. After that
17 | application starts functioning like a **single page application**, navigating
18 | between "pages" without reloads.
19 |
20 | ## Project structure
21 |
22 | Project structure is really minimal, you'd probably like to customize it for
23 | your specific needs and taste:
24 |
25 | .
26 | ├── assets
27 | ├── client.js
28 | ├── package.json
29 | └── server.js
30 |
31 | Directory `assets` is served under `/assets` URL, `client.js` module contains UI
32 | code while `server.js` — HTTP server which serves pre-rendered React components,
33 | assets and provide a stub for a REST API.
34 |
35 | ## Development workflow
36 |
37 | After cloning a git repo, run:
38 |
39 | % npm install
40 |
41 | to install all needed dependencies and then:
42 |
43 | % npm run start
44 |
45 | to start a development server.
46 |
47 | Now you can start edit the source code — on changes, server will be reloaded and
48 | client code bundle will be rebuilt.
49 |
50 | ## Going "production"
51 |
52 | To build an optimized bundle of client code run:
53 |
54 | % npm run build
55 |
56 | which will produce `assets/bundle.js` build, then:
57 |
58 | % npm run start-prod
59 |
60 | to start server in "production" mode (no source code watching and serving
61 | optimized bundle to browser).
62 |
63 | [react-router-component]: http://andreypopp.viewdocs.io/react-router-component
64 | [react-async]: http://andreypopp.viewdocs.io/react-async
65 | [express]: expressjs.com
66 | [npm]: https://www.npmjs.org/
67 | [browserify]: http://browserify.org/
68 |
--------------------------------------------------------------------------------
/assets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: Helvetica, sans-serif;
5 | background: #fefefe;
6 | color: #444444;
7 | }
8 |
9 | .App {
10 | padding: 25px;
11 | }
12 |
--------------------------------------------------------------------------------
/client.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @jsx React.DOM
3 | */
4 | 'use strict';
5 |
6 |
7 | var React = require('react');
8 | var ReactAsync = require('react-async');
9 | var ReactRouter = require('react-router-component');
10 | var superagent = require('superagent');
11 |
12 | var Pages = ReactRouter.Pages;
13 | var Page = ReactRouter.Page;
14 | var NotFound = ReactRouter.NotFound;
15 | var Link = ReactRouter.Link;
16 |
17 | var MainPage = React.createClass({
18 |
19 | render: function() {
20 | return (
21 |
22 |
Hello, anonymous!
23 |
Login
24 |
25 | );
26 | }
27 | });
28 |
29 | var UserPage = React.createClass({
30 | mixins: [ReactAsync.Mixin],
31 |
32 | statics: {
33 | getUserInfo: function(username, cb) {
34 | /*
35 | * The use of localhost URLs work as long as the browser is running on the same machine as the server,
36 | * a typical development setup.
37 | * As soon as you want to run this code on public facing machines, each server will need to know it's
38 | * own hostname and port (which is ugly).
39 | * Relative paths cannot work for serverside rendering, as that has no page context.
40 | * More discussion of this issue, and solutions, can be found at:
41 | * https://github.com/andreypopp/react-async/issues/34
42 | * http://stackoverflow.com/questions/26463924/getting-rid-of-localhost3000-urls-for-reactasync
43 | */
44 | superagent.get(
45 | 'http://localhost:3000/api/users/' + username,
46 | function(err, res) {
47 | cb(err, res ? res.body : null);
48 | });
49 | }
50 | },
51 |
52 | getInitialStateAsync: function(cb) {
53 | this.type.getUserInfo(this.props.username, cb);
54 | },
55 |
56 | componentWillReceiveProps: function(nextProps) {
57 | if (this.props.username !== nextProps.username) {
58 | this.type.getUserInfo(nextProps.username, function(err, info) {
59 | if (err) {
60 | throw err;
61 | }
62 | this.setState(info);
63 | }.bind(this));
64 | }
65 | },
66 |
67 | render: function() {
68 | var otherUser = this.props.username === 'doe' ? 'ivan' : 'doe';
69 | return (
70 |