├── .env
├── shared
├── components
│ ├── Root.js
│ ├── Main.js
│ ├── About.js
│ ├── NotFound.js
│ ├── HTML.js
│ ├── TopNav.js
│ └── Home.js
├── App.js
└── routes.js
├── .babelrc
├── server
├── run.js
├── server.js
└── api
│ └── api1.js
├── client
└── main.js
├── .gitignore
├── webpack.config.js
├── iso-middleware
└── renderRoute.js
├── .eslintrc
├── package.json
└── README.md
/.env:
--------------------------------------------------------------------------------
1 | PORT='3000'
2 | NODE_ENV='development'
3 |
--------------------------------------------------------------------------------
/shared/components/Root.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Main from './Main';
3 |
4 | const Root = ({ route }) => (
5 |
6 | )
7 |
8 | export default Root;
9 |
--------------------------------------------------------------------------------
/shared/components/Main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { renderRoutes } from 'react-router-config';
3 |
4 | const Main = ({ routes }) => (
5 |
6 | {renderRoutes(routes)}
7 |
8 | );
9 |
10 | export default Main;
11 |
--------------------------------------------------------------------------------
/shared/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { renderRoutes } from 'react-router-config';
3 | import routes from './routes';
4 |
5 | const App = () => (
6 |
7 | {renderRoutes(routes)}
8 |
9 | );
10 |
11 | export default App;
12 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "env",
4 | "stage-2",
5 | "react"
6 | ],
7 | "plugins": [
8 | "transform-runtime",
9 | "transform-es2015-destructuring",
10 | "transform-es2015-parameters",
11 | "transform-object-rest-spread"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/shared/components/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TopNav from './TopNav';
3 |
4 | export default ({ route }) => (
5 |
6 |
7 |
8 |
About Page
9 |
10 |
11 | );
12 |
--------------------------------------------------------------------------------
/server/run.js:
--------------------------------------------------------------------------------
1 | // Include Babel
2 | // it will parse all code that comes after it.
3 | // (Not recommended for production use).
4 |
5 | process.env.NODE_ENV = 'development';
6 | require('babel-register')({
7 | ignore: /\/(build|node_modules)\//,
8 | presets: ['env', 'react-app']
9 | });
10 |
11 | require('./server.js');
12 |
--------------------------------------------------------------------------------
/client/main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { BrowserRouter } from 'react-router-dom';
4 | import App from '../shared/App';
5 |
6 | const renderRouter = Component => {
7 | ReactDOM.hydrate(
8 |
9 |
10 | , document.getElementById('root')
11 | );
12 | };
13 |
14 | renderRouter(App);
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 | *.swp
10 |
11 | pids
12 | logs
13 | results
14 | tmp
15 | coverage
16 |
17 | # Dependency directory
18 | node_modules
19 | bower_components
20 | package-lock.json
21 |
22 | # Editors
23 | .idea
24 | *.iml
25 |
26 | # Builds
27 | build
28 | browser.js
29 |
30 | # OS metadata
31 | .DS_Store
32 | Thumbs.db
33 |
--------------------------------------------------------------------------------
/shared/components/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import TopNav from './TopNav';
3 |
4 | const style = {
5 | padding: '16px'
6 | };
7 |
8 | export default ({ route }) => (
9 |
10 |
11 |
12 |
13 |
Sorry!
14 |
Something went horribly wrong…
15 |
16 |
17 |
18 | );
19 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'development';
2 | const path = require('path');
3 |
4 | module.exports = {
5 | entry: {
6 | main: './client/main.js'
7 | },
8 | output: {
9 | path: path.resolve(__dirname, 'build'),
10 | filename: '[name].bundle.js',
11 | },
12 | devtool: 'inline-source-map',
13 | module: {
14 | rules: [
15 | {
16 | test: /\.(js|jsx)$/,
17 | exclude: /node_modules/,
18 | loader: 'babel-loader',
19 | }
20 | ],
21 | },
22 | resolve: {
23 | extensions: ['.js', '.jsx', '.css', '.es6'],
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/shared/routes.js:
--------------------------------------------------------------------------------
1 | import Home from './components/Home';
2 | import About from './components/About';
3 | import NotFound from './components/NotFound';
4 | import Root from './components/Root';
5 |
6 | const routes = [
7 | {
8 | component: Root,
9 | routes: [
10 | {
11 | path: '/',
12 | exact: true,
13 | component: Home
14 | },
15 | {
16 | path: '/about',
17 | component: About
18 | },
19 | {
20 | path: '*',
21 | restricted: false,
22 | component: NotFound
23 | }
24 | ]
25 | }
26 | ];
27 |
28 | export default routes;
29 |
--------------------------------------------------------------------------------
/shared/components/HTML.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const HTML = (props) => (
4 |
5 |
6 | Isomorphic Router Demo
7 |
11 |
12 |
13 |
17 |
23 |
24 |
25 |
26 | );
27 |
28 | export default HTML;
29 |
--------------------------------------------------------------------------------
/shared/components/TopNav.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | export default class TopNav extends React.Component {
5 | render() {
6 | console.log('props.route.path = '+ this.props.route.path)
7 | let selected = '';
8 | if(typeof this.props.route.path === 'string') {
9 | selected = this.props.route.path.split('/').pop();
10 | }
11 | return (
12 |
28 |
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | // Set up ======================================================================
2 | // get all the tools we need
3 | import express from 'express';
4 | import http from 'http';
5 | import logger from 'morgan';
6 | import path from 'path';
7 | import apiVersion1 from './api/api1';
8 | import renderRouterMiddleware from '../iso-middleware/renderRoute';
9 |
10 | require('dotenv').config();
11 |
12 | // Configuration ===============================================================
13 | const app = express();
14 | app.set('port', process.env.PORT || 8080);
15 | app.use(logger('short'));
16 |
17 | // Request Handlers
18 | const buildPath = path.join(__dirname, '../', 'build');
19 |
20 | app.use('/', express.static(buildPath));
21 | app.use('/api', apiVersion1);
22 |
23 | app.get('*', renderRouterMiddleware);
24 |
25 | // launch ======================================================================
26 | // Starts the Express server on port 3001 and logs that it has started
27 | http.createServer(app).listen(app.get('port'), () => {
28 | console.log(`Express server started at: http://localhost:${app.get('port')}/`); // eslint-disable-line no-console
29 | });
30 |
31 | module.exports = app;
32 |
--------------------------------------------------------------------------------
/iso-middleware/renderRoute.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import chalk from 'chalk';
3 | import { renderToString } from 'react-dom/server';
4 | import { StaticRouter } from 'react-router-dom';
5 | import { matchRoutes } from 'react-router-config';
6 | import routes from '../shared/routes';
7 | import HTML from '../shared/components/HTML';
8 | import App from '../shared/App';
9 |
10 | export default function renderRoute(req, res) {
11 | const branch = matchRoutes(routes, req.url);
12 | const promises = [];
13 |
14 | branch.forEach(({ route, match }) => {
15 | if (route.loadData) {
16 | promises.push(route.loadData(match));
17 | }
18 | });
19 |
20 | Promise.all(promises).then(data => {
21 | // data will be an array[] of datas returned by each promises.
22 | // // console.log(data)
23 |
24 | const context = data.reduce((context, data) => Object.assign(context, data), {});
25 |
26 | const router = ;
27 |
28 | const app = renderToString(router);
29 |
30 | const html = renderToString(