├── .gitignore ├── README.md ├── app ├── HOC │ ├── ContainerEnhancer.js │ ├── ReduxConnect.js │ └── index.js ├── actions │ ├── HOCAction.js │ └── HomePage.js ├── components │ ├── Test │ │ ├── index.js │ │ └── test.scss │ └── index.js ├── constants │ ├── ActionTypes.js │ └── resources.js ├── containers │ ├── App │ │ └── index.js │ └── Home │ │ └── index.js ├── main.js ├── reducers │ ├── HOCReducer.js │ ├── home.js │ └── index.js ├── routes.js └── stylesheets │ ├── _common.scss │ ├── _reset.scss │ ├── _theme.scss │ └── main.scss ├── config.js ├── models └── test.js ├── package.json ├── postcss.config.js ├── public ├── css │ └── style.css ├── index.html └── js │ └── bundle.js ├── secret.js ├── server ├── api │ ├── index.js │ └── root.js ├── bootstrap │ ├── database.js │ ├── launch.js │ ├── requestLimit.js │ ├── routing.js │ ├── sanitizeInput.js │ └── secureSession.js ├── common │ └── utils.js ├── config.js └── index.js ├── view └── index.html └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React-Redux-Node-Mongodb 2 | 3 | ### Introduction 4 | 5 | Setting up a new project can always be challenging and time consuming. 6 | **React-Redux-Node-Mongodb** is an easily customizable template project for starting a new professional project using the following technologies: 7 | 8 | * React 9 | * Redux 10 | * Node 11 | * Mongodb 12 | * Webpack 13 | 14 | ### Requirements 15 | 16 | * Node 17 | * Mongodb 18 | * npm 19 | 20 | ### How to use? 21 | 22 | 1. Simply clone or download the project. 23 | 2. Remove the .git directory (if applicable) 24 | 3. Change the information in the package.json file 25 | 4. Change the content in the secret.js and config.js files (optional but recommended) 26 | 5. Start developing your awesome project 27 | 28 | ### Installment 29 | 30 | 1. run `npm install` 31 | 2. run `npm run connect` to connect to the database 32 | 3. run one of the builds commands to build/rebuild the project 33 | 4. run `npm start` to start the server 34 | 5. visit [localhost:3000](http://localhost:3000) 35 | 36 | ### Builds 37 | 38 | * `npm run build` to make a build from the project, ready for production 39 | * `npm run watch` to make a build from the project and watch over file changes to automatically reload the browser 40 | 41 | ### Some of the included libraries 42 | 43 | * [Axios](https://github.com/axios/axios) 44 | * [Express](https://github.com/expressjs/express) 45 | * [Helmet](https://github.com/helmetjs/helmet) 46 | * [Mongoose](https://github.com/Automattic/mongoose) 47 | * [React-Router](https://github.com/ReactTraining/react-router) 48 | * [Redux-Thunk](https://github.com/gaearon/redux-thunk) -------------------------------------------------------------------------------- /app/HOC/ContainerEnhancer.js: -------------------------------------------------------------------------------- 1 | //Inheritance Inversion HOC 2 | 3 | import * as HOCActions from '../actions/HOCAction'; 4 | import ReduxConnect from './ReduxConnect'; 5 | 6 | export default function (WrappedComponent, actions) { 7 | const Component = ReduxConnect(WrappedComponent, actions); 8 | class Enhancer extends Component { 9 | componentWillUnmount() { 10 | this.props.reset(); 11 | if (super.componentWillUnmount) { 12 | super.componentWillUnmount(); 13 | } 14 | } 15 | } 16 | return ReduxConnect(Enhancer, HOCActions); 17 | } -------------------------------------------------------------------------------- /app/HOC/ReduxConnect.js: -------------------------------------------------------------------------------- 1 | //Props Proxy HOC 2 | 3 | import {connect} from 'react-redux'; 4 | 5 | function mapStateToProps(state) { 6 | return state; 7 | } 8 | 9 | export default function (WrappedComponent, actions) { 10 | return connect(mapStateToProps, actions)(WrappedComponent); 11 | } -------------------------------------------------------------------------------- /app/HOC/index.js: -------------------------------------------------------------------------------- 1 | export {default as ReduxConnect} from './ReduxConnect'; 2 | export {default as ContainerEnhancer} from './ContainerEnhancer'; -------------------------------------------------------------------------------- /app/actions/HOCAction.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | export function reset() { 4 | return { 5 | type: types.RESET 6 | }; 7 | } -------------------------------------------------------------------------------- /app/actions/HomePage.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | import Resources from '../constants/resources'; 3 | 4 | export function test(link) { 5 | return dispatch => { 6 | Resources.request 7 | .get(link) 8 | .then(response => { 9 | dispatch(dispatchTest(response)); 10 | }); 11 | }; 12 | } 13 | 14 | function dispatchTest(data) { 15 | return { 16 | type: types.TEST, 17 | data 18 | }; 19 | } -------------------------------------------------------------------------------- /app/components/Test/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const Test = props => { 5 | 6 | return ( 7 |
8 | Test Component 9 |
10 | ); 11 | }; 12 | 13 | Test.defaultProps = { 14 | }; 15 | 16 | Test.propTypes = { 17 | }; 18 | 19 | export default Test; 20 | -------------------------------------------------------------------------------- /app/components/Test/test.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Amin52J/React-Redux-Node-Mongodb/826deff99f7e1ae514ccddf069e3a9d010c0f40d/app/components/Test/test.scss -------------------------------------------------------------------------------- /app/components/index.js: -------------------------------------------------------------------------------- 1 | export {default as Test} from './Test'; -------------------------------------------------------------------------------- /app/constants/ActionTypes.js: -------------------------------------------------------------------------------- 1 | export const TEST = 'TEST'; 2 | export const RESET = 'RESET'; -------------------------------------------------------------------------------- /app/constants/resources.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import cookie from 'react-cookie'; 3 | 4 | const Resources = { 5 | api: { 6 | test: '/api/test' 7 | }, 8 | cookies: { 9 | user: 'ReactReduxNodeMongodb_user' 10 | }, 11 | }; 12 | 13 | Resources.request = { 14 | post(url, data = {}) { 15 | data.refreshToken = cookie.load(Resources.cookies.user) ? cookie.load(Resources.cookies.user).refreshToken : null; 16 | return axios 17 | .post(url, data); 18 | }, 19 | get(url, data = {}) { 20 | data.refreshToken = cookie.load(Resources.cookies.user) ? cookie.load(Resources.cookies.user).refreshToken : null; 21 | return axios 22 | .get(url, {params: data}); 23 | }, 24 | delete(url, data = {}) { 25 | data.refreshToken = cookie.load(Resources.cookies.user) ? cookie.load(Resources.cookies.user).refreshToken : null; 26 | return axios 27 | .delete(url, {params: data}); 28 | }, 29 | put(url, data = {}) { 30 | data.refreshToken = cookie.load(Resources.cookies.user) ? cookie.load(Resources.cookies.user).refreshToken : null; 31 | return axios 32 | .put(url, data); 33 | } 34 | }; 35 | 36 | export default Resources; 37 | -------------------------------------------------------------------------------- /app/containers/App/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {combineReducers, createStore, applyMiddleware} from 'redux'; 3 | import {Provider} from 'react-redux'; 4 | import thunk from 'redux-thunk'; 5 | import * as reducers from '../../reducers'; 6 | import HOCReducer from '../../reducers/HOCReducer'; 7 | require('isomorphic-fetch'); 8 | 9 | const combinedReducers = combineReducers(reducers); 10 | const reducer = HOCReducer(combinedReducers); 11 | const store = createStore(reducer, applyMiddleware(thunk)); 12 | 13 | export default class App extends React.Component { 14 | constructor(props) { 15 | super(props); 16 | } 17 | 18 | render() { 19 | return ( 20 | 21 |
22 | {this.props.children} 23 |
24 |
25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/containers/Home/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import * as actions from '../../actions/HomePage'; 3 | import {Test} from '../../components'; 4 | import {ContainerEnhancer} from '../../HOC'; 5 | 6 | class Home extends React.Component { 7 | render() { 8 | const {home: {test}} = this.props; 9 | 10 | return ( 11 |
12 | Home Page 13 | 14 |
15 | ); 16 | } 17 | } 18 | 19 | export default ContainerEnhancer(Home, actions); 20 | -------------------------------------------------------------------------------- /app/main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Router, browserHistory} from 'react-router'; 3 | import ReactDOM from 'react-dom'; 4 | import routes from './routes'; 5 | 6 | ReactDOM.render(, document.getElementById('app')); -------------------------------------------------------------------------------- /app/reducers/HOCReducer.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | export default (combinedReducers) => { 4 | return (state, action) => { 5 | switch (action.type){ 6 | case types.RESET: 7 | state = undefined; 8 | break 9 | } 10 | return combinedReducers(state, action); 11 | } 12 | }; -------------------------------------------------------------------------------- /app/reducers/home.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/ActionTypes'; 2 | 3 | const initialState = { 4 | }; 5 | 6 | export default function home(state = initialState, action) { 7 | let newState = JSON.parse(JSON.stringify(state)); 8 | switch (action.type) { 9 | case types.TEST: 10 | return newState; 11 | 12 | default: 13 | return state; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/reducers/index.js: -------------------------------------------------------------------------------- 1 | export {default as home} from './home'; 2 | -------------------------------------------------------------------------------- /app/routes.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Route} from 'react-router'; 3 | 4 | import App from './containers/App'; 5 | import Home from './containers/Home'; 6 | 7 | export default ( 8 | 9 | 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /app/stylesheets/_common.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Amin52J/React-Redux-Node-Mongodb/826deff99f7e1ae514ccddf069e3a9d010c0f40d/app/stylesheets/_common.scss -------------------------------------------------------------------------------- /app/stylesheets/_reset.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, body, div, span, applet, object, iframe, 6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 7 | a, abbr, acronym, address, big, cite, code, 8 | del, dfn, em, img, ins, kbd, q, s, samp, 9 | small, strike, strong, sub, sup, tt, var, 10 | b, u, i, center, 11 | dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, canvas, details, embed, 15 | figure, figcaption, footer, header, hgroup, 16 | menu, nav, output, ruby, section, summary, 17 | time, mark, audio, video { 18 | margin: 0; 19 | padding: 0; 20 | border: 0; 21 | font-size: 100%; 22 | font: inherit; 23 | vertical-align: baseline; 24 | } 25 | 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | 32 | body { 33 | line-height: 1; 34 | } 35 | 36 | ol, ul { 37 | list-style: none; 38 | } 39 | 40 | blockquote, q { 41 | quotes: none; 42 | } 43 | 44 | blockquote:before, blockquote:after, 45 | q:before, q:after { 46 | content: ''; 47 | content: none; 48 | } 49 | 50 | table { 51 | border-collapse: collapse; 52 | border-spacing: 0; 53 | } -------------------------------------------------------------------------------- /app/stylesheets/_theme.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Amin52J/React-Redux-Node-Mongodb/826deff99f7e1ae514ccddf069e3a9d010c0f40d/app/stylesheets/_theme.scss -------------------------------------------------------------------------------- /app/stylesheets/main.scss: -------------------------------------------------------------------------------- 1 | @import "common"; 2 | @import "theme"; 3 | 4 | html { 5 | body { 6 | overflow-x: hidden; 7 | 8 | @import "../components/Test/test"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | database: process.env.MONGO_URI || 'mongodb://localhost/React-Redux-Node-Mongodb' 3 | }; 4 | -------------------------------------------------------------------------------- /models/test.js: -------------------------------------------------------------------------------- 1 | let mongoose = require('mongoose'); 2 | 3 | let TestSchema = new mongoose.Schema({ 4 | test: {type: String, required: true} 5 | }); 6 | 7 | module.exports = mongoose.model('Test', TestSchema); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-node-mongodb", 3 | "version": "2.2.0", 4 | "scripts": { 5 | "start": "nodemon ./server/index.js", 6 | "watch": "webpack --watch", 7 | "build": "NODE_ENV=production webpack", 8 | "connect": "sudo mongod", 9 | "db-list": "ps wuax | grep mongo" 10 | }, 11 | "nodemonConfig": { 12 | "ignore": [ 13 | "app/*", 14 | "public/*" 15 | ] 16 | }, 17 | "babel": { 18 | "presets": [ 19 | "es2015", 20 | "react" 21 | ] 22 | }, 23 | "dependencies": { 24 | "axios": "^0.19.0", 25 | "body-parser": "^1.14.1", 26 | "connect-mongo": "^1.3.2", 27 | "cookie-parser": "^1.4.3", 28 | "create-file": "^1.0.1", 29 | "csurf": "^1.9.0", 30 | "express": "^4.13.3", 31 | "express-rate-limit": "^2.6.0", 32 | "express-session": "^1.7.6", 33 | "file-system": "^2.2.2", 34 | "helmet": "^3.4.0", 35 | "jsonwebtoken": "^7.3.0", 36 | "mongo-sanitize": "^1.0.0", 37 | "mongoose": "^5.7.7", 38 | "morgan": "^1.6.1", 39 | "mustache": "^2.3.0", 40 | "path": "^0.12.7", 41 | "prompt": "^1.0.0", 42 | "prop-types": "^15.5.10", 43 | "react": "^15.4.1", 44 | "react-cookie": "^1.0.4", 45 | "react-dom": "^15.4.1", 46 | "react-redux": "^5.0.4", 47 | "react-router": "^3.0.0", 48 | "redux": "^3.6.0", 49 | "redux-thunk": "^2.2.0", 50 | "request": "^2.65.0", 51 | "serve-favicon": "^2.3.0" 52 | }, 53 | "devDependencies": { 54 | "babel-core": "^6.26.0", 55 | "babel-loader": "^7.1.2", 56 | "babel-preset-es2015": "^6.24.1", 57 | "babel-preset-react": "^6.24.1", 58 | "babel-register": "^6.3.13", 59 | "copy-webpack-plugin": "^4.0.1", 60 | "css-loader": "^0.28.5", 61 | "eslint": "^4.6.0", 62 | "eslint-plugin-react": "^7.3.0", 63 | "extract-text-webpack-plugin": "^3.0.0", 64 | "isomorphic-fetch": "^2.2.1", 65 | "json-loader": "^0.5.7", 66 | "node-sass": "^4.5.3", 67 | "nodemon": "^1.11.0", 68 | "path": "^0.12.7", 69 | "postcss-loader": "^2.0.6", 70 | "sass-loader": "^6.0.6", 71 | "url-loader": "^0.5.9", 72 | "vinyl-buffer": "^1.0.0", 73 | "vinyl-source-stream": "^1.1.0", 74 | "webpack": "^3.5.5" 75 | }, 76 | "license": "MIT", 77 | "author": "Amin Jafari" 78 | } 79 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('autoprefixer') 4 | ] 5 | } -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | html body{overflow-x:hidden} 2 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-Redux-Node-Mongodb 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /secret.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | limit: { 3 | api: { 4 | windowMs: 60 * 60 * 1000, //1 hour 5 | max: 150, //150 requests 6 | } 7 | }, 8 | session: { 9 | secret: 'React-Redux-Node-Mongodb_Security_Secret', //secret for app session 10 | name: 'React-Redux-Node-Mongodb', //name of the app session 11 | ttl: 30 * 24 * 60 * 60, //store sessions for a month, 12 | touchAfter: 24 * 3600 //re-save sessions every 24 hours 13 | }, 14 | superSecret: 'React-Redux-Node-Mongodb_Super_Secret_Security_Secret' 15 | }; -------------------------------------------------------------------------------- /server/api/index.js: -------------------------------------------------------------------------------- 1 | const Resources = require('../../app/constants/resources').default; 2 | const api = { 3 | root: require('./root') 4 | }; 5 | 6 | module.exports = (app) => { 7 | /** 8 | * Test 9 | */ 10 | app.post(Resources.api.test, (req, res) => { 11 | api.root.post.test(req, res, app.get('superSecret')); 12 | }); 13 | }; -------------------------------------------------------------------------------- /server/api/root.js: -------------------------------------------------------------------------------- 1 | let Test = require('../../models/test'); 2 | 3 | module.exports = { 4 | post: { 5 | test(req, res, secret) { 6 | 7 | } 8 | }, 9 | get: {}, 10 | put: {}, 11 | delete: {}, 12 | options: {} 13 | }; -------------------------------------------------------------------------------- /server/bootstrap/database.js: -------------------------------------------------------------------------------- 1 | let mongoose = require('mongoose'); 2 | let config = require('../../config'); 3 | 4 | module.exports = () => { 5 | mongoose.connect(config.database, { 6 | useMongoClient: true 7 | }); 8 | mongoose.connection.on('error', function () { 9 | console.info('Connection error! Have you executed mongod?'); 10 | }); 11 | 12 | return { 13 | connection: mongoose.connection 14 | } 15 | }; -------------------------------------------------------------------------------- /server/bootstrap/launch.js: -------------------------------------------------------------------------------- 1 | module.exports = (app) => { 2 | app.listen(app.get('port'), function () { 3 | console.log('Express server listening on port ' + app.get('port')); 4 | }); 5 | }; -------------------------------------------------------------------------------- /server/bootstrap/requestLimit.js: -------------------------------------------------------------------------------- 1 | const RateLimit = require('express-rate-limit'); 2 | const secret = require('../../secret'); 3 | const serverConfig = require('../config'); 4 | 5 | module.exports = (app) => { 6 | app.use(serverConfig.apiRoute, new RateLimit({ 7 | windowMs: secret.limit.api.windowMs, 8 | max: secret.limit.api.max, 9 | delayMs: 0 10 | })); 11 | }; -------------------------------------------------------------------------------- /server/bootstrap/routing.js: -------------------------------------------------------------------------------- 1 | const Router = require('react-router'); 2 | const routes = require('../../app/routes'); 3 | const reactCookie = require('react-cookie'); 4 | const ReactDOM = require('react-dom/server'); 5 | const React = require('react'); 6 | const fs = require('fs'); 7 | const Mustache = require('mustache'); 8 | const serverConfig = require('../config'); 9 | 10 | module.exports = (app) => { 11 | app.use(function (req, res) { 12 | Router.match({routes: routes.default, location: req.url}, function (err, redirectLocation, renderProps) { 13 | reactCookie.plugToRequest(req, res); 14 | if (err) { 15 | res.status(500).send(err.message) 16 | } else if (redirectLocation) { 17 | res.status(302).redirect(redirectLocation.pathname + redirectLocation.search) 18 | } else if (renderProps) { 19 | const html = ReactDOM.renderToString(React.createElement(Router.RouterContext, renderProps)); 20 | fs.readFile(serverConfig.indexRoute, function (err, data) { 21 | if (err) throw err; 22 | const page = Mustache.render(data.toString(), {html: html}); 23 | res.status(200).send(page); 24 | }); 25 | } else { 26 | res.status(404).send('Page Not Found') 27 | } 28 | }); 29 | }); 30 | }; -------------------------------------------------------------------------------- /server/bootstrap/sanitizeInput.js: -------------------------------------------------------------------------------- 1 | const sanitize = require('mongo-sanitize'); 2 | 3 | module.exports = (app) => { 4 | app.use(function (req, res, next) { 5 | req.body = sanitize(req.body); 6 | req.query = sanitize(req.query); 7 | req.params = sanitize(req.params); 8 | next(); 9 | }); 10 | }; -------------------------------------------------------------------------------- /server/bootstrap/secureSession.js: -------------------------------------------------------------------------------- 1 | const session = require('express-session'); 2 | const MongoStore = require('connect-mongo')(session); 3 | const secret = require('../../secret'); 4 | 5 | module.exports = (app, db) => { 6 | app.use(session({ 7 | secret: secret.session.secret, 8 | name: secret.session.name, 9 | saveUninitialized: false, //don't start a session before anything is changed 10 | httpOnly: true, //only allow http[s] requests to access sessions 11 | resave: false, //don't save any session unless something is changed 12 | store: new MongoStore({ //where to save the sessions 13 | mongooseConnection: db.connection, //database connection 14 | ttl: secret.session.ttl, 15 | touchAfter: secret.session.touchAfter 16 | }) 17 | } 18 | )); 19 | }; -------------------------------------------------------------------------------- /server/common/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; -------------------------------------------------------------------------------- /server/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 3000, 3 | apiRoute: '/api', 4 | serverRoute: '/server', 5 | publicRoute: 'public', 6 | indexRoute: 'views/index.html' 7 | }; -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | require('babel-core/register'); 2 | 3 | const path = require('path'); 4 | const express = require('express'); 5 | const logger = require('morgan'); 6 | const bodyParser = require('body-parser'); 7 | const helmet = require('helmet'); 8 | const reload = require('reload'); 9 | const cookieParser = require('cookie-parser'); 10 | 11 | const config = require('../config'); 12 | const secret = require('../secret'); 13 | const utils = require('./common/utils'); 14 | const serverConfig = require('./config'); 15 | 16 | const database = require('./bootstrap/database'); 17 | const requestLimit = require('./bootstrap/requestLimit'); 18 | const secureSession = require('./bootstrap/secureSession'); 19 | const sanitizeInput = require('./bootstrap/sanitizeInput'); 20 | const routing = require('./bootstrap/routing'); 21 | const launch = require('./bootstrap/launch'); 22 | const api = require('./api'); 23 | 24 | //bootstrap database 25 | const db = database(); 26 | 27 | const app = express(); 28 | 29 | app.set('port', process.env.PORT || serverConfig.port); 30 | app.set('superSecret', secret.superSecret); 31 | 32 | //limit the number of request 33 | requestLimit(app); 34 | 35 | //secure session and cookies 36 | secureSession(app, db); 37 | 38 | //sanitize input 39 | sanitizeInput(app); 40 | 41 | //secure HTTP Headers 42 | app.use(helmet()); 43 | 44 | app.use(logger('dev')); 45 | app.use(bodyParser.json()); 46 | app.use(bodyParser.urlencoded({extended: false})); 47 | app.use(cookieParser()); 48 | app.use(express.static(path.join(__dirname.replace(serverConfig.serverRoute, ''), serverConfig.publicRoute))); 49 | 50 | const apiRoutes = express.Router(); 51 | app.use(serverConfig.apiRoute, apiRoutes); 52 | 53 | //initialize the api 54 | api(app); 55 | 56 | //setup routing 57 | routing(app); 58 | 59 | //launch the server 60 | launch(app); -------------------------------------------------------------------------------- /view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-Redux-Node-Mongodb 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | const webpack = require('webpack'); 5 | 6 | 7 | var plugins = [ 8 | new CopyWebpackPlugin([{from: 'view'}]), 9 | new ExtractTextPlugin('css/style.css'), 10 | new webpack.LoaderOptionsPlugin({ 11 | minimize: true 12 | }), 13 | new webpack.DefinePlugin({ 14 | 'process.env': { 15 | NODE_ENV: JSON.stringify(process.env.NODE_ENV) 16 | } 17 | }) 18 | ]; 19 | 20 | if (process.env.NODE_ENV === 'production') { 21 | plugins.push(new webpack.optimize.UglifyJsPlugin()); 22 | } 23 | 24 | module.exports = { 25 | entry: { 26 | 'js/bundle.js': path.resolve(__dirname, 'app/main.js'), 27 | 'css/style.css': path.resolve(__dirname, 'app/stylesheets/main.scss') 28 | }, 29 | output: { 30 | path: path.resolve(__dirname, 'public'), 31 | filename: '[name]' 32 | }, 33 | module: { 34 | rules: [{ 35 | exclude: /(node_modules)/, 36 | test: /\.js$/, 37 | loader: 'babel-loader', 38 | query: { 39 | presets: ['react'] 40 | } 41 | }, { 42 | test: /\.scss$/, 43 | loader: ExtractTextPlugin.extract(['css-loader?-minimize', 'postcss-loader', 'sass-loader']) 44 | }, { 45 | test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, 46 | loader: 'url-loader' 47 | }, { 48 | test: /\.json$/, 49 | loader: 'json-loader' 50 | }] 51 | }, 52 | stats: { 53 | colors: true 54 | }, 55 | plugins: plugins 56 | }; 57 | --------------------------------------------------------------------------------