├── .gitignore ├── LICENSE ├── README.md ├── config.json ├── gulpfile.js ├── index.js ├── package.json └── src ├── logger.js ├── server.js └── www ├── css └── site.scss ├── index.html └── js ├── site.jsx └── widgets-data.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | dist 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 training4developers 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # intro-to-react -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "webServer": { 3 | "port": 8080, 4 | "folder": "dist/www" 5 | }, 6 | "logger": { 7 | "transports": { 8 | "console": { 9 | "level": "debug", 10 | "colorize": true, 11 | "timeStamp": true 12 | }, 13 | "file": { 14 | "level": "debug", 15 | "fileName": "dist/logs/server.log", 16 | "timeStamp" : true 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const 4 | webpack = require("webpack-stream"), 5 | gulp = require("gulp"), 6 | babel = require("gulp-babel"), 7 | sass = require("gulp-sass"); 8 | 9 | gulp.task("sass", function() { 10 | return gulp.src("src/www/css/site.scss") 11 | .pipe(sass()) 12 | .on("error", function() { 13 | console.dir(arguments); 14 | }) 15 | .pipe(gulp.dest("dist/www/css")); 16 | }); 17 | 18 | gulp.task("babel", function() { 19 | 20 | return gulp.src(["src/www/js/**/*.jsx","src/www/js/**/*.js"]) 21 | .pipe(babel({ 22 | plugins: ["transform-react-jsx"], 23 | presets: ["es2015", "react"] 24 | })) 25 | .on("error", function() { 26 | console.dir(arguments); 27 | }) 28 | .pipe(gulp.dest("dist/www/js")); 29 | 30 | }); 31 | 32 | gulp.task("webpack", ["babel"], function() { 33 | 34 | return gulp.src("./dist/www/js/site.js") 35 | .pipe(webpack({ 36 | output: { 37 | filename: "site-webpack.js" 38 | } 39 | })) 40 | .on("error", function() { 41 | console.dir(arguments); 42 | }) 43 | .pipe(gulp.dest("./dist/www/js")); 44 | 45 | }); 46 | 47 | gulp.task("copy", function() { 48 | 49 | gulp.src("node_modules/bootstrap/dist/css/**/*") 50 | .pipe(gulp.dest("dist/www/css")); 51 | 52 | gulp.src("src/www/**/*.html") 53 | .pipe(gulp.dest("dist/www")); 54 | 55 | gulp.src(["src/**/*","!src/www/**/*"]) 56 | .pipe(gulp.dest("dist")); 57 | 58 | }); 59 | 60 | gulp.task("server", function() { 61 | require("./index.js"); 62 | }); 63 | 64 | gulp.task("default", ["sass", "webpack", "copy"], function () { 65 | 66 | gulp.watch("src/www/css/site.scss", ["sass"]); 67 | gulp.watch(["src/www/js/**/*.jsx","src/www/js/**/*.js"], ["webpack"]); 68 | gulp.watch(["node_modules/bootstrap/dist/css/**/*"], ["copy"]); 69 | gulp.watch(["src/www/**/*.html"], ["copy"]); 70 | gulp.watch(["src/**/*","!src/www/**/*"], ["copy"]); 71 | 72 | }); 73 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const 4 | fs = require("fs"), 5 | server = require("./dist/server.js"); 6 | 7 | fs.readFile("./config.json", function(err, data) { 8 | 9 | if (err) { 10 | console.log(err); 11 | return; 12 | } 13 | 14 | let options = null; 15 | 16 | try { 17 | options = JSON.parse(data, function(propName, propValue) { 18 | if (propName === "port") { 19 | return process.env.PORT || propValue; 20 | } 21 | return propValue; 22 | }); 23 | } catch (err) { 24 | console.log(err); 25 | return; 26 | } 27 | 28 | server(options).start(); 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "intro-to-react", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/training4developers/intro-to-react.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/training4developers/intro-to-react/issues" 17 | }, 18 | "homepage": "https://github.com/training4developers/intro-to-react#readme", 19 | "dependencies": { 20 | "bootstrap": "^3.3.6", 21 | "express": "^4.13.3", 22 | "immutable": "^3.7.6", 23 | "object-assign": "^4.0.1", 24 | "react": "^0.14.7", 25 | "react-dom": "^0.14.7", 26 | "socket.io": "^1.4.5", 27 | "winston": "^2.1.1" 28 | }, 29 | "devDependencies": { 30 | "babel-plugin-transform-react-jsx": "^6.5.2", 31 | "babel-preset-es2015": "^6.5.0", 32 | "babel-preset-react": "^6.5.0", 33 | "gulp": "^3.9.1", 34 | "gulp-babel": "^6.1.2", 35 | "gulp-sass": "^2.2.0", 36 | "webpack-stream": "^3.1.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | 3 | "use strict"; 4 | 5 | const 6 | winston = require("winston"), 7 | logger = new winston.Logger(); 8 | 9 | if (config.transports.console) { 10 | logger.add(winston.transports.Console, { 11 | level: config.transports.console.level || "error", 12 | colorize: config.transports.console.colorize || true, 13 | timestamp: config.transports.console.timestamp || true 14 | }); 15 | } 16 | 17 | if (config.transports.file) { 18 | logger.add(winston.transports.File, { 19 | level: config.transports.file.level || "error", 20 | filename: config.transports.file.fileName || "logs/server.log", 21 | timestamp: config.transports.file.timestamp || true 22 | }); 23 | } 24 | 25 | return logger; 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | module.exports = function(options) { 2 | 3 | "use strict"; 4 | 5 | global.logger = require("./logger")(options.logger); 6 | global.logger.info("logging started"); 7 | 8 | const 9 | http = require("http"), 10 | express = require("express"); 11 | 12 | let 13 | app = express(), 14 | server = http.createServer(app); 15 | 16 | app.use(/.*map$/, function(req, res) { 17 | res.writeHead(404); 18 | res.end(); 19 | }); 20 | 21 | app.use(express.static(options.webServer.folder)); 22 | 23 | return { 24 | start: function() { 25 | 26 | return new Promise(function startPromise(resolve, reject) { 27 | server.listen(options.webServer.port, function serverListen(err) { 28 | 29 | server.options = options.webServer; 30 | 31 | if (err) { 32 | err.options = server.options; 33 | global.logger.error(err); 34 | reject(err); 35 | return; 36 | } 37 | 38 | global.logger.info(`http server started on port ${server.options.port}`); 39 | resolve(server.options); 40 | 41 | }); 42 | }); 43 | 44 | }, 45 | stop: function() { 46 | 47 | return new Promise(function stopPromise(resolve, reject) { 48 | server.close(function serverClose(err) { 49 | 50 | if (err) { 51 | err.options = server.options; 52 | global.logger.error(err); 53 | reject(err); 54 | return; 55 | } 56 | 57 | global.logger.info(`http server stopped on port ${server.options.port}`); 58 | resolve(server.options); 59 | 60 | }); 61 | }); 62 | 63 | } 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /src/www/css/site.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/training4developers/intro-to-react/33c0a800413f2b397adff19e23a630449ac1a236/src/www/css/site.scss -------------------------------------------------------------------------------- /src/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Introduction to React Demo 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | Hello World! 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/www/js/site.jsx: -------------------------------------------------------------------------------- 1 | "use strict"; -------------------------------------------------------------------------------- /src/www/js/widgets-data.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { id: 1, name: "Small Red Widget", description: "A small, red widget.", color: "red", size: "small", quantity: 2 }, 3 | { id: 2, name: "Medium Blue Widget", description: "A medium, blue widget.", color: "blue", size: "medium", quantity: 15 }, 4 | { id: 3, name: "Large Green Widget", description: "A large, green widget.", color: "green", size: "large", quantity: 30 }, 5 | { id: 4, name: "Tiny Orange Widget", description: "A tiny, orange widget.", color: "orange", size: "tiny", quantity: 10 } 6 | ]; 7 | --------------------------------------------------------------------------------