├── .gitignore ├── readme.md ├── client └── src │ ├── views │ └── example.js │ ├── index.js │ └── root-container.js ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Isomorphic Example 2 | 3 | Example application for some isomorphic shenanigans. 4 | 5 | ## Usage 6 | ``` 7 | npm install 8 | npm run build && npm start 9 | ``` 10 | -------------------------------------------------------------------------------- /client/src/views/example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple "example" of a stateless React component. 3 | * 4 | * @author tahartik 5 | */ 6 | 7 | const React = require('react') 8 | const Redux = require('react-redux') 9 | 10 | const ExampleView = props => 11 |
12 |
{JSON.stringify(props)}
13 |
14 | 15 | module.exports = Redux.connect(state => state)(ExampleView) 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "isomorphic-example", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "build": "sh build.sh", 7 | "start": "babel-node server.js" 8 | }, 9 | "babel": { 10 | "presets": [ 11 | "react", 12 | "es2015" 13 | ] 14 | }, 15 | "dependencies": { 16 | "babel-cli": "^6.8.0", 17 | "babel-preset-es2015": "^6.6.0", 18 | "babel-preset-react": "^6.5.0", 19 | "express": "^4.13.4", 20 | "react": "^15.0.2", 21 | "react-dom": "^15.0.2", 22 | "react-redux": "^4.4.5", 23 | "react-router": "^2.4.0", 24 | "react-router-redux": "^4.0.4", 25 | "redux": "^3.5.2" 26 | }, 27 | "devDependencies": { 28 | "babelify": "^7.3.0", 29 | "browserify": "^13.0.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Entrypoint for the client side application. 3 | * 4 | * @author tahartik 5 | */ 6 | 7 | const React = require('react') 8 | const ReactDOM = require('react-dom') 9 | 10 | 11 | console.log('Checking for initial state...') 12 | 13 | let initialState = { } 14 | if(!!document.getElementById('initial-data')) { 15 | console.log('Document contains initial state...') 16 | try { 17 | initialState = 18 | JSON.parse(document.getElementById('initial-data').innerHTML) 19 | } 20 | catch(err) { 21 | console.error('Failed to parse initial state...') 22 | } 23 | } 24 | 25 | // we know we're on the client now... :-) 26 | initialState = Object.assign({}, initialState, { isClient: true }) 27 | 28 | ReactDOM.render( 29 | require('./root-container')(initialState), document.getElementById('app')) 30 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Example server showing server-rendered React application. 3 | * 4 | * @author tahartik 5 | */ 6 | 7 | const path = require('path') 8 | const express = require('express') 9 | 10 | const template = (app = '', data = '') => ` 11 | 12 | 13 | 16 | 17 | 18 |
${app}
19 | 20 | 21 | 22 | ` 23 | 24 | express() 25 | 26 | .get('/', (req, res) => { 27 | const initialState = { 28 | isClient: false 29 | } 30 | res.send(template(null, JSON.stringify(initialState))) 31 | }) 32 | 33 | .get('/app.js', (req, res) => { 34 | res.sendFile(path.join(__dirname, 'client/dist/app.js')) 35 | }) 36 | 37 | .listen(3000) 38 | -------------------------------------------------------------------------------- /client/src/root-container.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Example React + Redux application in a single file. 3 | * 4 | * @author tahartik 5 | */ 6 | 7 | const React = require('react') 8 | const Redux = require('redux') 9 | const Route = require('react-router').Route 10 | const Router = require('react-router').Router 11 | const Provider = require('react-redux').Provider 12 | const ReduxRouter = require('react-router-redux') 13 | 14 | // simple reducer to keep track of whether this application was initialized in 15 | // the server or on the browser 16 | const isomorphicReducer = (isClient = false) => isClient 17 | 18 | module.exports = initialState => { 19 | console.log('Rendering with ::', JSON.stringify(initialState)) 20 | const store = Redux.createStore( 21 | Redux.combineReducers({ 22 | routing: ReduxRouter.routerReducer, 23 | isClient: isomorphicReducer, 24 | }), 25 | initialState 26 | ) 27 | const history = ReduxRouter.syncHistoryWithStore( 28 | require('react-router').browserHistory, 29 | store 30 | ) 31 | return ( 32 | 33 | 34 | 35 | 36 | 37 | ) 38 | } --------------------------------------------------------------------------------