Some developers don’t like because it’s to hard, functional, new thinking. In this tutorial I’ll show you how easy and fast to create production ready full stack app with , react, with and from scratch with full code coverage. react node.js redux rxjs docker We will create full stack app with node.js on backend side and react with redux and rxjs on frontend side. And will be our data storage. To run redis on dev PC I’ll show how easy to make it with docker. redis Lets start creating our app from . After we should create directory and initiate node project. Who wants to see code now I created . docker installation github repository Each new JavaScript project should start with creating by using command. package.json npm init mkdir react-awesome-appcd react-awesome-appnpm init -f Node.js now is the not only as backend or tool for frontend bundling. As many great companies support it for own services (Google, AWS) or (PayPal, Uber). For real production project it’s better to use cloud services like or . But for development or small projects we can use node as http/https server with framework like or . In the tutorial I’ll show you other framework — , for working with promises, async / await, parallel execution… most popular platform I wrote before use it as part of system Google function AWS lambda express koa YEPS I created it As I said before to store our app data we can use redis. And thanks docker we can run it locally without dependencies and memory problems. To run it in docker we need to execute command docker run -d --name redis -p 6379:6379 redis:alpine Here we use small image running as daemon ( ), with opened default port . To stop it we need run: alpine -d 6379 docker rm -f redis As we work with we can add those commands to section: package.json script "scripts": {"db:start": "docker run -d --name redis -p 6379:6379 redis:alpine","db:stop": "docker rm -f redis"}, Don’t forget that is json file so don’t break it. Now we just need to run to start redis service and to stop it. package.json npm run db:start npm run db:stop Don’t forget to install node.js version 7.6.0 and higher because we will use natively. To check current version just run (I use latest version thanks to ): async / await node -v nvm Now I’m going to install only one global dependency — , it hepls to see all our commands: ntl npm i -g ntl After just run command in directory and select script: ntl Next step is our backend. It’s very important to understand how works. It’s single process and in fact it’s EventEmitter with event. Each user’s request runs event handler and each node.js framework like express.js or koa.js is just handler to process user’s requests. So any side effect like variables out of this process can create memory leaks. Be careful. node.js http/https server request For our project we will use . I created it for one high load project with async / await and parallel jobs using Promise.all. You can check . Thanks to promise model and parallel execution instead of middleware model with loop and running modules one by one I got speed in 10 times faster. YEPS framework benchmark To use YEPS we need install all dependencies (run command with flag to store dependencies in and to store it as ): -S package.json -D devDependencies npm i -S yeps yeps-bodyparser yeps-cors yeps-error yeps-helmet yeps-logger yeps-redis yeps-router yeps-server yeps-static And we can see changes in : package.json "dependencies": {"yeps": "^1.0.0","yeps-bodyparser": "^1.1.0","yeps-cors": "^1.0.0","yeps-error": "^1.2.0","yeps-helmet": "^1.0.0","yeps-logger": "^1.0.0","yeps-redis": "^1.0.0","yeps-router": "^1.0.0","yeps-server": "^1.0.0","yeps-static": "^1.2.0"} To assamble our server part I’ll create new directory and as entry point. server index.js mkdir servercd servertouch index.js And put this code: App = require('yeps'); Router = require('yeps-router'); error = require('yeps-error'); logger = require('yeps-logger'); redis = require('yeps-redis'); bodyParser = require('yeps-bodyparser'); helmet = require('yeps-helmet'); cors = require('yeps-cors'); serve = require('yeps-static'); const const const const const const const const const app = module.exports = App(); router = Router(); const new const new router.get('/data').then( (ctx) => { rows = ctx.redis.get('data');ctx.res.end(JSON.stringify(rows));}).post('/data').then( (ctx) => { ctx.redis.set('data', JSON.stringify(ctx.request.body));ctx.res.end(JSON.stringify({message: 'ok',}));}); async const await async await app.all([error({ isJSON: }),logger(),]).then(serve(),).all([redis(),bodyParser(),helmet(),cors(),]).then(router.resolve(),); true Here after require all dependencies I created and . In router I created two entry points to and . It’s not restfull app. app router get set data The most interesting things we can see after. With YEPS we can run parallel all jobs but using promise interface (behind YEPS interface we work with promise) we can use priorities. First we should setup our and (with json response headers). After checking request and understand that it’s not request to get static files like JavaScript files or index.html (without parameters this module looks into directory) we can enable all other modules and . After connecting to redis, setting all secure headers we can start parsing request and run router handler. logger error handler public run it parallel I use the same idea of parallel jobs in . For example in express.js we need to think which routes are most important, popular and put it first. In YEPS router all checks work parallel. And first matching router will stop this process. If you need to make some priority you can create more than one router: YEPS router routerFirst = Router(); routerSecond = Router(); const new const new app.then(routerFirst.resolve()).then(routerSecond.resolve()); Don’t forget to create for our redis. Examples you can find in documentation. To do it we need to create directory and put file: config yeps-redis config default.json {"redis": {"host": "127.0.0.1","port": 6379}} To run our server we need to create and in like we made it for docker: entry point script package.json "start: server": "node ./bin/www", and : bin/www #!/usr/bin/env node const app = require('../server');const server = require('yeps-server'); server.createHttpServer(app); And command for running: (or use ). npm run start:server ntl After open browser and check response. http://localhost:3000/data To be production ready we need to create our first test. Now we need to instal our first dev dependencies. For testing we will use , , and : mocha chai expect sinon chai-http npm i -D mocha chai chai-http sinon And our after has : package.json devDependencies "devDependencies": {"chai": "^4.1.2","chai-http": "^3.0.0","mocha": "^3.5.3","sinon": "^3.3.0"} And to run test we need to add to : script package.json "test:server": "mocha tests --recursive" After that create test directory with directory and file inside: servers index.js mkdir testscd testsmkdir servercd servertouch index.js And code of our backend tests: chai = require('chai'); chaiHttp = require('chai-http'); sinon = require('sinon'); yeps = require('yeps-server'); redis = require('yeps-redis/redis'); logger = require('yeps-logger/logger'); const const const const const const app = require('../../server'); const expect = chai.expect;chai.use(chaiHttp); server; const let describe('Server testing', () => {logger.info = text => text;logger.error = text => text; beforeEach(() => { server = yeps.createHttpServer(app); }); afterEach(() => { server.close(); }); it('should test 404 error', **async** () => { **const** spy = sinon.spy(); **await** chai.request(server) .get('/404') .send() .catch((error) => { expect(error).to.have.status(404); spy(); }); expect(spy.calledOnce).to.be.true; }); it('should test static server', **async** () => { **const** spy = sinon.spy(); **await** chai.request(server) .get('/index.html') .send() .then((res) => { expect(res).to.have.status(200); spy(); }); expect(spy.calledOnce).to.be.true; }); it('should test get data', **async** () => { **const** spy = sinon.spy(); **await** redis.set('data', 'test'); **await** chai.request(server) .get('/data') .send() .then((res) => { expect(res).to.have.status(200); expect(res.body).to.be.equal('test'); spy(); }); expect(spy.calledOnce).to.be.true; }); it('should test set data', **async** () => { **const** spy = sinon.spy(); **const** data = 'test'; **await** chai.request(server) .post('/data') .send({ data }) .then((res) => { expect(res).to.have.status(200); spy(); }); **const** storedData = JSON.parse(**await** redis.get('data')); expect(storedData.data).to.be.equal(data); expect(spy.calledOnce).to.be.true; }); }); And after running we see: npm run test:server I disabled logger to see clear result (we can see info about 404 error test — page not found): logger.info = text => text;logger.error = text => text; That’s all for our backend. We created two endpoints to get and set our data and our server can be a . Now we are ready to start our frontend part . static server in next chapter And some small updates if you work in team. First is . It helps to use the same code standard for all team members. We need to create : editorconfig .editorconfig root = true [*]end_of_line = lfinsert_final_newline = true charset = utf-8 indent_style = spaceindent_size = 2 Next step is installing — Node Security Platform. It helps you keep your node applications secure. We need it only for development so install it with flag: nsp -D npm i -D nsp And add script to to run it: package.json "test:security": "nsp check" Next step is installing and . Eslint helsp with ES6 code standards, we will use it with . And as we will use ES6 and higher we need to install new version of istanbul — istanbul@next. eslint istanbul airbnb react plugin npm i -D eslint eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-import istanbul@next To work with eslint we need to create config file — : .eslintrc {"extends": "airbnb","env": {"node": ,"mocha": },"rules": {"jsx-a11y/href-no-hash": 0,"no-unused-expressions": 0,"no-multi-assign": 0}} true true And script: "lint:js": "eslint server tests", To run: npm run lint:js The same for istanbul — : .istanbul.yml true [] true instrumentation:default-excludes: excludes: include-all-sources: And script: "test:coverage": "istanbul cover _mocha -- tests --recursive" And after running we see npm run test:coverage To run all our command in one click we need package: npm-run-all npm i -S npm-run-all And command (short version is or even ) will run all our tests: npm run test npm test npm t "test": "npm-run-all test:**", And final thing — each github repository should have file with instruction how to install and how to use your project. Lets check . And in next chapter I’ll show you how easy to create real reactive awesome app. Readme.md github repository