├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── README.md ├── circle.yml ├── dist └── favicon.ico ├── nodemon.json ├── package.json ├── platforms ├── browser │ ├── DevTools.js │ └── index.js ├── server │ ├── Html.jsx │ ├── api │ │ ├── index.js │ │ └── todos │ │ │ ├── index.js │ │ │ ├── redux.js │ │ │ └── routes │ │ │ ├── createTodo.js │ │ │ ├── deleteTodo.js │ │ │ ├── readTodo.js │ │ │ ├── readTodos.js │ │ │ └── updateTodo.js │ ├── index.js │ └── main.js └── shared │ ├── config.js │ ├── createClient.js │ ├── createStore.js │ └── reasync.js ├── src ├── App.css ├── App.jsx ├── Homepage │ └── Homepage.jsx ├── NotFound404 │ └── NotFound404.jsx ├── Repository │ ├── Author │ │ └── Author.jsx │ ├── BaseInfo │ │ └── BaseInfo.jsx │ ├── Contributors │ │ └── Contributors.jsx │ ├── Repository.jsx │ ├── redux.js │ └── routes.jsx ├── reducers.js └── routes.jsx └── webpack ├── build.js ├── dev.config.js ├── hot-server ├── index.js └── main.js ├── prod.config.js └── webpack-isomorphic-assets.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets":["es2015","react"], 3 | "plugins":[ 4 | "transform-object-rest-spread", 5 | "transform-class-properties", 6 | "transform-async-to-generator", 7 | "transform-decorators-legacy" 8 | ], 9 | "env": { 10 | "production": { 11 | "plugins": [ 12 | "transform-react-constant-elements", 13 | "transform-react-inline-elements" 14 | ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs. 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # We recommend you to keep these unchanged. 10 | charset = utf-8 11 | end_of_line = lf 12 | indent_size = 2 13 | indent_style = space 14 | insert_final_newline = true 15 | trim_trailing_whitespace = true 16 | 17 | [package.json] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false 23 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "ecmaFeatures": { 9 | "experimentalObjectRestSpread": true 10 | }, 11 | "rules": { 12 | "react/no-multi-comp": 0, 13 | "import/default": 0, 14 | "import/no-duplicates": 0, 15 | "import/named": 0, 16 | "import/namespace": 0, 17 | "import/no-unresolved": 0, 18 | "import/no-named-as-default": 2, 19 | "comma-dangle": 0, 20 | // not sure why airbnb turned this on. gross! 21 | "indent": [2, 2, {"SwitchCase": 1}], 22 | "no-console": 0, 23 | "no-case-declarations": 0, 24 | "no-alert": 0, 25 | "max-len":[2,140] 26 | }, 27 | "plugins": [ 28 | "react", 29 | "import" 30 | ], 31 | "settings": { 32 | "import/parser": "babel-eslint", 33 | "import/resolve": { 34 | moduleDirectory: [ 35 | "node_modules", 36 | "platforms", 37 | "src" 38 | ] 39 | } 40 | }, 41 | "globals": { 42 | "__DEVELOPMENT__": true, 43 | "__CLIENT__": true, 44 | "__SERVER__": true, 45 | "__DISABLE_SSR__": true, 46 | "__DEVTOOLS__": true, 47 | "socket": true, 48 | "webpackIsomorphicTools": true 49 | }, 50 | "parser": "babel-eslint" 51 | } 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | webpack-assets.json 3 | webpack-stats.json 4 | .idea/ 5 | npm-debug.log 6 | tmp/ 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project is not maintained anymore. There are much better boilerplates for starting your app 2 | 3 | ## Installation 4 | 5 | ```bash 6 | npm install 7 | ``` 8 | 9 | ## About 10 | 11 | This is boilerplate I have created to learn, to try, to evaluate how thing works, but I hope you can use it for yourself too. 12 | In this repo you can find a lot of parts of code from another similar projects. 13 | It's far from being complete, there is a lot of dependencies I want to use in future, but until now didn't have time to. 14 | 15 | ## Running Dev Server 16 | 17 | ```bash 18 | //first command line 19 | npm run start:dev 20 | 21 | //second command line 22 | npm run start:hot 23 | 24 | ``` 25 | 26 | ## To Be Done? 27 | 28 | * immutable? 29 | * styles (css-modules ???) 30 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 4.0 4 | environment: 5 | CONTINUOUS_INTEGRATION: true 6 | 7 | dependencies: 8 | cache_directories: 9 | - node_modules 10 | override: 11 | - npm prune && npm install 12 | 13 | test: 14 | override: 15 | - npm run lint 16 | -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svrcekmichal/universal-react/b91d0eedd0173dc8160f8c66fdd6f1ae447f94c6/dist/favicon.ico -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "restartable": "rs", 3 | "ignore": [ 4 | ".git", 5 | "node_modules", 6 | "webpack-assets.json", 7 | ".idea", 8 | "*/tmp/*" 9 | ], 10 | "verbose": true, 11 | "ext": "js jsx json" 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "universal-react", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack --verbose --colors --display-error-details --config webpack/prod.config.js", 8 | "start:prod": "NODE_ENV=production NODE_PATH=./platforms:./src PORT=8080 node ./platforms/server", 9 | "start:dev": "NODE_ENV=development NODE_PATH=./platforms:./src PORT=8080 nodemon ./platforms/server", 10 | "start:hot": "UV_THREADPOOL_SIZE=100 NODE_PATH=./platforms:./src PORT=8080 node webpack/hot-server", 11 | "lint": "eslint -c .eslintrc ./" 12 | }, 13 | "dependencies": { 14 | "autoprefixer": "^6.3.3", 15 | "axios": "^0.8.1", 16 | "babel-core": "^6.5.2", 17 | "babel-loader": "^6.2.3", 18 | "babel-plugin-transform-async-to-generator": "^6.4.0", 19 | "babel-plugin-transform-class-properties": "^6.4.0", 20 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 21 | "babel-plugin-transform-object-rest-spread": "^6.3.13", 22 | "babel-plugin-transform-react-constant-elements": "^6.3.13", 23 | "babel-plugin-transform-react-inline-elements": "^6.3.13", 24 | "babel-polyfill": "^6.3.14", 25 | "babel-preset-es2015": "^6.3.13", 26 | "babel-preset-react": "^6.3.13", 27 | "babel-runtime": "^6.5.0", 28 | "bluebird": "^3.1.1", 29 | "body-parser": "^1.15.0", 30 | "clean-webpack-plugin": "^0.1.6", 31 | "compression": "^1.6.0", 32 | "cookie-parser": "^1.4.1", 33 | "css-loader": "^0.23.1", 34 | "express": "^4.13.3", 35 | "file-loader": "^0.8.5", 36 | "history": "2.0.0-rc2", 37 | "jsonfile": "^2.2.3", 38 | "postcss-loader": "^0.8.2", 39 | "pretty-error": "^2.0.0", 40 | "react": "^0.14.6", 41 | "react-dom": "^0.14.6", 42 | "react-helmet": "^2.3.1", 43 | "react-redux": "^4.0.6", 44 | "react-router": "2.0.0-rc5", 45 | "react-router-redux": "^4.0.0-beta.1", 46 | "reasync": "^1.0.0-rc.1", 47 | "redux": "^3.3.1", 48 | "redux-axios-middleware": "^0.2.0", 49 | "redux-form": "^4.1.1", 50 | "serialize-javascript": "^1.1.2", 51 | "serve-favicon": "^2.3.0", 52 | "style-loader": "^0.13.0", 53 | "url-loader": "^0.5.7", 54 | "uuid": "^2.0.1", 55 | "webpack": "^1.12.10", 56 | "webpack-isomorphic-tools": "^2.2.24" 57 | }, 58 | "devDependencies": { 59 | "babel-eslint": "^5.0.0", 60 | "babel-plugin-react-transform": "^2.0.0", 61 | "clean-webpack-plugin": "^0.1.6", 62 | "eslint": "~2.2.0", 63 | "eslint-config-airbnb": "^6.0.1", 64 | "eslint-plugin-import": "^1.0.0-beta.0", 65 | "eslint-plugin-react": "^4.0.0", 66 | "nodemon": "^1.8.1", 67 | "react-transform-hmr": "^1.0.1", 68 | "redux-devtools": "^3.0.1", 69 | "redux-devtools-dock-monitor": "^1.0.1", 70 | "redux-devtools-log-monitor": "^1.0.1", 71 | "webpack-dev-middleware": "^1.4.0", 72 | "webpack-hot-middleware": "^2.6.0" 73 | }, 74 | "keywords": [], 75 | "author": "", 76 | "license": "ISC" 77 | } 78 | -------------------------------------------------------------------------------- /platforms/browser/DevTools.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createDevTools } from 'redux-devtools'; 3 | import LogMonitor from 'redux-devtools-log-monitor'; 4 | import DockMonitor from 'redux-devtools-dock-monitor'; 5 | 6 | export default createDevTools( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /platforms/browser/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { Router, browserHistory, match } from 'react-router'; 5 | import { syncHistoryWithStore } from 'react-router-redux'; 6 | 7 | import { getRoutes } from 'routes'; 8 | import createStore from 'shared/createStore'; 9 | import createClient from 'shared/createClient'; 10 | import { createClientResolver } from 'shared/reasync'; 11 | 12 | const store = createStore(browserHistory, window.__data__, createClient()); 13 | const history = syncHistoryWithStore(browserHistory, store); 14 | const routes = getRoutes(store); 15 | const mountPoint = document.getElementById('content'); 16 | const router = (); 17 | createClientResolver(history, routes, store); 18 | 19 | const hasDevToolsExtension = () => typeof window === 'object' 20 | && typeof window.devToolsExtension !== 'undefined'; 21 | 22 | const showDevTools = __DEVELOPMENT__ && __DEVTOOLS__ && !hasDevToolsExtension(); 23 | 24 | const { pathname, search, hash } = window.location; 25 | const location = `${pathname}${search}${hash}`; 26 | match({ routes, history, location }, () => { // to preload all components needed and not break server markup 27 | if (showDevTools && !hasDevToolsExtension()) { 28 | const DevTools = require('./DevTools').default; 29 | ReactDOM.render( 30 | 31 |
32 | {router} 33 | 34 |
35 |
, 36 | mountPoint 37 | ); 38 | } else { 39 | ReactDOM.render( 40 | 41 | {router} 42 | , 43 | mountPoint 44 | ); 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /platforms/server/Html.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import ReactDOM from '../../node_modules/react-dom/server'; 3 | import serialize from 'serialize-javascript'; 4 | import Helmet from 'react-helmet'; 5 | 6 | /** 7 | * Wrapper component containing HTML metadata and boilerplate tags. 8 | * Used in server-side code only to wrap the string output of the 9 | * rendered route component. 10 | * 11 | * The only thing this component doesn't (and can't) include is the 12 | * HTML doctype declaration, which is added to the rendered output 13 | * by the server.js file. 14 | */ 15 | export default class Html extends Component { 16 | 17 | static propTypes = { 18 | assets: PropTypes.object, 19 | component: PropTypes.node, 20 | store: PropTypes.object 21 | }; 22 | 23 | render() { 24 | const { assets, component, store } = this.props; 25 | const content = component ? ReactDOM.renderToString(component) : ''; 26 | const head = Helmet.rewind(); 27 | 28 | return ( 29 | 30 | 31 | {head.base.toComponent()} 32 | {head.title.toComponent()} 33 | {head.meta.toComponent()} 34 | {head.link.toComponent()} 35 | {head.script.toComponent()} 36 | 37 | 38 | 39 | {/* styles (will be present only in production with webpack extract text plugin) */} 40 | {Object.keys(assets.styles).map((style, key) => 41 | 43 | )} 44 | 45 | 46 |
47 |