├── .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 |
--------------------------------------------------------------------------------