It’s a first part of tutorial where I’m going to show how to create react app from scratch. React is not a framework. It’s a JavaScript library for building user interfaces. If you want to create react app you probably should create own framework based on react — you need to manage state, work with async actions, create own component structure… Codesandbox.io If you want to create your first component or just see what is react — you can use service . https://codesandbox.io/ Next I’ll show you how to work with react on your PC. You need to . I use and . About docker you can read my article: install node.js nvm docker _In this article I want to show how to use docker for development and testing. To show that now is time to switch from…_hackernoon.com Making right things using Docker Create-react-app If you just want to see what is react and create small app you can use . It’s not perfect choice for production because on real app you need to manage state, work with async actions (ajax requests)… In this case you mostly need webpack or other bundler. But for running your first hello world app on PC create-react-app is a good choise. create-react-app After installing node.js, npm helps you to install a new packages. To work with create-react-app you need to install it globally using next command: npm i create-react-app -g Create a new project: create-react-app my-app And start it: cd my-app/npm start Your project structure: You can play with it but for real production you need to use other way. Next I’ll show you react ecosystem: , , scripts, how to use hot module replacement ( ) with and with . webpack babel npm HMR dev server service workers workbox Let’s start… Create a new directory for our app: mkdir appcd app Init project Any node.js project should start from command: npm init npm init -f EditorConfig is a file format and collection of text editor plugins for maintaining consistent coding styles between different editors and IDEs. EditorConfig EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs. The EditorConfig project consists of for defining coding styles and a collection of that enable editors to read the file format and adhere to defined styles. EditorConfig files are easily readable and they work nicely with version control systems. a file format text editor plugins To use it just create file and be sure that your IDE works with it: .editorconfig # EditorConfig is awesome: http://EditorConfig.org# top-most EditorConfig fileroot = true# Unix-style newlines with a newline ending every file[*]end_of_line = lfinsert_final_newline = true # Set default charsecharset = utf-8# 2 space indentationindent_style = spaceindent_size = 2 Eslint Next we need to configure eslint. is an open source project originally created by in June 2013. Its goal is to provide a pluggable linting utility for JavaScript. ESLint Nicholas C. Zakas We will use . To install it just run: Airbnb eslint react config npm i -D We use flag to install it as dev dependency. -D After we need to create file with settings: .eslintrc {"extends": "airbnb","env": {"browser": true,"node": true,"mocha": true}} And add lint command to section: package.json scripts "scripts": {"test": "eslint ."}, To run it use npm run command: npm test You can configure your IDE for using eslint and auto checking. Npm Task List Each command from scripts section you can run using . For example , . Some useful commands like test and start you can run using short syntax: (or even ) and . npm run command npm run test npm run start npm test npm t npm start But if you work with a new project and you don’t want to open package.json file you can use npm task list ( ). Just install it globally: ntl npm i -g ntl After that run command in app directory and you can click up/down arrow buttons to select command: ntl npm-check-updates Other useful command if you need to check and update dependency. is a command-line tool that allows you to upgrade your package.json dependencies to the latest versions, regardless of existing version constraints. npm-check-updates To install it globally run npm i -g npm-check-updates After that run command. ncu We can downgrade eslint command to see how it works: Run , it will upgrade package.json ncu -u And run to install new dependency npm i Browserlist helps to share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-preset-env. Browserlist We will use it for and . postcss babel-preset-env Just create file and put configs there: .browserslistrc # Browsers that we support > 1%Last 2 versionsIE 10 # sorry You can use for testing Browserslist queries or use to test env preset: online demo babel repl You can see targets and plugins added to app for workings with browser targets. Babel is compiler for writing next generation JavaScript. It helps to transform react jsx and es6 code to old es5 code. It helps to use a new JS standards for old browsers. Babel To use it on node.js side we need to install . As we discussed before, we need to install with . And for react we need . babel-core babel-preset-env babel-polyfill babel-preset-react And one more. I’m going to use a new features like operator and . For this I need to install and . object spread/rest static object properties babel-plugin-transform-object-rest-spread babel-plugin-transform-class-properties And we can use — a simple transform to cherry-pick Lodash modules. babel-plugin-lodash We need it only for development: npm i -D babel-core babel-preset-env babel-preset-react babel-plugin-transform-class-properties babel-plugin-transform-object-rest-spread babel-plugin-lodash But with we will use in a code, so it’s not dev dependency. We should use flag : babel-polyfill react-hot-loader -S npm i -S babel-polyfill react-hot-loader Next we need to install configuration file: .babelrc {"presets": ["env", "react"],"plugins": ["transform-class-properties","transform-object-rest-spread","react-hot-loader/babel","lodash"]} As you can see I added as plugin. We need it to work with hot module replacement. react-hot-loader/babel PostCSS is a tool for transforming styles with JS plugins. These plugins can lint your CSS, support variables and mixins, transpile future CSS syntax, inline images, and more. PostCSS PostCSS is used by industry leaders including Wikipedia, Twitter, Alibaba, and JetBrains. The PostCSS plugin is one of the most popular CSS processors. Autoprefixer We will use and . postcss-cssnext cssnano PostCSS-cssnext is a PostCSS plugin that helps you to use the latest CSS syntax today. It transforms CSS specs into more compatible CSS so you don’t need to wait for browser support. Cssnano takes your nicely formatted CSS and runs it through many focused optimisations, to ensure that the final result is as small as possible for a production environment. To install it run: npm i -D postcss postcss-cssnext cssnano Postcss-cssnext has an interesting tool — . It’s postcss plugin to parse CSS and add vendor prefixes to CSS rules using values from . It is by Google and used in Twitter and Taobao. autoprefixer Can I Use recommended And it uses Browserlist rules. And config file: postcss.config.js module.exports = {plugins: {'postcss-cssnext': {warnForDuplicates: false,},cssnano: {},},}; Webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset. Webpack What we will use with webpack: — development server that provides live reloading. DevServer — copies individual files or entire directories to the build directory. copy-webpack-plugin — allows transpiling JavaScript files using and . babel-loader Babel webpack — PostCSS loader for webpack. postcss-loader — adds CSS to the DOM by injecting a tag. style-loader <style> — interprets and like and will resolve them. css-loader @import url() import/require() with — sass loader for webpack. Compiles Sass to CSS. sass-loader node-sass — instructs webpack to emit the required object as file and to return its public URL. file-loader — extract text from a bundle, or bundles, into a separate file. extract-text-webpack-plugin — simplifies creation of HTML files to serve your webpack bundles. html-webpack-plugin — a webpack plugin to remove your build folder(s) before building. clean-webpack-plugin — webpack plugin and CLI utility that represents bundle content as convenient interactive zoomable treemap. webpack-bundle-analyzer — create smaller Lodash builds by replacing of modules with , , or simpler alternatives. lodash-webpack-plugin feature sets noop identity — a plugin for your build process, helping you generate a manifest of local files that workbox-sw should precache. We will use it later. workbox-webpack-plugin Webpack To install it run: npm i -D webpack webpack-dev-server babel-loader postcss-loader style-loader css-loader sass-loader node-sass file-loader extract-text-webpack-plugin html-webpack-plugin clean-webpack-plugin webpack-bundle-analyzer lodash-webpack-plugin workbox-webpack-plugin copy-webpack-plugin Next I’m going to split webpack config into small single responsibility files. Let’s create webpack directory: mkdir webpackcd webpack webpack/index.js const { resolve } = require('path'); const vendor = require('./vendor');const rules = require('./rules');const plugins = require('./plugins');const devServer = require('./dev_server');const devtool = require('./devtool'); const settings = {resolve: {extensions: ['*', '.js', '.jsx', '.css', '.scss'],},context: resolve(__dirname, '..'),entry: {app: ['react-hot-loader/patch','babel-polyfill','./src/index'],vendor,},output: {filename: '[name].[hash].js',path: resolve(__dirname, '..', 'dist'),},module: {rules,},plugins,devServer,devtool,}; module.exports = settings; webpack/vendor.js const vendor = ['babel-polyfill','react','react-dom','react-redux','react-router','react-router-redux','react-virtualized','redux','redux-observable','react-toolbox','react-hot-loader','rxjs','lodash','moment','localforage','react-loadable',]; module.exports = vendor; Here we can put libraries which we don’t want to put in the main code. It helps to split one big app file into smaller files for entry points and vendors. Vendors can be cached between releases if we don’t upgrade them. All packages we will install later. webpack/rules.js const { join } = require('path');const ExtractTextPlugin = require('extract-text-webpack-plugin'); const rules = [{test: /.jsx?$/,loader: 'babel-loader',exclude: /node_modules/,}, {test: /\.scss$/,exclude: /node_modules/,use: ExtractTextPlugin.extract({fallback: 'style-loader',use: [{loader: 'css-loader',options: {sourceMap: true,importLoaders: 2,modules: true,localIdentName: '[name]__[local]___[hash:base64:5]'},}, {loader: 'postcss-loader',}, {loader: 'sass-loader',options: {sourceMap: true,},}],}),}, {test: /\.css$/,use: [{loader: 'style-loader',}, {loader: 'css-loader',options: {sourceMap: true,importLoaders: 2,modules: true,localIdentName: '[name]__[local]___[hash:base64:5]'},}, {loader: 'postcss-loader',}],}, {test: /\.(woff2|woff|ttf|eot|svg)(\?.*$|$)/,loader: 'file-loader?name=fonts/[name].[ext]',include: [join(__dirname, 'src'),join(__dirname, 'node_modules'),],}, {test: /\.(jpg|jpeg|gif|png|ico)(\?.*$|$)$/,loader: 'file-loader?name=img/[name].[ext]',include: [join(__dirname, 'src'),join(__dirname, 'node_modules'),],}]; module.exports = rules; Here we described rules for loading different kind of files like js/jsx, scss, css, fonts, images. webpack/plugins.js const { resolve, join } = require('path');const webpack = require('webpack');const HtmlWebpackPlugin = require('html-webpack-plugin');const ExtractTextPlugin = require('extract-text-webpack-plugin');const CleanWebpackPlugin = require('clean-webpack-plugin');const WorkboxPlugin = require('workbox-webpack-plugin');const CopyWebpackPlugin = require('copy-webpack-plugin');const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const isProduction = process.env.NODE_ENV === 'production'; const dist = 'dist'; // the path(s) that should be cleanedconst pathsToClean = [`${dist}/*.*`,]; // the clean options to useconst cleanOptions = {root: resolve(__dirname, '..'),exclude: [`${dist}/.gitignore`],verbose: true,dry: false,}; const plugins = [new webpack.EnvironmentPlugin({ NODE_ENV: 'development' }),new CleanWebpackPlugin(pathsToClean, cleanOptions),new LodashModuleReplacementPlugin(),new HtmlWebpackPlugin({template: join('src', 'index.html'),}),new ExtractTextPlugin(join(dist, 'bundle.css'), {allChunks: true,}),new webpack.optimize.CommonsChunkPlugin({name: 'vendor',minChunks: Infinity,}),new webpack.NamedModulesPlugin(),]; if (isProduction) {plugins.push(new webpack.LoaderOptionsPlugin({minimize: true,debug: false,}),new webpack.optimize.UglifyJsPlugin({sourceMap: true,compress: {warnings: false,screw_ie8: true,conditionals: true,unused: true,comparisons: true,sequences: true,dead_code: true,evaluate: true,if_return: true,join_vars: true,},output: {comments: false,},}),new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),new CopyWebpackPlugin([{from: require.resolve('workbox-sw'),to: 'workbox-sw.prod.js',}]),new WorkboxPlugin({globDirectory: dist,globPatterns: ['**/*.{html,js,css}'],swSrc: join('src', 'service-worker.js'),swDest: join(dist, 'service-worker.js'),clientsClaim: true,skipWaiting: true,navigateFallback: '/index.html',}));} else {plugins.push(new webpack.LoaderOptionsPlugin({debug: true,}),new webpack.HotModuleReplacementPlugin(),new BundleAnalyzerPlugin());} module.exports = plugins; In this file we configure webpack plugins and split it by environment — production or development. For development we need hot module replacement and analyzer, for production we need workbox plugin and uglifyjs. webpack/devtool.js const isProduction = process.env.NODE_ENV === 'production'; const devtool = isProduction ? 'source-map' : 'inline-cheap-module-source-map'; module.exports = devtool; Here we just check environment and choose what kind of source map we should use. webpack/dev_server.js const { join } = require('path'); const devServer = {quiet: false,port: 3000,contentBase: join(__dirname, '..', 'dist'),hot: true,historyApiFallback: true,inline: true,noInfo: false,headers: { 'Access-Control-Allow-Origin': '*' },stats: {assets: false,colors: true,version: false,hash: false,timings: false,chunks: false,chunkModules: false,},}; module.exports = devServer; Here we set config for webpack dev server. webpack.config.js require('webpack'); const settings = require('./webpack'); module.exports = settings; And last thing — adding scripts to : package.json "scripts": {"test": "eslint .","start": "webpack-dev-server --inline","build": "NODE_ENV=production webpack"}, Small update — we don’t need to check webpack files by eslint, so we need to create file and put next lines (about dist and service-worker later): .eslintignore webpack/*.jsdist/*.jssrc/service-worker.js Now run command or use to lint project files: npm test ntl React Now we can install all our dependency. I hope now you know what is it ;) React — — This package serves as the entry point of the DOM-related rendering paths. React-DOM — a predictable state container for JavaScript apps. Redux — official React bindings for Redux. react-redux — a library for reactive programming using Observables, to make it easier to compose asynchronous or callback-based code. RxJS — RxJS middleware for action side effects in Redux using “Epics”. redux-observable — declarative routing for react. react-router — ruthlessly simple bindings to keep react-router and redux in sync. react-router-redux — React components for efficiently rendering large lists and tabular data. react-virtualized — a set of React components implementing Google’s Material Design specification with the power of CSS Modules . react-toolbox http://www.react-toolbox.io — a JavaScript utility library delivering consistency, modularity, performance, & extras. Lodash — parse, validate, manipulate, and display dates and times in JavaScript. moment — offline storage, improved. Wraps IndexedDB, WebSQL, or localStorage using a simple but powerful API. localForage — a higher order component for loading components with promises. react-loadable All those packages we will use in next part. To install it use next command: npm i -S react react-dom redux react-redux rxjs redux-observable react-router react-router-redux react-virtualized react-toolbox lodash moment localforage react-loadable Our code we will store in directory. Let’s create it: src mkdir srccd src As we use html-webpack-plugin we need to create index.html: src/index.html <!DOCTYPE html><html><head><meta charset="UTF-8"><title>Reports</title><link href=" " rel="stylesheet"></head><body><div id="root"></div></body></html> https://fonts.googleapis.com/icon?family=Material+Icons Here I added link to because react-toolbox doesn’t include fonts into package. And is our app container. Html-webpack-plugin will add script tag after container. Google fonts <div id=”root”></div> And our entry point: src/index.jsx import React from 'react';import ReactDOM from 'react-dom';import { AppContainer } from 'react-hot-loader';import App from './components/App'; const render = (Component) => {ReactDOM.render(<AppContainer><Component /></AppContainer>,document.getElementById('root'),); if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('service-worker.js').catch(() => {});});}}; render(App); if (module.hot) {module.hot.accept();} Here I include react with react-hot-loader and link to our react component. After I created function for rendering our component using hot module replacement. Next I added code to work with service workers, but I’ll describe it later. I run our function render and after I check hot module replacement for changing code. And create our first react component. mkdir componentscd components src/components/App.jsx import React, { Component } from 'react';import { AppBar, Checkbox, IconButton } from 'react-toolbox';import { Layout, NavDrawer, Panel, Sidebar } from 'react-toolbox'; class App extends Component {state = {drawerActive: false,drawerPinned: false,sidebarPinned: false}; toggleDrawerActive = () => {this.setState({ drawerActive: !this.state.drawerActive });}; toggleDrawerPinned = () => {this.setState({ drawerPinned: !this.state.drawerPinned });}; toggleSidebar = () => {this.setState({ sidebarPinned: !this.state.sidebarPinned });}; render() {return (<Layout><NavDrawer active={this.state.drawerActive}pinned={this.state.drawerPinned} permanentAt='xxxl'onOverlayClick={ this.toggleDrawerActive }><p>Navigation, account switcher, etc. go here.</p></NavDrawer><Panel><AppBar title="React Toolbox" leftIcon="menu" onLeftIconClick={ this.toggleDrawerActive } /><div style={{ flex: 1, overflowY: 'auto', padding: '1.8rem' }}><h1>Main Content</h1><p>Main content goes here.</p><Checkbox label='Pin drawer' checked={this.state.drawerPinned} onChange={this.toggleDrawerPinned} /><Checkbox label='Show sidebar' checked={this.state.sidebarPinned} onChange={this.toggleSidebar} /></div></Panel><Sidebar pinned={ this.state.sidebarPinned } width={ 5 }><div><IconButton icon='close' onClick={ this.toggleSidebar }/></div><div style={{ flex: 1 }}><p>Supplemental content goes here.</p></div></Sidebar></Layout>);}} module.exports = App; It’s just an example. I took it from . react toolbox documentation Workbox is a collection of libraries and build tools that make it easy to store your website’s files locally, on your users’ devices. Consider Workbox if you want to: Workbox Make your site work offline. Improve load performance on repeat-visits. Even if you don’t want to go fully-offline, you can use Workbox to store and serve common files locally, rather than from the network. We use workbox webpack plugin (we already installed it and added it to webpack/plugins.js). Now we need to install — a service worker library to make managing fetch requests and caching as easy as possible. It provides a high-level wrapper on top of a number of individual modules, giving you a consistent, powerful interface. workbox-sw npm i -D workbox-sw To work with workbox-sw we already added another plugin — copy-webpack-plugin. It should copy workbox-sw module to dist/workbox-sw.prod.js where we have our files after building. Last thing — creating service-worker file where we can set rules for caching: src/service-worker.js importScripts('workbox-sw.prod.js'); const workboxSW = new self.WorkboxSW({"skipWaiting": true,"clientsClaim": true,}); workboxSW.precache([]); workboxSW.router.registerRoute(' workboxSW.strategies.cacheFirst({cacheName: 'googleapis',cacheExpiration: {maxEntries: 20,},cacheableResponse: { statuses: [0, 200] },})); https://fonts.googleapis.com/(.*)', // We want no more than 50 images in the cache. We check using a cache first strategyworkboxSW.router.registerRoute(/\.(?:png|gif|jpg)$/,workboxSW.strategies.cacheFirst({cacheName: 'images-cache',cacheExpiration: {maxEntries: 50,},})); workboxSW.router.registerRoute(/index.html/, workboxSW.strategies.staleWhileRevalidate()); Here I cache Google fonts, app images and index.html — main app page. And structure of our project: How to use First we need to create directory and add file (we will use it later): dist .gitkeep mkdir disttouch dist/.gitkeep Testing As we added directory to we should not test our built files. The same with . dist .eslintignore src/service-worker.js So we can run or use to check that we don’t have any problems: npm test ntl Development Command will run webpack dev server with configs from . npm start webpack/dev_server.js It helps us with 2 main problems — building our files with caching them into memory and hot module replacement (HMR). If you make changes in any file (js, css, scss…) you can see it almost at the same time in browser without refreshing page. After running or using you can see opened page with analyzer: npm start ntl Here you can see bundle content as convenient interactive zoomable treemap. This module will help you: Realize what’s inside your bundle really Find out what modules make up the most of it’s size Find modules that got there by mistake Optimize it! And the best thing is it supports minified bundles! It parses them to get real size of bundled modules. And it also shows their gzipped sizes! It’s a good start to make your app less and faster. But it’s not our goal now. Let’s open and check our app: http://localhost:3000/ If we open code and make any change: We can see it at the same time on page: It really helps in development. Build production ready bundles If we need to release our app we need to generate (build) files before put it on server or CDN. Just run or use : npm run build ntl We can see a new files: We can run index.html file in any web server for example http-server. Install it: npm i -g http-server And run it from directory: dist cd disthttp-server And open http://localhost:8080/ We see the same content. But if we open development tools and open Application tab with Service Workers menu we can se installed service worker: We can test it — set offline checkbox and refresh page: It works the same. If we open Network tab and again refresh page: We can see that all our files we get from service worker. It’s our goal. Github I created so you can clone code on your PC (don’t forget to install node.js and install all dependency) and run it. github repository In next part I’ll show you how to work with redux, redux-observable, react-loadable… And how to create tests to make your app 100% production ready. _It’s the second part of article — React app from scratch. I’ll show you how to create a CD process to make your app…_medium.com Continuous delivery of react app with Jenkins and Docker My other posts _Read writing from Evheniy Bystrov on Medium. Senior Software Engineer in Ciklum. Every day, Evheniy Bystrov and…_medium.com Evheniy Bystrov - Medium Open source node.js package from scratch Yet Another Event Promised Server Node.js REST API from scratch Node.js GraphQL from scratch Docker for Data Science TensorFlow Object Detection with Docker from scratch _For the last 8 months I got a lot of useful links and I decided to share it. I hope you can find something interesting…_hackernoon.com 150+ Useful Resources for Node.js / React Engineers References _Tinder recently swiped right on the web. Their new responsive Progressive Web App — Tinder Online — is available to 100…_medium.com A Tinder Progressive Web App Performance Case Study Webpack & The Hot Module Replacement Webpack’s HMR & React-Hot-Loader — The Missing Manual Workbox webpack Plugin Using Workbox + Webpack to precache with Service Worker