├── app ├── README.md ├── src │ ├── web │ │ ├── index.js │ │ └── __tests__ │ │ │ └── index.spec.js │ └── server │ │ ├── index.js │ │ └── app.js ├── .gitignore ├── .npmignore ├── configs │ ├── config.json │ └── webpack.config.js ├── .travis.yml ├── .babelrc ├── build │ ├── server │ │ ├── index.js │ │ └── app.js │ └── web │ │ └── app.js ├── .eslintrc.json ├── scripts │ ├── start.js │ └── dev.js ├── LICENSE.md └── package.json ├── node ├── README.md ├── src │ ├── index.js │ └── __tests__ │ │ └── index.spec.js ├── .gitignore ├── .npmignore ├── .travis.yml ├── .babelrc ├── .eslintrc ├── package.json └── LICENSE.md └── react ├── README.md ├── src ├── index.js └── __tests__ │ └── index.spec.js ├── .gitignore ├── .npmignore ├── .travis.yml ├── .babelrc ├── .eslintrc ├── package.json └── LICENSE.md /app/README.md: -------------------------------------------------------------------------------- 1 | # boilerplate -- node 2 | -------------------------------------------------------------------------------- /node/README.md: -------------------------------------------------------------------------------- 1 | # boilerplate -- node 2 | -------------------------------------------------------------------------------- /react/README.md: -------------------------------------------------------------------------------- 1 | # boilerplate -- node 2 | -------------------------------------------------------------------------------- /node/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'Hello'; 2 | -------------------------------------------------------------------------------- /react/src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'Hello'; 2 | -------------------------------------------------------------------------------- /app/src/web/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'Hello'; 2 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.json 3 | lib/ 4 | -------------------------------------------------------------------------------- /node/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.json 3 | lib/ 4 | -------------------------------------------------------------------------------- /react/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.json 3 | lib/ 4 | -------------------------------------------------------------------------------- /app/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.json 3 | lib/**/__tests__ 4 | src/ 5 | -------------------------------------------------------------------------------- /node/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.json 3 | lib/**/__tests__ 4 | src/ 5 | -------------------------------------------------------------------------------- /react/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.json 3 | lib/**/__tests__ 4 | src/ 5 | -------------------------------------------------------------------------------- /app/configs/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": { 3 | "port": 8080 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | - "6" 5 | - "4" 6 | -------------------------------------------------------------------------------- /node/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | - "6" 5 | - "4" 6 | -------------------------------------------------------------------------------- /react/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | - "6" 5 | - "4" 6 | -------------------------------------------------------------------------------- /app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "es2015" ], 3 | "plugins": [ "transform-async-to-generator" ] 4 | } 5 | -------------------------------------------------------------------------------- /node/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "es2015" ], 3 | "plugins": ["transform-async-to-generator"] 4 | } 5 | -------------------------------------------------------------------------------- /react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ "es2015" ], 3 | "plugins": ["transform-async-to-generator"] 4 | } 5 | -------------------------------------------------------------------------------- /app/src/server/index.js: -------------------------------------------------------------------------------- 1 | require('babel-polyfill') 2 | 3 | const main = require('./app') 4 | 5 | module.exports = main 6 | 7 | if (module === require.main) { 8 | main() 9 | } 10 | -------------------------------------------------------------------------------- /app/src/web/__tests__/index.spec.js: -------------------------------------------------------------------------------- 1 | const msg = require('../index'); 2 | 3 | describe('index', () => { 4 | it('should be "Hello"', () => { 5 | expect(msg).toBe('Hello'); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /node/src/__tests__/index.spec.js: -------------------------------------------------------------------------------- 1 | const msg = require('../index'); 2 | 3 | describe('index', () => { 4 | it('should be "Hello"', () => { 5 | expect(msg).toBe('Hello'); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /react/src/__tests__/index.spec.js: -------------------------------------------------------------------------------- 1 | const msg = require('../index'); 2 | 3 | describe('index', () => { 4 | it('should be "Hello"', () => { 5 | expect(msg).toBe('Hello'); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /react/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "globals": { 4 | "expect": true, 5 | "it": true, 6 | "describe": true, 7 | "beforeEach": true, 8 | "jest": true 9 | }, 10 | "rules": { 11 | "no-underscore-dangle": 0, 12 | "comma-dangle": 0 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /node/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/base", 3 | "globals": { 4 | "expect": true, 5 | "it": true, 6 | "describe": true, 7 | "beforeEach": true, 8 | "jest": true 9 | }, 10 | "rules": { 11 | "no-underscore-dangle": 0, 12 | "comma-dangle": 0 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/build/server/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('babel-polyfill'); 4 | 5 | var main = require('./app'); 6 | 7 | module.exports = function () { 8 | setTimeout(function () { 9 | throw 'err'; 10 | }, 3000); 11 | main(); 12 | }; 13 | 14 | if (module === require.main) { 15 | main(); 16 | } -------------------------------------------------------------------------------- /app/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "globals": { 4 | "expect": true, 5 | "it": true, 6 | "describe": true, 7 | "beforeEach": true, 8 | "jest": true 9 | }, 10 | "rules": { 11 | "no-underscore-dangle": 0, 12 | "comma-dangle": 0, 13 | "semi": [ 2, "never" ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/configs/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | function relative(p) { 4 | return path.resolve(__dirname, p) 5 | } 6 | 7 | module.exports = { 8 | entry: { 9 | app: relative('../src/web/index.js'), 10 | }, 11 | output: { 12 | path: relative('../build/web'), 13 | filename: '[name].js' 14 | }, 15 | module: { 16 | rules: [{ 17 | test: /.js&/, 18 | loader: 'babel', 19 | }] 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /app/src/server/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | 3 | function main() { 4 | const app = express() 5 | 6 | app.use('/', (req, res) => { 7 | res.send('Hello!') 8 | }) 9 | 10 | // NOTE: async/await also works 11 | // app.use('/', async (req, res, next) => { 12 | // await next() 13 | // }) 14 | 15 | app.listen(8080, () => { 16 | // eslint-disable-next-line 17 | console.log(`listen ${8080}`) 18 | }) 19 | } 20 | 21 | module.exports = main 22 | -------------------------------------------------------------------------------- /app/build/server/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | 5 | function main() { 6 | var app = express(); 7 | 8 | app.use('/', function (req, res) { 9 | res.send('Hello!'); 10 | }); 11 | 12 | // NOTE: async/await also works 13 | // app.use('/', async (req, res, next) => { 14 | // await next() 15 | // }) 16 | 17 | app.listen(8080, function () { 18 | // eslint-disable-next-line 19 | console.log('listen ' + 8080); 20 | }); 21 | } 22 | 23 | module.exports = main; -------------------------------------------------------------------------------- /app/scripts/start.js: -------------------------------------------------------------------------------- 1 | const cluster = require('cluster') 2 | const cpuNumber = require('os').cpus().length 3 | 4 | const main = require('../build/server/index') 5 | 6 | 7 | if (cluster.isMaster) { 8 | const childs = {} 9 | 10 | // eslint-disable-next-line 11 | function createChild() { 12 | const child = cluster.fork() 13 | 14 | childs[child.pid] = child 15 | 16 | child.on('exit', () => { 17 | delete childs[child.pid] 18 | createChild() 19 | }) 20 | } 21 | 22 | for (let i = 0; i < cpuNumber; i += 1) { 23 | createChild() 24 | } 25 | } else { 26 | main() 27 | } 28 | -------------------------------------------------------------------------------- /node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boilerplate_node", 3 | "version": "1.0.0", 4 | "description": "", 5 | "repository": { 6 | "type" : "git", 7 | "url" : "" 8 | }, 9 | "scripts": { 10 | "build": "babel src --out-dir lib", 11 | "dev": "jest --watch", 12 | "test": "eslint src && jest" 13 | }, 14 | "keywords": [ 15 | ], 16 | "bin": { 17 | }, 18 | "author": "oyyd ", 19 | "license": "MIT", 20 | "dependencies": { 21 | }, 22 | "devDependencies": { 23 | "babel-jest": "^18.0.0", 24 | "babel-plugin-transform-async-to-generator": "^6.22.0", 25 | "babel-polyfill": "^6.22.0", 26 | "babel-preset-es2015": "^6.18.0", 27 | "eslint": "^3.13.1", 28 | "eslint-config-airbnb": "^14.0.0", 29 | "eslint-config-airbnb-base": "^11.0.1", 30 | "eslint-plugin-import": "^2.2.0", 31 | "jest": "^18.1.0" 32 | }, 33 | "jest": { 34 | "testPathDirs": [ 35 | "/src" 36 | ], 37 | "testRegex": "(\\.|/)(test|spec)\\.js$" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boilerplate_node", 3 | "version": "1.0.0", 4 | "description": "", 5 | "repository": { 6 | "type": "git", 7 | "url": "" 8 | }, 9 | "scripts": { 10 | "build": "babel src --out-dir lib", 11 | "dev": "jest --watch", 12 | "test": "eslint src && jest" 13 | }, 14 | "keywords": [], 15 | "bin": {}, 16 | "author": "oyyd ", 17 | "license": "MIT", 18 | "dependencies": {}, 19 | "devDependencies": { 20 | "babel-jest": "^18.0.0", 21 | "babel-plugin-transform-async-to-generator": "^6.22.0", 22 | "babel-polyfill": "^6.22.0", 23 | "babel-preset-es2015": "^6.18.0", 24 | "eslint": "^3.13.1", 25 | "eslint-config-airbnb": "^14.0.0", 26 | "eslint-config-airbnb-base": "^11.0.1", 27 | "eslint-plugin-import": "^2.2.0", 28 | "eslint-plugin-jsx-a11y": "^4.0.0", 29 | "eslint-plugin-react": "^6.9.0", 30 | "jest": "^18.1.0" 31 | }, 32 | "jest": { 33 | "testPathDirs": [ 34 | "/src" 35 | ], 36 | "testRegex": "(\\.|/)(test|spec)\\.js$" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-present Ouyang Yadong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /node/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-present Ouyang Yadong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /react/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-present Ouyang Yadong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boilerplate_node", 3 | "version": "1.0.0", 4 | "description": "", 5 | "repository": { 6 | "type": "git", 7 | "url": "" 8 | }, 9 | "scripts": { 10 | "build": "NODE_ENV=production webpack --config configs/webpack.config.js && babel src/server --out-dir build/server", 11 | "dev": "node scripts/dev.js", 12 | "start": "node scripts/start.js", 13 | "test": "jest" 14 | }, 15 | "keywords": [], 16 | "bin": {}, 17 | "author": "oyyd ", 18 | "license": "MIT", 19 | "dependencies": { 20 | "babel-polyfill": "^6.22.0", 21 | "chokidar": "^1.6.1", 22 | "express": "^4.14.1" 23 | }, 24 | "devDependencies": { 25 | "babel-cli": "^6.22.2", 26 | "babel-jest": "^18.0.0", 27 | "babel-plugin-transform-async-to-generator": "^6.22.0", 28 | "babel-polyfill": "^6.22.0", 29 | "babel-preset-es2015": "^6.18.0", 30 | "eslint": "^3.13.1", 31 | "eslint-config-airbnb": "^14.0.0", 32 | "eslint-config-airbnb-base": "^11.0.1", 33 | "eslint-plugin-import": "^2.2.0", 34 | "eslint-plugin-jsx-a11y": "^4.0.0", 35 | "eslint-plugin-react": "^6.9.0", 36 | "jest": "^18.1.0", 37 | "webpack": "^2.2.1" 38 | }, 39 | "jest": { 40 | "testPathDirs": [ 41 | "/src" 42 | ], 43 | "testRegex": "(\\.|/)(test|spec)\\.js$" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/scripts/dev.js: -------------------------------------------------------------------------------- 1 | const chokidar = require('chokidar') 2 | const path = require('path') 3 | const { exec } = require('child_process') 4 | 5 | function relative(p) { 6 | return path.resolve(__dirname, p) 7 | } 8 | 9 | function run(cmd) { 10 | return new Promise((resolve, reject) => { 11 | process.nextTick(() => { 12 | const child = exec(cmd, (err) => { 13 | if (err) { 14 | reject(err) 15 | return 16 | } 17 | 18 | resolve() 19 | }) 20 | 21 | child.stdout.pipe(process.stdout) 22 | }) 23 | }) 24 | } 25 | 26 | const build = run.bind(null, 'babel src/server --out-dir build/server') 27 | 28 | function watchServer() { 29 | let initial = true 30 | let server 31 | let wait 32 | 33 | const restart = () => { 34 | clearTimeout(wait) 35 | 36 | wait = setTimeout(() => { 37 | if (server) { 38 | server.kill() 39 | } 40 | 41 | build().then(() => { 42 | server = exec(`node ${relative('../build/server/index.js')}`, (error, stdout, stderr) => { 43 | if (error) { 44 | // eslint-disable-next-line 45 | console.log(stderr) 46 | } else { 47 | initial = false 48 | } 49 | 50 | // do not restart if it's the first time 51 | if (initial) { 52 | return 53 | } 54 | 55 | restart() 56 | }) 57 | 58 | server.stdout.pipe(process.stdout) 59 | }) 60 | }, 300) 61 | } 62 | 63 | // start webpack 64 | const webpack = exec(`node_modules/.bin/webpack --config ${relative('../configs/webpack.config.js')} --color`) 65 | 66 | webpack.stdout.pipe(process.stdin) 67 | 68 | // start process 69 | const watcher = chokidar.watch([ 70 | relative('../src/server') 71 | ]) 72 | 73 | watcher.on('ready', () => { 74 | restart() 75 | 76 | watcher.on('all', restart) 77 | }) 78 | } 79 | 80 | watchServer() 81 | -------------------------------------------------------------------------------- /app/build/web/app.js: -------------------------------------------------------------------------------- 1 | /******/ (function(modules) { // webpackBootstrap 2 | /******/ // The module cache 3 | /******/ var installedModules = {}; 4 | 5 | /******/ // The require function 6 | /******/ function __webpack_require__(moduleId) { 7 | 8 | /******/ // Check if module is in cache 9 | /******/ if(installedModules[moduleId]) 10 | /******/ return installedModules[moduleId].exports; 11 | 12 | /******/ // Create a new module (and put it into the cache) 13 | /******/ var module = installedModules[moduleId] = { 14 | /******/ i: moduleId, 15 | /******/ l: false, 16 | /******/ exports: {} 17 | /******/ }; 18 | 19 | /******/ // Execute the module function 20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 21 | 22 | /******/ // Flag the module as loaded 23 | /******/ module.l = true; 24 | 25 | /******/ // Return the exports of the module 26 | /******/ return module.exports; 27 | /******/ } 28 | 29 | 30 | /******/ // expose the modules object (__webpack_modules__) 31 | /******/ __webpack_require__.m = modules; 32 | 33 | /******/ // expose the module cache 34 | /******/ __webpack_require__.c = installedModules; 35 | 36 | /******/ // identity function for calling harmony imports with the correct context 37 | /******/ __webpack_require__.i = function(value) { return value; }; 38 | 39 | /******/ // define getter function for harmony exports 40 | /******/ __webpack_require__.d = function(exports, name, getter) { 41 | /******/ if(!__webpack_require__.o(exports, name)) { 42 | /******/ Object.defineProperty(exports, name, { 43 | /******/ configurable: false, 44 | /******/ enumerable: true, 45 | /******/ get: getter 46 | /******/ }); 47 | /******/ } 48 | /******/ }; 49 | 50 | /******/ // getDefaultExport function for compatibility with non-harmony modules 51 | /******/ __webpack_require__.n = function(module) { 52 | /******/ var getter = module && module.__esModule ? 53 | /******/ function getDefault() { return module['default']; } : 54 | /******/ function getModuleExports() { return module; }; 55 | /******/ __webpack_require__.d(getter, 'a', getter); 56 | /******/ return getter; 57 | /******/ }; 58 | 59 | /******/ // Object.prototype.hasOwnProperty.call 60 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 61 | 62 | /******/ // __webpack_public_path__ 63 | /******/ __webpack_require__.p = ""; 64 | 65 | /******/ // Load entry module and return exports 66 | /******/ return __webpack_require__(__webpack_require__.s = 0); 67 | /******/ }) 68 | /************************************************************************/ 69 | /******/ ([ 70 | /* 0 */ 71 | /***/ (function(module, exports) { 72 | 73 | module.exports = 'Hello'; 74 | 75 | 76 | /***/ }) 77 | /******/ ]); --------------------------------------------------------------------------------