├── .gitignore
├── Dockerfile
├── README.md
├── favicon.ico
├── index.html
├── package.json
├── server
├── app.js
└── index.js
├── src
├── components
│ ├── About
│ │ ├── index.js
│ │ └── style.css
│ ├── App
│ │ ├── index.js
│ │ ├── logo.svg
│ │ └── style.css
│ └── NotFound
│ │ ├── index.js
│ │ └── style.css
├── index.css
├── index.js
└── routes.js
└── test
└── server.test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # production
7 | build
8 |
9 | # misc
10 | .DS_Store
11 | npm-debug.log
12 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Dockerfile
2 | FROM node:6
3 |
4 | # Create app directory
5 | RUN mkdir -p /usr/src/app
6 | WORKDIR /usr/src/app
7 |
8 | # Install app dependencies
9 | COPY package.json /usr/src/app/
10 | RUN npm install
11 |
12 | # Bundle app source
13 | COPY . /usr/src/app
14 |
15 | # Build and optimize react app
16 | RUN npm run build
17 |
18 | EXPOSE 9000
19 |
20 | # defined in package.json
21 | CMD [ "npm", "run", "start:server" ]
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Using `create-react-app` with React Router + Express.js
2 |
3 | **:warning: This is outdated, please refer to the official and new [react-router docs](https://reacttraining.com/react-router/)**
4 |
5 | See : https://medium.com/@patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d
6 |
7 | ## Development
8 |
9 | Clone this repository:
10 |
11 | ```sh
12 | git clone https://github.com/mrpatiwi/routed-react.git
13 | cd routed-react
14 | ```
15 |
16 | Install dependencies:
17 |
18 | ```sh
19 | npm install
20 | ```
21 |
22 | Start the project at [`http://localhost:3000`](http://localhost:3000).
23 |
24 | ```sh
25 | npm start
26 | ```
27 |
28 | ## Running with Docker
29 |
30 | Be sure to install Docker and start a Docker-machine if necessary.
31 |
32 | Let's create an image named `routed-react`:
33 |
34 | ```sh
35 | docker build -t routed-react .
36 | ```
37 |
38 | Finally, start a container named `routed-react-instance` at port `80`.
39 |
40 | ```sh
41 | docker run -p 80:9000 --name routed-react-instance routed-react
42 | ```
43 |
44 | ## Testing
45 |
46 | ```sh
47 | npm test
48 | ```
49 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lopezjurip/routed-react/ab1b41dfd88df44221d9532fd73e1b61e815f48f/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | React App
7 |
8 |
9 |
10 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "routed-react",
3 | "version": "0.0.1",
4 | "private": true,
5 | "devDependencies": {
6 | "chai": "^3.5.0",
7 | "mocha": "^3.0.2",
8 | "mz": "^2.4.0",
9 | "react-scripts": "0.2.1",
10 | "supertest-as-promised": "^4.0.0"
11 | },
12 | "dependencies": {
13 | "classnames": "^2.2.5",
14 | "express": "^4.14.0",
15 | "morgan": "^1.7.0",
16 | "react": "^15.2.1",
17 | "react-dom": "^15.2.1",
18 | "react-router": "^2.6.1"
19 | },
20 | "scripts": {
21 | "start": "react-scripts start",
22 | "start:server": "node server",
23 | "build": "react-scripts build",
24 | "eject": "react-scripts eject",
25 | "test": "mocha test"
26 | },
27 | "eslintConfig": {
28 | "extends": "./node_modules/react-scripts/config/eslint.js",
29 | "env": {
30 | "mocha": true
31 | },
32 | "rules": {
33 | "strict": 0
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | // server/app.js
2 | const express = require('express');
3 | const morgan = require('morgan');
4 | const path = require('path');
5 |
6 | const app = express();
7 |
8 | // Setup logger
9 | app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));
10 |
11 | // Serve static assets
12 | app.use(express.static(path.resolve(__dirname, '..', 'build')));
13 |
14 | // Always return the main index.html, so react-router render the route in the client
15 | app.get('*', (req, res) => {
16 | res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
17 | });
18 |
19 | module.exports = app;
20 |
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | // server/index.js
2 | 'use strict';
3 |
4 | const app = require('./app');
5 |
6 | const PORT = process.env.PORT || 9000;
7 |
8 | app.listen(PORT, () => {
9 | console.log(`App listening on port ${PORT}!`);
10 | });
11 |
--------------------------------------------------------------------------------
/src/components/About/index.js:
--------------------------------------------------------------------------------
1 | // src/components/About/index.js
2 | import React, { Component } from 'react';
3 | import classnames from 'classnames';
4 |
5 | import './style.css';
6 |
7 | class About extends Component {
8 | static propTypes = {}
9 | static defaultProps = {}
10 | state = {}
11 |
12 | render() {
13 | const { className, ...props } = this.props;
14 | return (
15 |
16 |
17 | About
18 |
19 |
20 | );
21 | }
22 | }
23 |
24 | export default About;
25 |
--------------------------------------------------------------------------------
/src/components/About/style.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lopezjurip/routed-react/ab1b41dfd88df44221d9532fd73e1b61e815f48f/src/components/About/style.css
--------------------------------------------------------------------------------
/src/components/App/index.js:
--------------------------------------------------------------------------------
1 | // src/components/App/index.js
2 | import React, { Component } from 'react';
3 | import classnames from 'classnames';
4 |
5 | import logo from './logo.svg';
6 | import './style.css';
7 |
8 | class App extends Component {
9 | static propTypes = {}
10 | static defaultProps = {}
11 | state = {}
12 |
13 | render() {
14 | const { className, ...props } = this.props;
15 | return (
16 |
17 |
18 |

19 |
Welcome to React
20 |
21 |
22 | To get started, edit src/App.js
and save to reload.
23 |
24 |
25 | );
26 | }
27 | }
28 |
29 | export default App;
30 |
--------------------------------------------------------------------------------
/src/components/App/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/components/App/style.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-intro {
18 | font-size: large;
19 | }
20 |
21 | @keyframes App-logo-spin {
22 | from { transform: rotate(0deg); }
23 | to { transform: rotate(360deg); }
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/NotFound/index.js:
--------------------------------------------------------------------------------
1 | // src/components/NotFound/index.js
2 | import React, { Component } from 'react';
3 | import classnames from 'classnames';
4 |
5 | import './style.css';
6 |
7 | export default class NotFound extends Component {
8 | static propTypes = {}
9 | static defaultProps = {}
10 | state = {}
11 |
12 | render() {
13 | const { className, ...props } = this.props;
14 | return (
15 |
16 |
17 | 404 Not Found :(
18 |
19 |
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/NotFound/style.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lopezjurip/routed-react/ab1b41dfd88df44221d9532fd73e1b61e815f48f/src/components/NotFound/style.css
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | // index.js
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import { browserHistory } from 'react-router'
5 |
6 | import Routes from './routes';
7 |
8 | import './index.css';
9 |
10 | ReactDOM.render(
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/src/routes.js:
--------------------------------------------------------------------------------
1 | // src/routes.js
2 | import React from 'react';
3 | import { Router, Route } from 'react-router'
4 |
5 | import App from './components/App';
6 | import About from './components/About';
7 | import NotFound from './components/NotFound';
8 |
9 | const Routes = (props) => (
10 |
11 |
12 |
13 |
14 |
15 | );
16 |
17 | export default Routes;
18 |
--------------------------------------------------------------------------------
/test/server.test.js:
--------------------------------------------------------------------------------
1 | // test/server.test.js
2 | const exec = require('mz/child_process').exec;
3 | const request = require('supertest-as-promised');
4 | const expect = require('chai').expect;
5 |
6 | const app = require('../server/app');
7 |
8 | describe('builds application', function () {
9 | it('builds to "build" directory', function () {
10 | // Disable mocha time-out because this takes a lot of time
11 | this.timeout(0);
12 |
13 | // Run process
14 | return exec('npm run build');
15 | });
16 | });
17 |
18 | describe('express serving', function () {
19 | it('responds to / with the index.html', function () {
20 | return request(app)
21 | .get('/')
22 | .expect('Content-Type', /html/)
23 | .expect(200)
24 | .then(res => expect(res.text).to.contain(''));
25 | });
26 |
27 | it('responds to favicon.icon request', function () {
28 | return request(app)
29 | .get('/favicon.ico')
30 | .expect('Content-Type', 'image/x-icon')
31 | .expect(200);
32 | });
33 |
34 | it('responds to any route with the index.html', function () {
35 | return request(app)
36 | .get('/foo/bar')
37 | .expect('Content-Type', /html/)
38 | .expect(200)
39 | .then(res => expect(res.text).to.contain(''));
40 | });
41 | });
42 |
--------------------------------------------------------------------------------