├── .babelrc ├── .editorconfig ├── .env ├── .eslintignore ├── .eslintrc ├── .gitignore ├── Dockerfile ├── README.md ├── package.json ├── public └── favicon.ico ├── src ├── actions │ └── user.js ├── client.js ├── components │ ├── Home │ │ ├── Home.js │ │ ├── Home.scss │ │ └── funyee.png │ └── Html │ │ └── Html.js ├── constants │ └── user.js ├── containers │ └── HomeContainer │ │ ├── HomeContainer.js │ │ └── HomeContainer.scss ├── reducers │ ├── index.js │ └── user.js ├── routes │ ├── index.js │ └── routes.js ├── server.js └── store │ └── create.js └── tools ├── webpack-isomorphic-tools.js ├── webpack.dev.config.js └── webpack.prod.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | presets: [ "es2015", "stage-3", "react" ] 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.js] 8 | indent_style = tab 9 | 10 | [*.json] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | API=http://localhost:3000 2 | NODE_APP_PORT=3000 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | tools/webpack.dev.config.js 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "plugins": [ 9 | "react", "import" 10 | ], 11 | "settings": { 12 | "import/default": /\*.js/ 13 | }, 14 | "rules": { 15 | "indent": [2, "tab"], 16 | "no-console": 0 17 | }, 18 | "globals": { 19 | "console": true 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | public/dist 2 | npm-debug.log 3 | .DS_Store 4 | node_modules 5 | webpack-assets.json 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | RUN mkdir -p /usr/src/app 4 | WORKDIR /usr/src/app 5 | 6 | COPY package.json package.json 7 | RUN npm install 8 | 9 | COPY . . 10 | 11 | CMD [ "npm", "run", "start:prod" ] 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-universal-redux-starter-kit 2 | It's the starter kit to build up universal structure of react with redux. 3 | We use as less code as we can to build up universal, I hope you will like it! 4 | 5 | ## Before staring it, something you must to know 6 | 7 | 1. Of course, React, Redux, Isomorphic(Universal), ES6, eslint, npm, node. 8 | 2. [redux-thunk](https://github.com/gaearon/redux-thunk) => Help Redux do asynchronized actions. 9 | 3. [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) => Help react to do hot reload on client side. 10 | 4. [webpack-hot-middleware](https://github.com/glenjamin/webpack-hot-middleware) => Help you do hot reload in server-side. 11 | 5. [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch) => Use fetch in both client and server side. 12 | 6. [webpack-isomorphic-tools](https://github.com/halt-hammerzeit/webpack-isomorphic-tools) => Help you deal with some files in isomorphic structure, make it avaible on both client and server side. 13 | 7. [dotenv](https://github.com/bkeepers/dotenv) => Help you easily write configs. 14 | 8. [extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin) Extract all your css in one file for server-side use. 15 | 9. Container Design Pattern of React Redux 16 | 17 | 18 | ## Clone repository 19 | Clone the repository 20 | 21 | ```bash 22 | https://github.com/DumDumGeniuss/react-universal-redux-starter-kit.git react-universal-redux-starter-kit 23 | ``` 24 | Go into the directory 25 | 26 | ```bash 27 | cd react-universal-redux-starter-kit 28 | ``` 29 | 30 | ## Make it yours 31 | Delete the .git directory 32 | 33 | ```bash 34 | rm -rf .git 35 | ``` 36 | Re-initialize the repository 37 | 38 | ```bash 39 | git init 40 | ``` 41 | 42 | ## INSTALL packages 43 | 44 | ```bash 45 | npm install 46 | ``` 47 | 48 | ## DEVELOPMENT MODE 49 | 50 | ```bash 51 | npm run start:dev 52 | ``` 53 | 54 | ## PRODUCTION MODE 55 | 56 | ```bash 57 | npm run start:prod 58 | ``` 59 | 60 | ## ESLINT CHECK 61 | 62 | ```bash 63 | npm run eslint 64 | ``` 65 | 66 | ## DOCKER (optional) 67 | 68 | Build up your react application image 69 | 70 | ```bash 71 | docker build -t react-universal-redux-starter-kit . 72 | ``` 73 | Create container by the image, and run it, expose port 74 | 75 | ```bash 76 | docker run -p 3000:3000 -d react-universal-redux-starter-kit 77 | ``` 78 | 79 | Then you can find your app on localhost:3000 (maybe few seconds) 80 | 81 | ###_If you use Mac, sometimes you need to find your docekr vm ip rather than localhost_ 82 | 83 | ```bash 84 | docker-machine ip 85 | ``` 86 | 87 | ## REFERENCE 88 | 89 | [erikras/react-redux-universal-hot-example](https://github.com/erikras/react-redux-universal-hot-example) 90 | 91 | [kriasoft/react-starter-kit 92 | ](https://github.com/kriasoft/react-starter-kit) 93 | 94 | ## LICENSE 95 | Free, welcome to use it. 96 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-universal-redux-starter-kit", 3 | "version": "1.0.0", 4 | "description": "It's the react-start-kit for you to quickly build application of React Isomorphic Structure.", 5 | "scripts": { 6 | "eslint": "better-npm-run eslint", 7 | "start:dev": "better-npm-run start:dev", 8 | "start:prod": "better-npm-run start:prod" 9 | }, 10 | "betterScripts": { 11 | "eslint": { 12 | "command": "eslint src; exit 0" 13 | }, 14 | "start:dev": { 15 | "command": "webpack --config tools/webpack.dev.config.js && babel-node src/server.js", 16 | "env": { 17 | "NODE_ENV": "development" 18 | } 19 | }, 20 | "start:prod": { 21 | "command": "webpack --config tools/webpack.prod.config.js && babel-node src/server.js", 22 | "env": { 23 | "NODE_ENV": "production" 24 | } 25 | } 26 | }, 27 | "author": "DumDumGeniuss", 28 | "license": "MIT", 29 | "dependencies": { 30 | "babel-loader": "^6.2.8", 31 | "babel-polyfill": "^6.16.0", 32 | "body-parser": "^1.15.2", 33 | "cookie-parser": "^1.4.3", 34 | "dotenv": "^4.0.0", 35 | "es6-promise": "^4.0.5", 36 | "express": "^4.14.0", 37 | "history": "^1.17.0", 38 | "isomorphic-fetch": "^2.2.1", 39 | "react": "^15.4.0", 40 | "react-dom": "^15.4.0", 41 | "react-redux": "^4.4.6", 42 | "react-router": "^3.0.0", 43 | "redux": "^3.6.0", 44 | "redux-thunk": "^2.1.0", 45 | "serialize-javascript": "^1.3.0", 46 | "serve-favicon": "^2.3.2", 47 | "webpack-isomorphic-tools": "^2.2.18" 48 | }, 49 | "devDependencies": { 50 | "autoprefixer-loader": "^3.2.0", 51 | "babel-cli": "^6.18.0", 52 | "babel-eslint": "^7.1.1", 53 | "babel-preset-es2015": "^6.18.0", 54 | "babel-preset-react": "^6.16.0", 55 | "babel-preset-stage-3": "^6.17.0", 56 | "better-npm-run": "0.0.13", 57 | "css-loader": "^0.26.0", 58 | "eslint": "^1.10.3", 59 | "eslint-config-airbnb": "^0.1.0", 60 | "eslint-loader": "^1.0.0", 61 | "eslint-plugin-import": "^0.8.1", 62 | "eslint-plugin-react": "^3.16.1", 63 | "extract-text-webpack-plugin": "^1.0.1", 64 | "file-loader": "^0.9.0", 65 | "json-loader": "^0.5.4", 66 | "node-sass": "^3.13.0", 67 | "sass-loader": "^4.0.2", 68 | "style-loader": "^0.13.1", 69 | "url-loader": "^0.5.7", 70 | "webpack": "^1.13.3", 71 | "webpack-dev-middleware": "^1.8.4", 72 | "webpack-hot-middleware": "^2.13.2" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/messi-yang/react-universal-redux-starter-kit/587a32e0df6eb180e2194443a531a9000d22701e/public/favicon.ico -------------------------------------------------------------------------------- /src/actions/user.js: -------------------------------------------------------------------------------- 1 | import * as userConstant from '../constants/user.js'; 2 | import es6Promise from 'es6-promise'; 3 | es6Promise.polyfill(); 4 | import fetch from 'isomorphic-fetch'; 5 | 6 | export function addUser(user) { 7 | return { 8 | type: userConstant.ADD_USER, 9 | result: user, 10 | }; 11 | } 12 | 13 | /* 14 | Here's example of how to do asynchronization in Redux Actions , 15 | Before doing that, you need to add 'Thunk' middleware in createStore function. 16 | */ 17 | export function addUserAsync(user) { 18 | // You will need dispatch to dispatch the object returned by addUser 19 | return dispatch => { 20 | const headers = new Headers(); 21 | headers.append('Content-Type', 'text/plain'); 22 | 23 | //process.env.API comes from webpack config file and .env file 24 | fetch(process.env.API + '/getUserTitle', {headers: headers}) 25 | .then((res) => { 26 | return res.text(); 27 | }) 28 | .then((res) => { 29 | user.name = res + user.name; 30 | dispatch(addUser(user)); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/client.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Routes from './routes/index.js'; 4 | 5 | import { Provider } from 'react-redux'; 6 | import storeCreator from './store/create.js'; 7 | 8 | const app = document.getElementById('app'); 9 | 10 | /** 11 | * Hydrate the server side State. 12 | */ 13 | const store = storeCreator(window.__INITIAL_STATE__); 14 | 15 | ReactDOM.render( 16 | 17 | 18 | 19 | , app); 20 | 21 | // Let you do the hot-reload while in development mode, google 'webpack-dev-middleware' and 'webpack-hot-middleware' 22 | if (module.hot) { 23 | module.hot.accept(); 24 | } 25 | -------------------------------------------------------------------------------- /src/components/Home/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class Home extends React.Component { 4 | static get propTypes() { 5 | return { 6 | users: React.PropTypes.array, 7 | }; 8 | } 9 | render() { 10 | const { users } = this.props; 11 | const style = require('./Home.scss'); 12 | // In this place, funyee represents the file path. 13 | const funyee = require('./funyee.png'); 14 | return ( 15 |
16 | { 17 | users.map( (item, index) => { 18 | return ( 19 |
20 | 21 | {item.name} 22 |
23 | ); 24 | }) 25 | } 26 |
27 | ); 28 | } 29 | } 30 | 31 | export default Home; 32 | -------------------------------------------------------------------------------- /src/components/Home/Home.scss: -------------------------------------------------------------------------------- 1 | .box { 2 | display: inline-block; 3 | border: 2px solid black; 4 | border-radius: 10px; 5 | margin: 5px; 6 | padding: 4px; 7 | } 8 | .name { 9 | display: inline-block; 10 | color: #5d108e; 11 | vertical-align: middle; 12 | font-size: 20px; 13 | } 14 | .image { 15 | display: inline-block; 16 | vertical-align: middle; 17 | width: 20px; 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Home/funyee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/messi-yang/react-universal-redux-starter-kit/587a32e0df6eb180e2194443a531a9000d22701e/src/components/Home/funyee.png -------------------------------------------------------------------------------- /src/components/Html/Html.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import serialize from 'serialize-javascript'; 3 | 4 | class Html extends React.Component { 5 | static get propTypes() { 6 | return { 7 | assets: React.PropTypes.object, 8 | reactHtml: React.PropTypes.string, 9 | store: React.PropTypes.object, 10 | }; 11 | } 12 | render() { 13 | // The assets are providde by webpack-isomorphic-tools 14 | const { assets, reactHtml, store } = this.props; 15 | return ( 16 | 17 | 18 | 19 | {Object.keys(assets.styles).map((style, key) => 20 | 22 | )} 23 | 24 | 25 |
26 |