├── .babelrc
├── .gitignore
├── .npmignore
├── .travis.yml
├── README.md
├── app.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── server
├── app.js
├── index.js
└── loader.js
└── src
├── App.css
├── App.js
├── components
├── About
│ └── About.js
├── Contacts
│ └── Contacts.js
├── Container
│ └── Container.js
├── Home
│ └── Home.js
├── NavBar
│ ├── NavBar.css
│ └── NavBar.js
├── NotFound
│ ├── NotFound.css
│ └── NotFound.js
└── index.js
├── index.css
├── index.js
└── logo.svg
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "env",
5 | "react-app"
6 | ],
7 | "plugins": [
8 | [
9 | "babel-plugin-transform-require-ignore",
10 | {
11 | "extensions": [".css"]
12 | }
13 | ]
14 | ]
15 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 | package-lock.json
19 | yarn.lock
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 |
4 | # testing
5 | /coverage
6 |
7 | # production
8 | /build
9 |
10 | # misc
11 | .DS_Store
12 | .env.local
13 | .env.development.local
14 | .env.test.local
15 | .env.production.local
16 | package-lock.json
17 | yarn.lock
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | .git*
24 | .idea
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - 6
5 |
6 | script:
7 | - npm run build
8 |
9 | cache:
10 | directories:
11 | - node_modules
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React.js Sample Project
2 |
3 | [](https://david-dm.org/edoko/react-js-sample) [](https://david-dm.org/edoko/react-js-sample?type=dev) [](https://badge.fury.io/js/react-js-sample) [](https://travis-ci.org/edoko/react-js-sample)
4 |
5 | [](https://heroku.com/deploy?template=https://github.com/edoko/react-js/sample)
6 |
7 |
8 | [Live Demo](http://react-js-sample.herokuapp.com/)
9 |
10 | This app is built using React.js Boilerplate project.
11 | * React.js (create-react-app)
12 | * React Router v4
13 | * Server: Node.js (Express)
14 | * Support 404 Not found page
15 | * Support Server-side rendering
16 |
17 | ### Installation
18 |
19 | Clone repository:
20 | ```sh
21 | git clone git@github.com:edoko/react-js-sample.git
22 | ```
23 | Before running:
24 | ```sh
25 | npm install
26 | ```
27 |
28 |
29 | ## Run
30 |
31 | ### Local test
32 |
33 | ```sh
34 | npm start
35 | ```
36 |
37 | ### Local+Server test
38 |
39 | ```sh
40 | npm run test
41 | ```
42 |
43 | ### Server only test
44 |
45 | ```sh
46 | npm run server
47 | ```
48 |
49 | ### Production build
50 |
51 | ```sh
52 | npm run build
53 | ```
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "React.js Sample",
3 | "description": "React.js + React Router v4 + Express.js Sample Project",
4 | "repository": "https://github.com/edoko/react-js-sample",
5 | "logo": "http://react-js-sample.herokuapp.com/favicon.ico",
6 | "keywords": ["react", "reactjs", "reactrouter", "expressjs", "express", "boilerplate"]
7 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-js-sample",
3 | "version": "1.0.7",
4 | "description": "React.js + React Router v4 + Express.js(Server-side rendering) Boilerplate Project",
5 | "author": {
6 | "name": "Seongmin Park",
7 | "email": "me@komalab.io",
8 | "url": "http://komalab.io/"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git://github.com/edoko/react-js-sample.git"
13 | },
14 | "bugs": {
15 | "url": "http://github.com/edoko/react-js-sample/issues"
16 | },
17 | "licenses": [
18 | {
19 | "type": "MIT",
20 | "url": "http://www.opensource.org/licenses/MIT"
21 | }
22 | ],
23 | "keywords": [
24 | "react",
25 | "reactjs",
26 | "reactrouter",
27 | "expressjs",
28 | "boilerplate",
29 | "reactsample"
30 | ],
31 | "dependencies": {
32 | "compression": "^1.7.0",
33 | "express": "^4.15.4",
34 | "morgan": "^1.8.2",
35 | "react": "^15.6.1",
36 | "react-dom": "^15.6.1",
37 | "react-router-dom": "^4.1.2",
38 | "react-scripts": "1.1.5"
39 | },
40 | "scripts": {
41 | "start-win": "set NODE_ENV=production&babel-node server",
42 | "start-other": "export BABEL_ENV=production&&babel-node server",
43 | "build": "react-scripts build",
44 | "test": "react-scripts build && babel-node server",
45 | "server": "babel-node server",
46 | "eject": "react-scripts eject"
47 | },
48 | "devDependencies": {
49 | "babel-cli": "^6.24.1",
50 | "babel-core": "^6.26.0",
51 | "babel-plugin-transform-require-ignore": "^0.1.1",
52 | "babel-preset-env": "^1.6.0",
53 | "babel-preset-es2015": "^6.24.1",
54 | "babel-preset-react-app": "^3.0.2",
55 | "babel-preset-stage-0": "^6.24.1"
56 | }
57 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edoko/react-js-sample/db53362c2ef5c55df2b5aa6efe0304456ff0c86d/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | React.js + React Router v4 + Express.js Sample App
9 |
10 |
11 |
14 | {{SSR}}
15 |
16 |
17 |
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | // Express.js server file (app)
2 |
3 | import express from 'express';
4 | import morgan from 'morgan';
5 | import path from 'path';
6 | import compression from 'compression';
7 | import loader from './loader';
8 |
9 | const app = express();
10 |
11 | // Support compress gzip format
12 | app.use(compression());
13 |
14 | // request logger with morgan
15 | app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer"'));
16 |
17 | // server static file
18 | app.use(express.static(path.resolve(__dirname, '../build')));
19 |
20 | app.use('/', loader);
21 |
22 | // export module
23 | export default app;
--------------------------------------------------------------------------------
/server/index.js:
--------------------------------------------------------------------------------
1 | // Express.js server file (index)
2 |
3 | import app from './app';
4 |
5 | // listen port 3000
6 | const PORT = process.env.PORT || 3000;
7 |
8 | app.listen(PORT, () => {
9 | console.log(`Listening on ${PORT}\nLaunch your browser!`);
10 | });
11 |
--------------------------------------------------------------------------------
/server/loader.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import path from 'path';
3 | import fs from 'fs';
4 | import { renderToString } from 'react-dom/server';
5 | import { StaticRouter } from 'react-router-dom';
6 | import App from '../src/components/Container/Container';
7 |
8 | export default (req, res) => {
9 | const filePath = path.resolve(__dirname, '../build', 'index.html');
10 |
11 | fs.readFile(filePath, 'utf8', (err, htmlData)=>{
12 | if (err) {
13 | console.error('Read Error!', err);
14 | return res.status(404).end();
15 | }
16 |
17 | const context = {};
18 | const markup = renderToString(
19 |
20 |
21 |
22 | );
23 |
24 | if (context.url) {
25 | redirect(301, context.url);
26 | } else {
27 | // 리로드해도 정상적으로 렌더링
28 | const render = htmlData.replace('{{SSR}}', markup);
29 | res.send(render);
30 | }
31 |
32 | });
33 | };
--------------------------------------------------------------------------------
/src/App.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/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Container, NavBar } from './components';
3 | import logo from './logo.svg';
4 | import './App.css';
5 |
6 | class App extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |

12 |
Welcome to React
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | export default App;
24 |
--------------------------------------------------------------------------------
/src/components/About/About.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class About extends Component {
4 | render() {
5 | return (
6 |
7 |
This is About page.
8 | Hi~~~
9 |
10 | );
11 | }
12 | }
13 |
14 | export default About;
--------------------------------------------------------------------------------
/src/components/Contacts/Contacts.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Contacts extends Component {
4 | render() {
5 | return (
6 |
7 |
This is Contacts page.
8 |
9 |
10 | );
11 | }
12 | }
13 |
14 | export default Contacts;
--------------------------------------------------------------------------------
/src/components/Container/Container.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Route, Switch } from 'react-router-dom'
3 |
4 | import { Home, About, Contacts, NotFound } from '../';
5 |
6 | class Container extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default Container;
--------------------------------------------------------------------------------
/src/components/Home/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Home extends Component {
4 | render() {
5 | return (
6 |
7 |
This is Home page.
8 | built using React.js + React Router v4 + Express.js
9 | Now, It is Server-side rendering !
10 |
11 | );
12 | }
13 | }
14 |
15 | export default Home;
--------------------------------------------------------------------------------
/src/components/NavBar/NavBar.css:
--------------------------------------------------------------------------------
1 | .NavList {
2 | text-align: center;
3 | margin-top: 5rem;
4 | }
5 |
6 | .NavList li {
7 | display: inline-block;
8 | padding: 0 5rem;
9 | font-weight: bold;
10 | font-size: 2rem;
11 | }
--------------------------------------------------------------------------------
/src/components/NavBar/NavBar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import './NavBar.css';
4 |
5 | class NavBar extends Component {
6 | render() {
7 | return (
8 |
9 | -
10 | HOME
11 |
12 | -
13 | ABOUT
14 |
15 | -
16 | CONTACTS
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | export default NavBar;
--------------------------------------------------------------------------------
/src/components/NotFound/NotFound.css:
--------------------------------------------------------------------------------
1 | .NotFound h1, h2 {
2 | text-align: center;
3 | }
--------------------------------------------------------------------------------
/src/components/NotFound/NotFound.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './NotFound.css';
3 |
4 | class NotFound extends Component {
5 |
6 | render() {
7 | return (
8 |
9 |
404: NOT FOUND
10 | You referred to the wrong address.
11 |
12 | );
13 | }
14 | }
15 |
16 | export default NotFound;
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import NavBar from './NavBar/NavBar';
2 | import Container from './Container/Container';
3 | import About from './About/About';
4 | import Contacts from './Contacts/Contacts';
5 | import Home from './Home/Home';
6 | import NotFound from './NotFound/NotFound';
7 |
8 | export {
9 | NavBar,
10 | Container,
11 | About,
12 | Contacts,
13 | Home,
14 | NotFound
15 | };
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {BrowserRouter} from 'react-router-dom'
4 | import './index.css';
5 | import App from './App';
6 |
7 | const clientRender = () => {
8 | ReactDOM.render(
9 | , document.getElementById('root'));
10 | };
11 |
12 | const serverRender = () => {};
13 |
14 | if (typeof window === 'object') {
15 | clientRender();
16 | } else {
17 | serverRender();
18 | };
19 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------