├── .eslintignore ├── .gitignore ├── src ├── client │ └── jsguild.js ├── components │ └── jsguild-home │ │ └── jsguild-home.jsx ├── helpers │ └── html.js └── server.js ├── .eslintrc ├── .stylelintrc.js ├── README.md ├── webpack ├── webpack.server.config.js └── webpack.browser.config.js └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | src/vendors 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | build/ 4 | static/baseUrl.js 5 | config/config.js 6 | src/stats.json 7 | dist/ 8 | .vscode 9 | npm-debug* 10 | -------------------------------------------------------------------------------- /src/client/jsguild.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | import '../vendors/semantic.min.js'; 3 | 4 | $(document).ready(function() { 5 | $('.ui.dropdown').dropdown(); 6 | alert('Dom is ready!'); 7 | }); 8 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "id-length": 0, 5 | "func-names": 0, 6 | "no-dupe-keys": 0, 7 | "react/no-did-mount-set-state": 0, 8 | "no-unused-expressions": 0, 9 | "no-else-return": 0, 10 | "react/prop-types": 0, 11 | "no-fallthrough": 0, 12 | "guard-for-in": 0, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'rules': { 3 | 'declaration-block-no-single-line': true, 4 | 'declaration-block-single-line-max-declarations': 1, 5 | 'selector-class-pattern': '^(?!js-).*', 6 | 'string-quotes': 'double', 7 | 'declaration-block-semicolon-newline-after': 'always', 8 | 'block-closing-brace-newline-after': 'always', 9 | 'block-closing-brace-newline-before': 'always', 10 | 'color-hex-case': 'lower', 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/jsguild-home/jsguild-home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import '../../client/jsguild.js'; 5 | 6 | export default class HomeContainer extends React.Component { 7 | constructor() { 8 | super(); 9 | } 10 | 11 | componentDidMount() { 12 | 13 | } 14 | 15 | render() { 16 | return ( 17 |
18 |

Hello World from maincontainer!

19 |
20 | ); 21 | } 22 | } 23 | 24 | ReactDOM.render( 25 | , 26 | document.getElementById('maincontainer') 27 | ); 28 | -------------------------------------------------------------------------------- /src/helpers/html.js: -------------------------------------------------------------------------------- 1 | import stats from '../stats.json'; 2 | 3 | let jsGuildHomeSrc = stats.jsGuildHome.split('/'); 4 | jsGuildHomeSrc = jsGuildHomeSrc[jsGuildHomeSrc.length - 1]; 5 | let vendorsSrc = stats.vendors.split('/'); 6 | vendorsSrc = vendorsSrc[vendorsSrc.length - 1]; 7 | 8 | export function renderHomePage() { 9 | return ` 10 | 11 | 12 | 13 | JS Guild 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | `; 24 | } 25 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | import config from '../config/config.js'; 2 | 3 | // Create express app 4 | import express from 'express'; 5 | const app = express(); 6 | 7 | // Adding caching for 30 days 8 | const cacheTime = 86400000 * 30; 9 | 10 | app.use('/js/?', express.static(__dirname + '/../build/js', { maxAge: cacheTime })); 11 | app.use('/css/?', express.static(__dirname + '/../dist/css')); 12 | app.use('/css/?', express.static(__dirname + '/../src/static/css')); 13 | app.use('/js/?', express.static(__dirname + '/../src/static/js', { maxAge: cacheTime })); 14 | app.use('/js/?', express.static(__dirname + '/../src/vendors', { maxAge: cacheTime })); 15 | app.use('/fonts/?', express.static(__dirname + '/../src/static/fonts', { maxAge: cacheTime })); 16 | app.use('/images/?', express.static(__dirname + '/../src/static/images', { maxAge: cacheTime })); 17 | 18 | import { renderHomePage } from './helpers/html.js'; 19 | 20 | app.get('/', function(req, res) { 21 | res.send(renderHomePage()); 22 | }); 23 | 24 | const port = process.env.PORT || config.serverPort; 25 | app.listen(port, function() { 26 | console.log('Listening on ' + port); 27 | }); 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Boilerplate 2 | 3 | SPA build with: 4 | * Express server 5 | * ReactJs as view library 6 | * Webpack as module bundler 7 | 8 | ###Setting up the project 9 | 10 | * Install nvm 11 | ``` 12 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash 13 | ``` 14 | 15 | * Install required node version 16 | ``` 17 | nvm install 4.4.0 18 | ``` 19 | 20 | * Install the `webpack` command for the terminal. 21 | ``` 22 | npm install -g webpack 23 | ``` 24 | 25 | * Install all the node packages 26 | ``` 27 | npm install 28 | ``` 29 | 30 | * Install pm2 31 | ``` 32 | npm install pm2 -g 33 | ``` 34 | 35 | ###Deploying 36 | 37 | * For devs 38 | 39 | First Time 40 | ``` 41 | npm run build && pm2 start dist/main.js 42 | ``` 43 | 44 | Next times - It will automatically start a local server and open the localhost. 45 | ``` 46 | npm run serve 47 | ``` 48 | 49 | * For production 50 | ``` 51 | npm run serve-prod 52 | ``` 53 | 54 | ### Nginix config 55 | 56 | ```server { 57 | set $server_uri 127.0.0.1:8142; 58 | server_name jsguild.practo.local; 59 | listen 80; 60 | 61 | access_log /var/log/nginx/app.access.log; 62 | error_log /var/log/nginx/app.error.log; 63 | location = /robots.txt { 64 | echo "User-agent: *\nDisallow: /\n"; 65 | } 66 | location / { 67 | proxy_pass http://$server_uri; 68 | include proxy_params; 69 | } 70 | }``` 71 | -------------------------------------------------------------------------------- /webpack/webpack.server.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | 5 | var nodeModules = {}; 6 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 7 | 8 | fs.readdirSync('node_modules') 9 | .filter(function(x) { 10 | return ['.bin'].indexOf(x) === -1; 11 | }) 12 | .forEach(function(mod) { 13 | nodeModules[mod] = 'commonjs ' + mod; 14 | }); 15 | 16 | 17 | module.exports = 18 | { 19 | name: 'server', 20 | target: 'node', 21 | entry: './src/server.js', 22 | output: { 23 | path: './dist/', 24 | publicPath: 'dist/', 25 | filename: "[name].js", 26 | }, 27 | node: { 28 | __dirname: false, 29 | }, 30 | externals: nodeModules, 31 | module: { 32 | preLoaders: [{ 33 | test: /(\.js$|\.jsx$)/, 34 | exclude: /node_modules/, 35 | loader: "eslint-loader" 36 | }, 37 | { test: /\.(sass|scss)$/, loader: 'stylelint' } 38 | ], 39 | loaders: [ 40 | { 41 | test: /(\.js$|\.jsx$)/, 42 | exclude: /node_modules/, 43 | loader: "babel-loader", 44 | },{ 45 | test: /\.json?$/, 46 | exclude: /node_modules/, 47 | loader: "json-loader", 48 | },{ 49 | test: /\.scss$/, 50 | exclude: /node_modules/, 51 | loader: ExtractTextPlugin.extract( 52 | "style", 53 | "css!sass" 54 | ) 55 | },{ 56 | test: /\.css$/, 57 | exclude: /node_modules/, 58 | loader: ExtractTextPlugin.extract( 59 | "style-loader", 60 | "css-loader" 61 | ) 62 | },{ 63 | test: /\.(ttf|eot|woff(2)?)(\?[a-z0-9]+)?$/, exclude: /node_modules/, 64 | exclude: /node_modules/, 65 | loader : 'file-loader' 66 | },{ 67 | test: /\.(png|jpg|svg)$/, 68 | exclude: /node_modules/, 69 | loader: 'url-loader?limit=8192' 70 | } 71 | ] 72 | }, 73 | stylelint: { 74 | configFile: path.join(__dirname, '../.stylelintrc.js'), 75 | }, 76 | plugins: [ 77 | new ExtractTextPlugin('css/[name].css', {allChunks: false}), 78 | ] 79 | }; 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsguild", 3 | "version": "1.0.0", 4 | "description": "Application to host all JS Guild stuff @ practo", 5 | "main": "index.js", 6 | "scripts": { 7 | "eslint": "./node_modules/.bin/eslint --config=.eslintrc ./src/**/.jsx", 8 | "build": "npm run webpack-client-build && npm run webpack-server-build", 9 | "webpack-server-build": "rm -rf ./dist/* && ./node_modules/webpack/bin/webpack.js --config ./webpack/webpack.server.config.js", 10 | "webpack-client-build": "./node_modules/webpack/bin/webpack.js --config ./webpack/webpack.browser.config.js", 11 | "serve": "npm run build && pm2 stop all && pm2 start ./dist/main.js", 12 | "build-prod": "npm run webpack-client-build-prod && npm run webpack-server-build-prod", 13 | "webpack-server-build-prod": "rm -rf ./dist/* && ./node_modules/webpack/bin/webpack.js --config ./webpack/webpack.server.config.js -p", 14 | "webpack-client-build-prod": "./node_modules/webpack/bin/webpack.js --config ./webpack/webpack.browser.config.js -p", 15 | "serve-prod": "npm run build-prod && pm2 stop all && pm2 start ./dist/main.js" 16 | }, 17 | "keywords": [ 18 | "guild", 19 | "javascript", 20 | "js", 21 | "libraries" 22 | ], 23 | "author": "Arpit Bhayani", 24 | "license": "ISC", 25 | "dependencies": { 26 | "express": "^4.13.4", 27 | "extract-text-webpack-plugin": "^1.0.1", 28 | "history": "^2.0.1", 29 | "jquery": "^2.2.2", 30 | "json-loader": "^0.5.4", 31 | "raw-loader": "^0.5.1", 32 | "react": "^0.14.7", 33 | "react-dom": "^0.14.7", 34 | "react-router": "^2.0.1", 35 | "superagent": "^1.8.1" 36 | }, 37 | "devDependencies": { 38 | "babel-core": "^5.8.25", 39 | "babel-eslint": "^4.1.3", 40 | "babel-loader": "^5.3.2", 41 | "chalk": "^1.1.1", 42 | "clean-webpack-plugin": "^0.1.8", 43 | "css-loader": "^0.20.1", 44 | "eslint": "^1.7.3", 45 | "eslint-config-airbnb": "^0.1.0", 46 | "eslint-loader": "^1.1.0", 47 | "eslint-plugin-react": "^3.6.3", 48 | "file-loader": "^0.8.4", 49 | "imports-loader": "^0.6.5", 50 | "node-sass": "^3.3.3", 51 | "sass-loader": "^3.0.0", 52 | "style-loader": "^0.13.0", 53 | "stylelint": "^4.2.0", 54 | "stylelint-loader": "^0.2.0", 55 | "url-loader": "^0.5.6", 56 | "webpack": "^1.12.2" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /webpack/webpack.browser.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | var CleanWebpackPlugin = require('clean-webpack-plugin'); 4 | module.exports = { 5 | name: "client", 6 | entry: { 7 | jsGuildHome: "./src/components/jsguild-home/jsguild-home.jsx", 8 | vendors: [ 9 | 'react', 10 | 'react-dom', 11 | 'react-router', 12 | 'history' 13 | ] 14 | }, 15 | output: { 16 | filename: "./js/[name]-[chunkhash].js", 17 | path: "build", 18 | }, 19 | module: { 20 | preLoaders: [{ 21 | test: /(\.js$|\.jsx$)/, 22 | exclude: /node_modules/, 23 | loader: "eslint-loader" 24 | } 25 | ], 26 | loaders : [ 27 | { 28 | test: /vendors\/.+\.(jsx|js)$/, 29 | loader: 'imports?jQuery=jquery,$=jquery,this=>window' 30 | }, 31 | { 32 | test: /client\/.+\.(jsx|js)$/, 33 | loader: 'imports?jQuery=jquery,$=jquery,this=>window' 34 | }, 35 | { 36 | test: /(\.js$|\.jsx$)/, 37 | exclude: /node_modules/, 38 | loader: "babel-loader", 39 | },{ 40 | test: /\.json?$/, 41 | exclude: /node_modules/, 42 | loader: "json-loader", 43 | },{ 44 | test: /\.scss?$/, 45 | exclude: /node_modules/, 46 | loaders: ["style", "css", "sass"], 47 | },{ 48 | test: /\.css$/, 49 | exclude: /node_modules/, 50 | loader: 'style-loader!css-loader' 51 | },{ 52 | test: /\.(png|jpg|svg)$/, 53 | exclude: /node_modules/, 54 | loader: 'url-loader?limit=8192' 55 | },{ 56 | test : /\.(ttf|eot|woff(2)?)(\?[a-z0-9]+)?$/, 57 | exclude: /node_modules/, 58 | loader : 'file-loader' 59 | } 60 | ] 61 | }, 62 | eslint: { 63 | configFile: '.eslintrc' 64 | }, 65 | plugins: [ 66 | new webpack.optimize.CommonsChunkPlugin('vendors', './js/vendors-[chunkhash].js', Infinity), 67 | function() { 68 | this.plugin("done", function(stats) { 69 | require("fs").writeFileSync( 70 | path.join(__dirname, "..", "src", "stats.json"), 71 | JSON.stringify(stats.toJson().assetsByChunkName)); 72 | }); 73 | }, 74 | new CleanWebpackPlugin(['dist', 'build'], { 75 | verbose: true, 76 | dry: false, 77 | root: path.join(__dirname, '..'), 78 | }) 79 | ] 80 | } 81 | --------------------------------------------------------------------------------