├── postcss.config.js ├── .gitignore ├── src ├── config.js ├── components │ ├── Profile │ │ ├── index.js │ │ ├── package.json │ │ └── Profile.js │ ├── App │ │ ├── package.json │ │ ├── AppActions.js │ │ ├── index.js │ │ ├── App.spec.js │ │ ├── AppReducer.js │ │ ├── AppContainer.js │ │ ├── style.scss │ │ └── App.js │ └── NotFound │ │ ├── package.json │ │ ├── style.scss │ │ └── NotFound.js ├── common.js ├── store.js └── routes.js ├── index.ejs ├── .babelrc ├── index.js ├── .editorconfig ├── webpack.test.config.js ├── webpack.config.js ├── webpack.production.config.js ├── README.md └── package.json /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules/ 3 | coverage/ 4 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | export const BASE_PATH = "/app"; 2 | -------------------------------------------------------------------------------- /src/components/Profile/index.js: -------------------------------------------------------------------------------- 1 | import Profile from "./Profile"; 2 | 3 | export default Profile; 4 | -------------------------------------------------------------------------------- /src/components/App/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./index.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Profile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Profile", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./index.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/NotFound/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NotFound", 3 | "version": "1.0.0", 4 | "private": true, 5 | "main": "./NotFound.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/common.js: -------------------------------------------------------------------------------- 1 | import { BASE_PATH } from "./config"; 2 | 3 | export const routeFor = (path) => { 4 | if (path === "/") return BASE_PATH; 5 | return `${BASE_PATH}/${path}`; 6 | } 7 | -------------------------------------------------------------------------------- /src/components/App/AppActions.js: -------------------------------------------------------------------------------- 1 | export const CHANGE_COLOR = "CHANGE_COLOR"; 2 | 3 | export const changeColor = () => { 4 | return { 5 | type: CHANGE_COLOR 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /src/components/NotFound/style.scss: -------------------------------------------------------------------------------- 1 | ._404 { 2 | text-align: center; 3 | font-size: 3em; 4 | span{ color: red } 5 | a { 6 | font-size: 20px; 7 | color: blue; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 |
9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/App/index.js: -------------------------------------------------------------------------------- 1 | import App from "./App"; 2 | import AppActions from "./AppActions"; 3 | import AppContainer from "./AppContainer"; 4 | import AppReducer from "./AppReducer"; 5 | 6 | export { 7 | App, 8 | AppActions, 9 | AppContainer, 10 | AppReducer 11 | } 12 | export default App; 13 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "latest", "stage-0"], 3 | "plugins": [ "transform-runtime" ], 4 | "env": { 5 | "test": { 6 | "plugins": [ 7 | [ 8 | "babel-plugin-webpack-loaders", 9 | { 10 | "config": "./webpack.test.config.js", 11 | "verbose": false, 12 | } 13 | ] 14 | ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/App/App.spec.js: -------------------------------------------------------------------------------- 1 | jest.unmock("./App.js"); 2 | import React from "react"; 3 | import App from "./App.js"; 4 | import { shallow, mount } from "enzyme"; 5 | 6 | describe("App", function(){ 7 | test("renders the App component", function() { 8 | const component = mount(); 9 | expect(component.find('p').text()).toEqual("Awesome React!"); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/components/App/AppReducer.js: -------------------------------------------------------------------------------- 1 | import { CHANGE_COLOR } from "./AppActions.js"; 2 | import randomColor from "randomcolor"; 3 | 4 | let DEFAULT_STATE = { 5 | color: randomColor() 6 | }; 7 | 8 | export default (state = DEFAULT_STATE, action) => { 9 | switch ( action.type ) { 10 | case CHANGE_COLOR: 11 | return { ...state, color: randomColor()}; 12 | default: 13 | return state; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { render } from "react-dom"; 3 | import Router from "./src/routes"; 4 | import store from "./src/store"; 5 | 6 | const run = () => { 7 | render(Router(store), document.getElementById("App")); 8 | } 9 | 10 | if (["complete", "loaded", "interactive"].includes(document.readyState) && document.body) { 11 | run(); 12 | } else { 13 | document.addEventListener("DOMContentLoaded", run, false); 14 | } 15 | 16 | 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /src/components/App/AppContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from "react-redux"; 2 | import App from "./App"; 3 | import { changeColor } from "./AppActions"; 4 | 5 | const mapStateToProps = (state) => { 6 | return { 7 | color: state.AppReducer.color 8 | } 9 | } 10 | 11 | const mapDispatchToProps = (dispatch) => { 12 | return { 13 | onChangeColor: () => dispatch(changeColor()), 14 | } 15 | } 16 | 17 | const AppContainer = connect( 18 | mapStateToProps, 19 | mapDispatchToProps 20 | )(App); 21 | 22 | export default AppContainer; 23 | -------------------------------------------------------------------------------- /src/components/App/style.scss: -------------------------------------------------------------------------------- 1 | .react-logo { 2 | display: block; 3 | width: 400px; 4 | height: 400px; 5 | margin: 0 auto; 6 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 7 | span { 8 | width: 200px; 9 | display: block; 10 | cursor: pointer; 11 | margin: 0 auto; 12 | font-size: 22em; 13 | &:before { 14 | content: '⚛'; 15 | font-weight: bold; 16 | } 17 | } 18 | } 19 | 20 | p, a{ 21 | width: 400px; 22 | height: 20px; 23 | display: block; 24 | margin: 0 auto; 25 | text-align: center; 26 | text-decoration: none; 27 | cursor: pointer; 28 | &:hover { 29 | font-weight: bold; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Profile/Profile.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | 3 | class Profile extends Component { 4 | 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | name: "Alejandro Espinoza", 9 | email: "alexesba@gmail.com", 10 | avatar: "https://avatars2.githubusercontent.com/u/579793?v=4&s=460" 11 | } 12 | } 13 | 14 | render() { 15 | return ( 16 |
17 | 18 |
19 |

{ this.state.name }

20 |

{ this.state.email }

21 |
22 |
23 | ); 24 | } 25 | } 26 | 27 | export default Profile; 28 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, combineReducers } from 'redux' 2 | import thunk from "redux-thunk"; 3 | import { browserHistory } from 'react-router' 4 | import { routerMiddleware } from "react-router-redux"; 5 | 6 | // Import reducers 7 | import { AppReducer } from "./components/App"; 8 | 9 | const reactRouterReduxMiddleware = routerMiddleware(browserHistory); 10 | 11 | let createStoreWithMiddleware = applyMiddleware( 12 | thunk, reactRouterReduxMiddleware 13 | )(createStore); 14 | 15 | let reducers = combineReducers({ 16 | AppReducer 17 | }); 18 | 19 | export default createStoreWithMiddleware(reducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); 20 | 21 | -------------------------------------------------------------------------------- /src/routes.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Router, Route, browserHistory } from "react-router"; 3 | import { AppContainer } from "./components/App"; 4 | import NotFound from "./components/NotFound"; 5 | import Profile from "./components/Profile"; 6 | import { routeFor } from "./common"; 7 | import { Provider } from "react-redux"; 8 | 9 | export default (store) => { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src/components/App/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import CSSModules from "react-css-modules"; 3 | import { Link } from "react-router"; 4 | import style from "./style.scss"; 5 | import { routeFor } from "../../common"; 6 | 7 | class App extends Component { 8 | 9 | render() { 10 | const { onChangeColor, color } = this.props; 11 | return ( 12 |
13 |
14 | 15 |
16 |

17 | 18 | Awesome React! 19 | 20 |

21 |
22 | ); 23 | } 24 | 25 | }; 26 | 27 | export default CSSModules(App, style); 28 | -------------------------------------------------------------------------------- /src/components/NotFound/NotFound.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import CSSModules from "react-css-modules"; 3 | import { Link } from "react-router"; 4 | import style from "./style.scss"; 5 | import { routeFor } from "../../common"; 6 | 7 | class NotFound extends Component { 8 | 9 | constructor(props) { 10 | super(props); 11 | } 12 | 13 | static defaultProps = { 14 | message: "not found" 15 | } 16 | render() { 17 | const { location: { pathname } } = this.props; 18 | return( 19 |
20 | Page: { pathname } {this.props.message } 21 | Home 22 |
23 | ); 24 | } 25 | } 26 | 27 | export default CSSModules(NotFound, style); 28 | -------------------------------------------------------------------------------- /webpack.test.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); // eslint-disable-line no-var 2 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); // eslint-disable-line no-var 3 | 4 | const loaderString = [ 5 | 'css?minimize&modules&localIdentName=[hash:base64:4]', 6 | 'postcss-loader?parser=postcss-scss', 7 | "sass-loader" 8 | ].join('!') 9 | module.exports = { 10 | output: { 11 | // for babel plugin 12 | libraryTarget: 'commonjs2', 13 | // where to place webpack files 14 | path: path.join(__dirname, './build/'), 15 | // for url-loader if limit exceeded to set publicPath 16 | publicPath: '', 17 | }, 18 | module: { 19 | loaders: [ 20 | { 21 | test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf)$/, 22 | loader: 'url-loader?limit=1000', 23 | }, 24 | { 25 | test: /.json$/, 26 | loader: "json-loader" 27 | }, 28 | { 29 | test: /\.scss?$/, 30 | exclude: /node_modules/, 31 | loader: ExtractTextPlugin.extract(loaderString) 32 | } 33 | ] 34 | }, 35 | "plugins": [ 36 | new ExtractTextPlugin('style.css') 37 | ] 38 | }; 39 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var lodash = require("lodash"); 3 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 4 | var HtmlWebpackPlugin = require("html-webpack-plugin"); 5 | 6 | 7 | module.exports = { 8 | entry: path.join(__dirname, "index.js"), 9 | output: { 10 | publicPath: '/' 11 | }, 12 | devServer: { 13 | historyApiFallback: true, 14 | hot: true, 15 | inline: true, 16 | open: true, 17 | progress: true 18 | }, 19 | module: { 20 | loaders: [ 21 | { test: /\.jsx?$/, 22 | loader: "babel", 23 | exclude: /node_modules/, 24 | include: __dirname, 25 | query: { 26 | presets: ['react-hmre', 'react', 'latest', "stage-0"] 27 | } 28 | }, 29 | { 30 | test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf)$/, 31 | loader: 'url-loader?limit=9999999', 32 | }, 33 | 34 | { test: /\.scss?$/, loaders: [ 35 | "style?sourceMap", 36 | "css-loader?sourceMap&modules&localIdentName=[path]__[name]__[local]__[hash:base64:5]", 37 | "postcss-loader?parser=postcss-scss", 38 | "sass-loader?sourceMap" 39 | ] 40 | }, 41 | ] 42 | }, 43 | "plugins": [ 44 | new HtmlWebpackPlugin({ 45 | title: "Awesome React!!", 46 | template: "index.ejs", 47 | }) 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /webpack.production.config.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var lodash = require("lodash"); 3 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 4 | var HtmlWebpackPlugin = require("html-webpack-plugin"); 5 | var HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin'); 6 | 7 | 8 | const loaderString = [ 9 | 'css?minimize&modules&localIdentName=[hash:base64:4]', 10 | 'postcss-loader?parser=postcss-scss', 11 | "sass-loader" 12 | ].join('!') 13 | module.exports = { 14 | node: { 15 | fs: "empty" 16 | }, 17 | entry: { 18 | app: [ path.join(__dirname, "/index.js") ] 19 | }, 20 | output: { 21 | path: path.resolve(__dirname + "/build"), 22 | filename: "app.js" 23 | }, 24 | resolve: { 25 | extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx', '.json'], 26 | modulesDirectories: ['src', 'node_modules'], 27 | root: [path.join(__dirname, "src")] 28 | }, 29 | module: { 30 | loaders: [ 31 | { test: /\.jsx?$/, loader: "babel-loader", exclude: /node_modules/ }, 32 | { 33 | test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|eot|ttf)$/, 34 | loader: 'url-loader?limit=1000', 35 | }, 36 | { 37 | test: /.json$/, 38 | loader: "json-loader" 39 | }, 40 | { 41 | test: /\.scss?$/, 42 | exclude: /node_modules/, 43 | loader: ExtractTextPlugin.extract(loaderString) 44 | }, 45 | ] 46 | }, 47 | "externals": { 48 | "react": "React", 49 | "react-dom": "ReactDOM" 50 | }, 51 | "plugins": [ 52 | new ExtractTextPlugin('style.css'), 53 | new HtmlWebpackPlugin({ 54 | title: "Awesome React!!", 55 | template: "index.ejs" 56 | }), 57 | new HtmlWebpackExternalsPlugin([ 58 | { name: "react", var: "React", url: "https://unpkg.com/react@15.4.1/dist/react.js" }, 59 | { name: "react-dom", var: "ReactDOM", url: "https://unpkg.com/react-dom@15.4.1/dist/react-dom.js" } 60 | ]) 61 | ] 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Rebo 2 | 3 | ## Simple [**React**](https://facebook.github.io/react/) boilerplate 4 | 5 | > Create [**React**](https://facebook.github.io/react/) applications and avoid spent time configuring tasks for transpiling scss and javascripts 6 | This project has born with the main idea to have something up and running in a couple of minutes. It also provides you 7 | a structure of files to keep your code organized in packages called **Components** this boilerplate integrates [**Redux**](https://github.com/reactjs/redux) 8 | 9 | ## Technologies implemented: 10 | - *babel* 11 | - *es6* 12 | - *jsx* 13 | - *react* 14 | - *redux* 15 | - *scss* 16 | 17 | 18 | ## Available tasks/commands: 19 | * `npm start:` runs the application in development mode it will open your browser in a tab and display a small demo 20 | * `npm run build`: compiles the whole src directory whithin the `build` directory 21 | * `npm run test`: runs the test suite. 22 | * `npm coverage`: opens the coverage results in the browser 23 | 24 | 25 | ## File Structure: 26 | ```sh 27 | . 28 | ├── README.md 29 | ├── build 30 | │   ├── 966a74a61246a4060d377bbc8321529e.svg 31 | │   ├── app.js 32 | │   ├── index.html 33 | │   └── style.css 34 | ├── coverage 35 | ├── index.ejs #ejs template which is used on production and development env. 36 | ├── index.js #entry file for webpack compilations in other word our main file 37 | ├── package.json #package dependencies and dev-dependcies. 38 | ├── src 39 | │   ├── components 40 | │   │   ├── App 41 | │   │   │   ├── App.js 42 | │   │   │   ├── App.spec.js 43 | │   │   │   ├── AppActions.js 44 | │   │   │   ├── AppContainer.js 45 | │   │   │   ├── AppReducer.js 46 | │   │   │   ├── index.js 47 | │   │   │   ├── package.json 48 | │   │   │   ├── react.svg 49 | │   │   │   └── style.scss 50 | │   │   └── NotFound 51 | │   │   ├── NotFound.js 52 | │   │   └── package.json 53 | │   ├── routes.js 54 | │   └── store.js 55 | ├── webpack.config.js #config file used for development 56 | ├── webpack.production.config.js #config file used for production 57 | ├── webpack.test.config.js #used to compile and run the suite test 58 | └── yarn.lock #used to install all dependencies if you are using yarn 59 | ``` 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo-react", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "alexesba ", 6 | "license": "MIT", 7 | "dependencies": { 8 | "lodash": "^4.17.4", 9 | "prop-types": "^15.5.8", 10 | "randomcolor": "^0.4.4", 11 | "react": "^15.5.4", 12 | "react-css-modules": "^4.0.5", 13 | "react-dom": "^15.5.4", 14 | "react-redux": "^4.4.6", 15 | "react-router": "^3.0.0", 16 | "react-router-redux": "^4.0.7", 17 | "redux": "^3.6.0", 18 | "redux-thunk": "^2.1.0" 19 | }, 20 | "scripts": { 21 | "start": "webpack-dev-server --hot", 22 | "clean": "rm -rf build", 23 | "compile": "webpack --config webpack.production.config.js", 24 | "build": "npm run clean && npm run compile", 25 | "test": "BABEL_DISABLE_CACHE=1 NODE_ENV=test jest", 26 | "coverage": "opener coverage/lcov-report/index.html" 27 | }, 28 | "jest": { 29 | "rootDir": ".", 30 | "collectCoverage": true, 31 | "transform": { 32 | ".js": "/node_modules/babel-jest" 33 | }, 34 | "moduleFileExtensions": [ 35 | "js", 36 | "jsx", 37 | "json" 38 | ], 39 | "moduleDirectories": [ 40 | "node_modules" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "autoprefixer-core": "^6.0.1", 45 | "babel-cli": "^6.18.0", 46 | "babel-core": "^6.18.2", 47 | "babel-eslint": "^7.1.1", 48 | "babel-jest": "^17.0.2", 49 | "babel-loader": "^6.2.8", 50 | "babel-plugin-css-modules-transform": "^1.1.0", 51 | "babel-plugin-react-transform": "^2.0.2", 52 | "babel-plugin-transform-runtime": "^6.15.0", 53 | "babel-plugin-webpack-loaders": "^0.8.0", 54 | "babel-preset-latest": "^6.16.0", 55 | "babel-preset-react": "^6.16.0", 56 | "babel-preset-react-hmre": "^1.1.1", 57 | "babel-preset-stage-0": "^6.16.0", 58 | "babel-runtime": "^6.18.0", 59 | "css-loader": "^0.26.0", 60 | "enzyme": "^2.6.0", 61 | "extract-text-webpack-plugin": "^1.0.1", 62 | "file-loader": "^0.9.0", 63 | "html-webpack-externals-plugin": "^2.1.2", 64 | "html-webpack-plugin": "^2.24.1", 65 | "identity-obj-proxy": "^3.0.0", 66 | "isomorphic-style-loader": "^1.1.0", 67 | "jest": "^17.0.3", 68 | "jest-cli": "^17.0.3", 69 | "jest-css-modules": "^1.1.0", 70 | "json-loader": "^0.5.4", 71 | "mocha": "^3.2.0", 72 | "node-sass": "^3.13.0", 73 | "opener": "^1.4.2", 74 | "postcss-color-rebeccapurple": "^2.0.1", 75 | "postcss-loader": "^1.1.1", 76 | "postcss-scss": "^0.4.0", 77 | "raw-loader": "^0.5.1", 78 | "react-addons-test-utils": "^15.4.1", 79 | "react-hot-loader": "^1.3.1", 80 | "react-test-renderer": "^15.4.1", 81 | "resolve-url": "^0.2.1", 82 | "resolve-url-loader": "^1.6.0", 83 | "sass-loader": "^4.0.2", 84 | "style-loader": "^0.13.1", 85 | "url-loader": "^0.5.7", 86 | "webpack": "^1.13.3", 87 | "webpack-dev-middleware": "^1.8.4", 88 | "webpack-dev-server": "^1.16.2", 89 | "webpack-hot-middleware": "^2.13.2" 90 | } 91 | } 92 | --------------------------------------------------------------------------------