Category Archives: TUTORIALS

Detailed tutorials explaining how to build most common applications, in different languages.

Adding Apollo provider and introduction to making queries to GraphQL

branch-name:  
Click To Copy

Running GraphQL server to connect to.

 First let’s have GraphQL server running so we could connect to.
How to do this:

  • Install MongoDB because our version of GraphQL is using it and we will need a real database in the future tutorials. So let’s do it now. If you are on MAC and have Homebrew installed this is as simple as executing brew install mongodb from the command line.
  •  Download an run GraphQL setup as well. This will install Database settings that we will need in MogoDB.

yarn setup

then run the server:

yarn start

Now if you  point your browser to http://localhost:4001/graphql you will be able to see GraphQL GUI and you could execute queries there, but this is not the subject of this tutorial. If you are interested of how to set up GraphQL with Express server you could visit this article.

Creating ‘Smart’ component.

The concept of ‘smart’ and ‘dumb’ components is simple: We separate the data fetching from presentational layer by dividing the components into ‘presentational’ which only deal with how to show the data, and ‘container’ components, which only work is to fetch the data from some source. In our case this will be Apollo provider.  (read more …)

Installing dependencies.

yarn add graphql graphql-tag react-apollo apollo-client apollo-link-http apollo-cache-inmemory

  • graphql – query language for APIs created by Facebook.
  • graphql-tag – utilities for parsing GraphQL queries.
  • react-apolllo – utilities that fetch data from GraphQL server and use it in building complex and reactive UIs using the React framework.
  • apollo-client – GraphQL client with integrations for React, Angular, and more.
  • apollo-link-http – interface for modifying control flow of GraphQL requests and fetching GraphQL results
  • apollo-cache-inmemory – Tool for caching GraphQL client with integrations for React, Angular, and more.

yarn add graphql graphql-tag react-apollo apollo-link-http apollo-client apollo-cache-inmemory 

Now if we have all moving peaces in place, we could start building our first ‘connected‘ component, that will fetch data from QgraphQL.

Creating Apollo provider.

Let’s add all necessary components that we will need to connect to GraphQL, and wrap the rotes into Apollo provider .

./src/components/App/index.js

import React, { Component } from 'react';
import Home from '../Home';
import Greetings from '../Greetings';
import About from '../About';
import DogsCatalog from '../../containers/DogsCatalog';
import Header from '../Header';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import styles from './styles.scss';
export default class App extends Component {
  render() {
    const GRAPHQL_URL = 'http://localhost:4001/graphql';
    const client = new ApolloClient({
      link: new HttpLink({ uri:  GRAPHQL_URL }),
      cache: new InMemoryCache()
    });  
    return (
      <div className={styles.appWrapper}>
        <ApolloProvider client={client}>
          <Router>
            <Header />
            <Switch>
              <Route exact path="/home" user="Test" component={Home} />
              <Route exact path="/greetings" user="Test" component={Greetings} />
              <Route exact path="/dogs-catalog" component={DogsCatalog} />              
              <Route exact path="/about" component={About} />
            </Switch>
          </Router>
        </ApolloProvider>
      </div>        
    );
  }
}

 

what we just did:
– added all necessary components that we will need to connect to GraphQL (lines 7 – 10) .
– Import our new Dogs-Catalog component that we are going to build (line 5).
– created Apollo component, and pass link and cache parameters (lines 15-19).
– wrap the routes into Apollo provider.
– add new route to show out new ‘Dogs Catalog’ component.

Also make sure that you are adding navigation section to the Header component.

import React from 'react';
import { Link } from 'react-router-dom';
const styles = require('./styles.scss');
const Header = ( {title} ) => (
  <div>
    <div className={styles.wrapper}>
      <ul>
        <li><Link to='/home'>HOME</Link></li>
        <li><Link to='/greetings'>GREETINGS</Link></li>       
        <li><Link to='/dogs-catalog'>DOGS CATALOG</Link></li>
        <li><Link to='/about'>ABOUT</Link></li>
      </ul>
    </div>
  </div>
);
export default Header;

 

Creating connected component.

We will create a simple component, that will fetch data from GraphQL and will show different dogs breeds depending of which one user will choose.

Create new folder mkdir ./src/containers and add the new index.js for the new ‘Dogs Catalog’  component.

./src/containers/DogsCatalog/index.js

import React from 'react';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';

const GET_DOG = gql`
query 
{
  getDogByBreed(breed: "labrador") {
    id
    breed
    displayImage
  }
}
`

const DogCatalog = () => (
  <Query query={GET_DOG}>
    {({ loading, error, data }) => {
      if (loading) return <div>Loading...</div>;
      if (error) return <div>Error!</div>;

      return (
        <div>
            <span>breed: </span>
            <span>{data.getDogByBreed.breed}</span>
            <br />
            <img src={data.getDogByBreed.displayImage} />
        </div>
      )
    }}
  </Query>
)

export default DogCatalog;

what we just did:
– we created const GET_DOG query and we ‘asked’ GraphQL to getDogByBreed where breed = labrador (for more information of what queries you could execute, you could go to http://localhost:4001/graphql and look at the right side where the schema is defined or read more here)
– we wrapped our new component in Query tag, which passes down three properties: loading, error and data
– we showed the appropriate messages depending of the status of loading and error and on success we rendered the component, showing the returned data

Fire up the server using you prefered method, and  navigate to http://localhost:8080/dogs  and enjoy your new component, showing an image of nice black Labrador!

Refactoring the component.

Move the GraphQL query to a separate file.

Keeping things well organized is very important for maintainability and scaling reasons, so let’s move the query in a separate file.

./src/containers/DogsCatalog/index.js

import React from 'react';
import { graphql } from 'react-apollo';
import query from './query';


const DogCatalog = (props) => {
  if(typeof props.data.getDogByBreed === 'undefined') {
    return (
      <p>Loading ...</p>
    );
  }
  return(
    <div>
        <span>breed: </span>
        <span>{props.data.getDogByBreed.breed}</span>
        <br />
        <img src={props.data.getDogByBreed.displayImage} />
    </div>
  );
}

let breed = 'labrador';

export default graphql(query, {
  options: {
    variables: { 
      breed: breed
    } 
  } 
})(DogCatalog);

Create query.js file with the query.

./src/containers/DogsCatalog/query.js

import gql from 'graphql-tag';

const query = gql`
  query getDogByBreed($breed: String) 
  {
    getDogByBreed(breed: $breed) {
      id
      breed
      displayImage
    }
  }
`
export default query;

 what we just did:
– we moved the query to a separate file query.js
– we include the query (line 3)
– we wrapped the DogsCatalog component into GraphQL component, which will execute the query once the component is mounted, and will pass the result back into props.data .

Adding high order component with dogs breed buttons grid.

What we just created is more like a Dog Details component than Dog catalog, so let’s create a new folder under ./src/containers/DogsCatalog and name it DogDetails, and move  ./src/containers/DogsCatalog/index.js and ./src/containers/DogsCatalog/query.js to the new DogDetails folder.

Then create a new ./src/containers/DogsCatalog/index.js file which will show a gird with buttons, from where users can select which dog breed should be displayed into DogDetails component. Then we will pass the selected breed to the DogDetails component.

./src/containers/DogsCatalog/index.js

import React, { Component } from 'react';
import { graphql } from 'react-apollo';
import DogDetails from './DogDetails';
import query from './query';


class DogsCatalog extends Component {

  constructor(props) {
    super(props);
    this.state = {
        breed: "labrador"
    }
  }

  handleClick(breedType) {
    this.setState({
        breed: breedType
    });
  }

  render() {  
    if(typeof this.props.data.getDogsList == 'undefined') {
      return(
        <div>Loading ... </div>
      );
    }
    return(
      <div>
        <p>Dogs catalog</p>
        <div>
          {this.props.data.getDogsList.map( (dog) => {
            return (<button key={dog.id} onClick={ () => { this.handleClick(dog.breed) } }>{dog.breed}</button>);
          })}          
        </div>
        <DogDetails breed={this.state.breed} />
      </div>
    );
  }
}


export default graphql(query, {})(DogsCatalog);

 

./src/containers/DogsCatalog/query.js

import gql from 'graphql-tag';

const query = gql`
query getDogsList
{
  getDogsList {
    id
    breed
  }
}
`
export default query;

 

./src/containers/DogsCatalog/DogDetails/index.js

import React from 'react';
import { graphql } from 'react-apollo';
import query from './query';


const DogDetails = (props) => {
  if(typeof props.data.getDogByBreed === 'undefined') {
    return (
      <p>Loading ...</p>
    );
  }
  return(
    <div>
        <span>breed: </span>
        <span>{props.data.getDogByBreed.breed}</span>
        <br />
        <img src={props.data.getDogByBreed.displayImage} />
    </div>
  );
}

let breed = 'labrador';

export default graphql(query, {
  justADumFunction(ThePropsValuesPassedIntoTheFunction) {
    return {
      variables: {
        breed: ThePropsValuesPassedIntoTheFunction.breed,
      },
    };
  },
})(DogDetails);

 

./src/containers/DogsCatalog/DogDetails/query.js

import gql from 'graphql-tag';

const query = gql`
  query getDogByBreed($breed: String) 
  {
    getDogByBreed(breed: $breed) {
      id
      breed
      displayImage
    }
  }
`
export default query;

We could have download all dog details and pass it to the DogDetails component and save the second query, but for the purpose of exercising working with queries we are not going to do this. Besides imagine that we might need a lot more data for each breed then it’s not wise to pre-load it since this might take significant amount of time.

 

Beautify the component with SASS.

Let’s add some css.

create new file

./src/containers/DogsCatalog/styles.scss

.Wrapper {
  img {
    width: 100%;
  }
  .Buttons {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    grid-gap: 8px;
    max-width: 1200px;
    width: 100%;
    margin: 0 auto;    
  }

  .Buttons > button {
    background: efefef;
    border-radius: 5px;
    transition: 0.5s;
  }

  .Buttons > button:hover {  
    background: silver;
    color:white;
    cursor: pointer;
  }

}

and edit dogs component adding the css styles:

./src/containers/DogsCatalog/index.js

/* eslint-disable no-debugger */

import React, { Component } from 'react';
import { graphql } from 'react-apollo';
import DogDetails from './DogDetails';
import query from './query';

const styles = require('./styles.scss');


class DogsCatalog extends Component {

  constructor(props) {
    super(props);
    this.state = {
        breed: "labrador"
    }
  }

  handleClick(breedType) {
    this.setState({
        breed: breedType
    });
  }

  render() {  
    if(typeof this.props.data.getDogsList == 'undefined') {
      return(
        <div>Loading ... </div>
      );
    }
    return(
      <div className={styles.Wrapper}>
        <p>Dogs catalog</p>
        <div className={styles.Buttons}>
          {this.props.data.getDogsList.map( (dog) => {
            return (<button key={dog.id} onClick={ () => { this.handleClick(dog.breed) } }>{dog.breed}</button>);
          })}          
        </div>
        <DogDetails breed={this.state.breed} />
      </div>
    );
  }
}


export default graphql(query, {})(DogsCatalog);

Now our component looks much better.

We could have also move the presentational layer to the components instead, but since this is pretty small amount of code, we are not going to complicate it and will keep the presentational layer here for now.

branch-name:  
Click To Copy

 

 

 

Adding routing

branch-name:  
Click To Copy

Set up Express server to route all requests to the default ./index.html 

  • For CLI instance this could be achieved by just passing –history-api-fallback in package.json file.
    Give it a try: fire up the project using the cli settings yarn start-cli and go to http://127.0.0.1:8080/test for example and you will see the same homepage no matter what is the url.

./package.json

"scripts": {
  "start-cli": "webpack-dev-server --hot --history-api-fallback",
  "start-api": "babel-node server-api.js",
  "start-middleware": "babel-node server-middleware.js",
  "clean": "rm -rf ./dist",
  "lint": "eslint .",
  "build-dev": "webpack --mode development",
  "build-prod": "webpack --mode production"
},
  • For server using API config we are adding historyApiFallback: true (line 12) which basically tells the the dev server to fallback to the default file if it can’t find a route.

./server-api.js

/**
 * Runs a webpack-dev-server, using the API.
 */
import WebpackDevServer from 'webpack-dev-server';
import webpack from 'webpack';
import config from './webpack.api.config.js';

const compiler = webpack(config);
const server = new WebpackDevServer(compiler, {
  hot: true,
  publicPath: config.output.publicPath,
  historyApiFallback: true
});
server.listen(8080, 'localhost', function() {});
  • For the dev-middleware it a bit different approach since we are no longer using the built in express server in Webpack-dev-server since we have Express server already in place. So the solution is to tell Express server to accept all requests ‘*’ and to server the same index.html for all requests (line 18)

./server-middleware.js

const express = require('express');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const webpack = require('webpack');
const webpackConfig = require('./webpack.middleware.config.js');
const app = express();
const path = require('path');
const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
  hot: true,
  publicPath: webpackConfig.output.publicPath,
}));
app.use(webpackHotMiddleware(compiler, {
  log: console.log,
  path: '/__webpack_hmr',
  heartbeat: 10 * 1000,
}));
app.get('*', function(req, res) {
  res.sendFile(path.join(__dirname, 'index.html'));
});
const server = app.listen(8080, function() {
  const host = server.address().address;
  const port = server.address().port;
  console.log('App is listening at http://%s:%s', host, port);
});

We did this for all server configurations, but at the end we could just stick with only one, but for now we demonstrate how to set up all three configurations.

Let’s continue with setting up React router.

Setting up React router.

Install React-router-dom

yarn add react-router-dom

Before we continue, let’s add another component so we have two URLs to navigate to.

mkdir ./src/Components/About

and create a simple component that will display a message.

./src/Components/About/index.js

import React from 'react';


const About = () => (
  <div>
    <div>Wellcome to my tutorial!</div>
  </div>
)

export default About;

Now let’s move to adding the react router.

There are different palaces where we could ‘wrap’ our project components with Express router component. We could do it in ./src/index.js but I personally prefer to keep ./src/index.js as simple as possible and would move all complex logic into ./src/App/index.js 

./src/App/index.js

import React, { Component } from 'react';
import Greetings from '../Greetings';
import About from '../About';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

import styles from './styles.scss';
export default class App extends Component {
  render() {
    return (
      <div className={styles.appWrapper}>
        <Router>
          <Switch>
            <Route exact path="/greetings" component={() => <Greetings user="John"/> } />
            <Route exact path="/about" component={About} />
          </Switch>
        </Router>
      </div>        
    );
  }
}

what we just did:
– we added React router and Switch module.
– also we added two routes: ‘/greetings’, and ‘/about’ which will open the corresponding components.
– we wrapped ‘Greetings’ component into an inline function that passes the user parameter, otherwise if you try passing it into the route <Route user="John ... React router will simply ignore it.

Wrapping the component into an inline function to pass parameters will work but is not the best approach. The reason for this is because of performance. According to the official docs…

  “When you use the component props, the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component attribute, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component.”

So what is the better solution? Instead of using component, use the renderprop. render accepts a functional component and that function won’t get unnecessarily remounted like with component. That function will also receive all the same props that component would receive. So you can take those and pass them along to the rendered component.

Let’s fix this:

./src/App/index.js

import React, { Component } from 'react';
import Greetings from '../Greetings';
import About from '../About';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

import styles from './styles.scss';
export default class App extends Component {
  render() {
    return (
      <div className={styles.appWrapper}>
        <Router>
          <Switch>
            <Route exact path="/greetings" render={(props) => <Greetings {...props} user="John" />} />
            <Route exact path="/about" component={About} />
          </Switch>
        </Router>
      </div>        
    );
  }
}

Give it a try and navigate to http://localhost:8080/about  and http://localhost:8080/greetings

Great! Now we have React router set up with  two pages opening two different components.

Adding Navigation

Let’s create a component that will serve as a navigation menu mkdir ./src/components/Header

./src/components/Header/index.js

import React from 'react';
import { Link } from 'react-router-dom';

const styles = require('./styles.scss');

const Header = ( {title} ) => (
  <div>
    <div className={styles.wrapper}>
      <ul>
        <li><Link to='/home'>HOME</Link></li>
        <li><Link to='/greetings'>GREETINGS</Link></li>       
        <li><Link to='/about'>ABOUT</Link></li>
      </ul>
    </div>
  </div>
);

export default Header;

and let’s add styles:

./src/components/Header/styles.scss

.wrapper {
  
  ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;
    border: 1px solid #e7e7e7;
    background-color: #f3f3f3;
  }
  li {
    float: left;
  }

  li a {
    display: block;
    color: #666;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
  }

  li a:hover:not(.active) {
      background-color: #ddd;
  }

  li a.active {
      color: white;
    
  }
}

 

We used React Link component to allow users to navigate through the site.

Now put the component inside the <Router> component.

./src/components/App/index.js

import React, { Component } from 'react';
import Home from '../Home';
import Greetings from '../Greetings';
import About from '../About';
import Header from '../Header';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';

import styles from './styles.scss';
export default class App extends Component {
  render() {
    return (
      <div className={styles.appWrapper}>
        <Router>
          <Header />
          <Switch>
            <Route exact path="/home" component={Home} />            
            <Route exact path="/greetings" render={(props) => <Greetings {...props} user="John" />} />
            <Route exact path="/about" component={About} />
          </Switch>
        </Router>
      </div>        
    );
  }
}

You probably noticed that we have 2 pages but the navigation has 3 links. Let’s add another component just to have more pages to navigate through, besides we will need this component later in this tutorial  mkdir ./src/components/Home

./src/components/Home/index.js

import React from 'react';

const styles = require('./styles.scss');

const Home = () => (
  <div>
    <div className={styles.wrapper}>This is my home section!</div>
  </div>
)

export default Home;

./src/components/Home/styles.scss

.wrapper {
  background: rgb(141, 141, 172);
  color: white;
  text-align: center;
  font-family: MyFont;
}

Start the server and give it a try!

branch-name:  
Click To Copy

 

 

Adding React Library, SASS, Images and font loaders

branch-name:  
Click To Copy

 

React is cool frontend library that updates only the necessary portions of the html. Let’s add it to the project.

Adding React library

yarn add react react-dom

First, let’s keep things more consistent and do some house cleaning. Let’s rename ./src/app.js to ./src/index.js This will be the place where React app will be attached to our HTML and remove ./src/greeting.js

Also change Webpack entering point to reflect app.js filename change:

./webpack.config.js

entry: [
  './src/index.js'
],

Optionally but not necessarily  change the app.js to index.js in the package.json. It’s always a good practice to keep things consistent.

Alternatively you could simply ommit the name of the entrance and Webpack by default will look for src/index.js

Now Let’s do a react app. Remove ./src/app.js and ./src/greeting folder and let’s

Create simple react app

and place it into the components folder that we will create.

mkdir -p src/components/App

and add it’s index file

./src/components/App/index.js

import React, { Component } from 'react';


export default class App extends Component {

  render() {
    return (
      <div>
        <h1>React is running</h1>
      </div>
    );
  }
}

Attach React app to the main html

edit ./src/index.js remove it’s test contents and replace it with this:

./src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

ReactDOM.render(<App/>, document.getElementById('root'));

if (module.hot) {
  module.hot.accept();
}

What we just did:
– we imported React and React dom library. React dom is needed to attach React app to the HTML
– we imported newly created React app
– we attached the app to the root container.
– we also added the HMR activation script.

One last thing before we are ready to test is to add the html container where the react app will be attached.

./index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Babel Webpack Boilerplate</title>
    </head>
    <body>
        <h1>Babel Webpack React Boilerplate</h1>
        <div id="root"></div>
        <script type="text/javascript" src="dist/main-bundle.js"></script>
    </body>
</html>

 

Start the project yarn start

Oh snap! Dev server crashed with error message:
ERROR in ./src/index.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /Users/toninichev/Examples/WebpackReactReduxApolloTutorial/.babelrc: Error while parsing config – JSON5: invalid end of input at 1:1

Why this is happening? We replaced the plain JavaScript form ./src/index.js with JSX syntax that react is using but Babel doesn’t know how to transpile this. Let’s fix it and add in .babelrc config, the react preset plug-in, and install it.

yarn install @babel/preset-react --dev

./.babelrc

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

Right now we need only @babel/preset-react” and @babel/preset/env plug-ins, but in the feature we will have to use more of the advanced ES6 syntax and add more.

Give it another shot and do yarn start

At this point we should have working react app!

Create React component

Let’s re-create ‘greetings’ component but this time making it React component. Create Greetings folder  mkdir -p ./src/components/Greetings folder and add:

./src/components/Greetings/index.js

import React from 'react';

function Greetings(props) {
  return <div>Hello, {props.user}</div>;
}

export default Greetings;

and render the component.

./src/components/App/index.js

import React, { Component } from 'react';
import Greetings from '../Greetings';

export default class App extends Component {

  render() {
    return (
      <div>
        <h1>React is running</h1>
        <Greetings user="John" />
      </div>
    );
  }
}

What we just did:
– in ./src/greetings/index.js we created a new Greetings component that will take property of the user passed from the higher component and show it. Props stands short for properties.
– in ./src/components/app/index.js we are loading the Greetings component and passing the user name as a property to the Greeting component.

Webpack loaders.

Webpack loaders  allow us to bundle any static resource way beyond JavaScript.

Using SCSS and adding SASS loader.

So far so good. We could see our new React component rendering but no styles.
The simplest way to style our components could be to add css-loader and then to inject the css into the DOM using style-loader.

...
    {
      test: /\.(s)?css$/,
      use: [
        'style-loader',
        'css-loader'
      ]
    },
...

 

But it could be really nice if we could add specific styles only applying to this component.

Go to the terminal, and install these modules:

yarn add style-loader --dev
yarn add css-loader --dev
yarn add postcss-loader --dev
yarn add sass-loader --dev
yarn add node-sass --dev
yarn add autoprefixer --dev

Add the highlighted lines in webpack.config.js

./webpack.config.js

module.exports = {
  mode: 'development',
  entry: [
    '@babel/polyfill',    
    './src/index.js'
  ],
  output: {
    filename: '[name]-bundle.js',
    publicPath: '/dist',
  },  
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },
      // SCSS
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              importLoaders: 2,
              localIdentName: '[folder]-[local]',
              sourceMap: true
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins: () => [require('autoprefixer')()],
              sourceMap: true

            },
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'expanded',
              sourceMap: true
            }
          }
        ],
      }      
    ]
  }
};

 

 what we just did:
– added sass-loader which will first convert SCSS to plain CSS
– added postcss-loader interprets @import and url() like import/require() and will resolve them.
– added style-loader simply inserts the css into the DOM

Let’s add some styling for our new greetings component:

./src/components/Greetings/styles.scss

.wrapper {
  background: blue;
  h2 {
    color: white;
  }
}

and let’s load it and style the component:

./src/components/Greetings/index.js

import React from 'react';

const styles = require('./styles.scss');

function Greetings(props) {
  return <div className={styles.wrapper}><h2>Hello, {props.user}</h2></div>;
}

export default Greetings;

What we just did:
– we added the new style that will be loaded by JavaScript into the new component (line 3)
– we applied the new style (line 6) by using JSX way of doing this.

If you are not familiar with React and JSX please read the React tutorial first.

Congratulations! Now you have React component that could really be in use!

Adding image loader.

Let’s add url-loader and file-loader and save them as a dev dependencies.

yarn add url-loader file-loader --save

Download a small Home Icon that we are going to add it to our greeting component, and save it into a new folder under ./src folder./src/images/home.png (Make sure that you renamed the file to home.png ). Now let’s add the Webpack config to load images:

./webpack.config.js

import webpack from 'webpack';
import getEnvironmentConstants from './getEnvironmentConstants';

module.exports = {
  mode: 'development',
  devtool: 'eval-source-map',
  entry: [
    '@babel/polyfill',
    './src/index.js',
    'webpack/hot/dev-server',
    'webpack-dev-server/client?http://localhost:8080/',
  ],
  output: {
    filename: '[name]-bundle.js',
    publicPath: '/dist',
  }, 
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({ 'process.env' : getEnvironmentConstants() } )
  ],   
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },


      // SCSS
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              importLoaders: 2,
              localIdentName: '[folder]-[local]',
              sourceMap: true
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins: () => [require('autoprefixer')()],
              sourceMap: true
            },
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'expanded',
              sourceMap: false
            }
          }
        ],
      }, 
      
      // images
      {
        test: /\.(png|jp(e*)g|svg)$/,  
        use: [{
            loader: 'url-loader',
            options: { 
                limit: 8000, // Convert images < 8kb to base64 strings
                name: 'images/[hash]-[name].[ext]'
            } 
        }]
      }      
      
    ],
  }
};

 what we just did:
– we are testing files for image type (line 64) (png, gpeg or gpg, svg)
– we are using url-loader to load the images.
– url-loader – limit: 8000 means that any image smaller than 8kb will be converted to base64 string and inlined in the bundle. Any other image will be passed to the loader that will pass it as a file.

An now let’s use the image in our Greetings component:

./src/components/Greetings.js

import React from 'react';
const styles = require('./styles.scss');
import homeIcon from '../../images/home.png';

function Greetings(props) {

  return (<div className={styles.wrapper}>
            <img height='75px' width='75px' src={homeIcon} /> 
            <h2>Hello, {props.user}</h2>
          </div>);
}
export default Greetings;

Navigate to the greeting component, and we should see the house image there.

Let’s also check if we can add the image url in the CSS. Remove the image tag from the file above, and add it in the greeting CSS

./src/components/Greetings/styles.scss

.wrapper {
  background-image:url('../../images/home.png');
  height: 500px;
  h2 {
    color: black;
  }
}

navigate to the page again and you will see a big background house in the component.

Adding fonts loader.

Loading fonts is as easy as adding another file-loader as it is shown below.

./webpack.config.js

module.exports = {
  mode: 'development',
  entry: [
    '@babel/polyfill',    
    './src/index.js'
  ],
  output: {
    filename: '[name]-bundle.js',
    publicPath: '/dist',
  },  
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      },

      // SCSS
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              importLoaders: 2,
              localIdentName: '[folder]-[local]',
              sourceMap: true
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              plugins: () => [require('autoprefixer')()],
              sourceMap: true
            },
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'expanded',
              sourceMap: true
            }
          }
        ],
      },
      // images
      {
        test: /\.(png|jp(e*)g|svg)$/,  
        use: [{
            loader: 'url-loader',
            options: { 
                limit: 8000, // Convert images < 8kb to base64 strings
                name: 'images/[hash]-[name].[ext]'
            } 
        }]
      },
      //File loader used to load fonts
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: ['file-loader']
      }                    
    ]
  }
};

then we could download some font for example from fonts.google.com or here and add the font in the css using font face:

./src/components/App/styles.scss

@font-face {
  font-family: 'MyFont';
  src:  url('../../fonts/aclonica/aclonica-regular.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
}

.appWrapper {
  background: rgb(141, 141, 172);
  color: white;
  text-align: center;
  font-family: MyFont;
}

 

Modifying component to use latest ES syntax.

We want to be cool devs and to use the latest technologies so let’s modify our Greeting component to use the latest ES6 syntax and take advantage of Babel that we installed in the previous chapters.

Modify greetings index file as follows:

./src/components/Greetings/index.js

import React from 'react';
import styles from './styles.scss';

function Greetings(props) {
  return(<div className={styles.wrapper}>
          <h2>Hello, {props.user}</h2>
        </div>);
}
export default Greetings;

What we just did:
– (line 2) we refactored the component to use the latest EC6 syntax by replacing require with import
– we removed the image tag since now we are loading the image-background from CSS.

 

branch-name:  
Click To Copy

 

Adding Webpack-dev-server

branch-name:  
Click To Copy

Ading Webpack-dev-server

what is webpackdevserver ? Like it was said  “The webpackdevserver is a little Node.js Express server, which uses the webpackdev-middleware to serve a webpack bundle. It also has a little runtime script, which is connected to the server via Sock.js. The server emits information about the compilation state to the client, which reacts to those events.

Basically webpack-dev-server is handy dev tool that is not only an HTTP server but it could monitor your files for changes and rebuild the bundle and serve it from memory which speeds up the developing process.

Let’s add webpack-dev-server so we could open the project via http. Additionally  Webpack dev server adds a few more benefits like live reloading for the client side code.
Webpack dev server like it’s name suggests should be used only for development and never in production.

yarn add webpack-dev-server --dev

Let’s add a script to execute it through Yarn/NPM. Also, since we have the entry and the output set up in webpack.config.js we can simplify the build-dev and build-prod scripts as well.

  "scripts": {
    "start": "webpack-dev-server",
    "clean": "rm -rf ./dist",
    "lint": "eslint .",
    "build-dev": "webpack --mode development",
    "build-prod": "webpack --mode production"
  }

Let’s give it a try and start the server:

yarn start

and point the browser to http://localhost:8080/

If everything worked fine, you should be able to see the project and the console message.

But bundle file is still served statically from the ./dist` folder instead of bundled dynamically from Webpack-dev-server and serving it from memory,  and you could confirm this by deleting the ./dist folder, and restarting the server. And you will get this error message in the console.

GET http://localhost:8080/dist/main-bundle.js net::ERR_ABORTED 404 (Not Found)

As you see bundle file is not there, instead Webpack-dev-server is serving it from here:http://localhost:8080/main-bundle.js
Point your browser there and you will see the bundle file. Let’s fix this. Open ./webpack.config.js and add the highlighted lines:

./webpack.config.js

module.exports = {
  mode: 'development',
  entry: [
    '@babel/polyfill',
    './src/app.js'
  ],
  output: {
    filename: '[name]-bundle.js',
    publicPath: '/dist',
  },  
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};

This instructs Webpack-dev-server to serve the bundle from ./dist location but this time the bundle will be dynamically generated by Webpack-dev-server, instead of statically served from the ./dist location.

The advantage is that the bundle will re-generate on change and the location will be the same as the production location but just served from the memory.
Reload the browser and now the error message in the console is gone, and if you navigate to `http://localhost:8080/dist/main-bundle.js` you will see newly generated bundle.

 Webpack-dev-server is serving the bundle from memory. You could go ahed and delete ./dist folder and reload the server and the main bundle should still be accessible.

Set up Webpack to monitor your project’s folder for changes and rebuild the bundle.

Webpack-dev-server comes with very handy option --watch to monitor for changes, rebuild the bundle and restart the browser.
The god news is that by default the --watch` mode it turned on so if you go and do some changes into any file under ./src folder and save it, you will see in the console that Webpack-dev-server will re-generate the bundles and the browser will restart and reflect the changes.

There are two ways of setting up Webpack-dev-server to reload the page:

  • Iframe mode (page is embedded in an iframe and reloaded on change)
  • Inline mode (a small webpack-dev-server client entry is added to the bundle which refreshes the page on change)

But we could go even further.

Adding Hot Module Replacement plug-in.

Having Webpack-dev-server to reload our page and reflect the changes is cool but we still reload the whole page and components state is reset back to the initial state. We could tell Webpack-dev-server to use hot module replacement plugin (HMR) to re-load only the components that did change, but before doing this, let’s make some real component that will show something in the website instead of the console.

Remove ./src/test.js.

Let’s create greeting component that will simply show a greeting in the webpage.
create folder called ‘greeting’ and file in ./src/greeting/index.js with these contents:

./src/greeting/index.js

function doGreeting(name) {
  return "Hello " + name;
}
module.exports = doGreeting;

edit ./src/app.js to load the new component and attach the result to an HTML div component. We have to also add the highlighted if statement that will enable HMR.

./src/app.js

var greeting = require('./greeting');

var result = greeting("John");
document.querySelector('#root').innerHTML = result;


if (module.hot) {
  module.hot.accept();
}

and edit index.html to have a div component with id=”root” that  will be the entry point for our app and will show the result of our greeting component.

./index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Babel Webpack Boilerplate</title>
    </head>
    <body>
        <div id="root"></div>
        <script type="text/javascript" src="dist/main-bundle.js"></script>
    </body>
</html>

Last step is to tell Webpack-dev-server to use HMR.

./package.json

{
  "name": "babel-webpack-react-boilerplate",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "devDependencies": {
    "@babel/core": "^7.1.2",
    "@babel/preset-env": "^7.1.0",
    "@babel/preset-react": "^7.0.0",
    "babel-eslint": "^10.0.1",
    "babel-loader": "^8.0.4",
    "eslint": "^5.7.0",
    "eslint-loader": "^2.1.1",
    "eslint-plugin-react": "^7.11.1",
    "webpack": "^4.20.2",
    "webpack-cli": "^3.1.2",
    "webpack-dev-server": "^3.1.9"
  },
  "scripts": {
    "start": "webpack-dev-server --hot",
    "clean": "rm -rf ./dist",
    "lint": "eslint .",
    "build-dev": "webpack --mode development",
    "build-prod": "webpack --mode production"
  }
}

what we just did:
– we added --hot parameter to tell Webpack-dev-server to use HMR.

Go ahead, restart the server and give it a try and now if you change something in ./src folder the browser will reflect the changes without reloading. (you could observe the reload button and it will never show reload). Also if you look at browser’s console you will see the messages from HMR

[HMR] Waiting for update signal from WDS…
client:71 [WDS] Hot Module Replacement enabled.

Now development process could really speed up!

branch-name:  
Click To Copy

 

Setting up SSL host using LetsEncrypt free certificate and set up auto renewal shell script.

1. Obtain SSL certificates from the letsencrypt.org ACME server.Navigate to the location that you would like to add the script. I personally prefer to keep apps and scripts here:
cd ~/Applications

2. Download getssl (this is the auto renewal shell script)
git clone https://github.com/srvrco/getssl.git

4. Do initial setup
 ./getssl -c yourdomain.com

this command will create the following folders and files:

~/.getssl
~/.getssl/getssl.cfg
~/.getssl/yourdomain.com
~/.getssl/yourdomain.com/getssl.cfg

5. Edit ~/.getssl/getssl.cfg There are a couple of things that we have to set up:
– make sure that you switch to use the staging server while testing, since the production one has rate limits.

# The staging server is best for testing
CA="https://acme-staging.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"

6.Add the sub domains in ~/.getssl/yourdomain.com/getssl.cfg

# Additional domains - this could be multiple domains / subdomains in a comma separated list
# Note: this is Additional domains - so should not include the primary domain.
SANS="www.mysite.com, other.mysite.com"

– Very important: add the location where the script should put verification file in order to prove that you have ownership over this domain. For more information of what exactly is the prove of ownership procedure you could read https://letsencrypt.org/how-it-works/ but basically the bash script puts a small file into specific server directory and then the letsencrypt server checks id the file is there and ensures that you have control over this domain.
So Make sure that this folder (acme-challenge) is accessible on the web.
What that means is that if you put a test text file (e.e. test.txt) with any random text inside in this location: /webroot/.well-known/acme-challenge and then you open the browser and point to www.mysite.com/.well-known/acme-challenge/test.txt you should be able to see the contents of the file.
Once you did this you could go ahead and edit .getssl file and add the right location.

# Acme Challenge Location. The first line for the domain, the following ones for each additional domain.
# If these start with ssh: then the next variable is assumed to be the hostname and the rest the location.
# An ssh key will be needed to provide you with access to the remote server.
# Optionally, you can specify a different userid for ssh/scp to use on the remote server before the @ sign.
# If left blank, the username on the local server will be used to authenticate against the remote server.
# If these start with ftp: then the next variables are ftpuserid:ftppassword:servername:ACL_location
# These should be of the form "/path/to/your/website/folder/.well-known/acme-challenge"
# where "/path/to/your/website/folder/" is the path, on your web server, to the web root for your domain.
#ACL=('/var/www/toninichev.com/web/.well-known/acme-challenge'
#     'ssh:server5:/var/www/toninichev.com/web/.well-known/acme-challenge'
#     'ssh:sshuserid@server5:/var/www/toninichev.com/web/.well-known/acme-challenge'
#     'ftp:ftpuserid:ftppassword:toninichev.com:/web/.well-known/acme-challenge')

ACL=('/var/www/html/projects/src/webroot/.well-known/acme-challenge')

 Make sure that you replace /var/www/html/projects/src/ with the actual location on your server.
– one last thing that I did is to use single ACL to make my life easier

#Set USE_SINGLE_ACL="true" to use a single ACL for all checks
USE_SINGLE_ACL="true"

7. Execute the script and create certificate

~/Applications/getssl yourdomain.com

Again make sure that you navigate to the place where you did git clone of the script.

Example of adding certificate to an express server:

var options = {
    key: fs.readFileSync('/Users/toninichev/.getssl/mysite.com.key'),
    cert: fs.readFileSync('/Users/toninichev/.getssl/mysite.com.crt')
    };

/**
 * HTTP Server
 * Gets post requests from app_clients and sends data to the web_clients
 */
var app = https.createServer(options, function (request, response) {
...
});

Example of adding certificate to Apache virtual host:

<VirtualHost *:443>

    ServerName mywebsite.com
    ServerAlias www.mywebsite.com
    ServerAdmin info@mywebsite.com

    SSLEngine on
    SSLCertificateFile /Users/toninichev/.getssl/mywebsite.com/mywebsite.com.crt
    SSLCertificateKeyFile /Users/toninichev/.getssl/mywebsite.com/mywebsite.com.key

    ErrorLog "/private/var/log/apache2/mywebsite.com-error_log"
    CustomLog "/private/var/log/apache2/mywebsite.com-access_log" common

    SetEnv APPLICATION_ENV production
    DocumentRoot "/Users/toninichev/mywebsite/app/webroot"
    <Directory "/Users/toninichev/mywebsite/app/webroot">
        Options Indexes FollowSymLinks
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

 

 

Median of Two Sorted Arrays

Task

Task:

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

This problem was taken from Leetcode

Solution


Using a brute force we could merge the two arrays and find the median, but this is slow.
To optimize the solution we could use one of the properties of the arrays: the arrays are sorted.
– We could substitute the problem of find the median with find the numbers that are not in the median

Two sum diagram

The solution:

Java Script

/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number}
 */
var findMedianSortedArrays = function(nums1, nums2) {

	function findMedianIndex(arr) {
		var median = 0;
		var i = 0;
		if(arr.length % 2) {
			var i = (arr.length / 2 + 0.5) - 1;
			median = arr[i];
		}
		else {
			var i = (arr.length / 2);
			median = ((arr[i - 1] + arr[i]) / 2);
		}
		return median;
	}

	function isFirstArrayInTheMiddleOfSecondEvenArray(x, y) {		
		var minX = x[0];
		var maxX = x [1];
		var medianY = Math.floor(y.length / 2);
		var leftMiddleY = y[medianY - 1];
		var rightMiddleY = y[medianY];
		return minX > leftMiddleY && maxX < rightMiddleY; } function findMedianOfArrayAndValue(arr, val) { if(arr.length == 0) { return val; } else if (typeof(val) == 'undefined') { return findMedianIndex(arr); } var median = 0; if(arr.length % 2) { // odd aray // var medianIndex = Math.floor((arr.length / 2)); // median = arr[medianIndex]; var arrMedian = findMedianIndex(arr); if(arrMedian > val) {
				// the median of merged array should lie on the left of arr  <== var i = Math.floor(arr.length / 2); var right = arr[i]; var left = Math.max( arr[i - 1], val ); return findMedianIndex( [left, right] ); } else { // the median of merged array should lie on the right of arr ==>
				var i = Math.floor(arr.length / 2);
				var left = arr[i];				
				var right = Math.min( arr[i + 1], val );
				return 	findMedianIndex( [left, right] );					
			}
		}
		else {
			// even aray
			var arrMedian = findMedianIndex(arr);
			if(arrMedian > val) {
				// the median of merged array should lie on the left of arr median  <== var i = Math.floor((arr.length / 2) - 1); var left = arr[i]; return Math.max(left, val); } else { // the median lies on the right side ==>
				var i = (arr.length / 2);
				var right = arr[i];
				return Math.min(right, val);
			}

			median = findMedianIndex( [ arr[medianIndex], arr[medianIndex + 1] ]);

		}
		return ( Math.min(median, val) + Math.max(median, val) ) / 2;
	}


	function findMedian(X, Y) {

		// check all odd cases	
		if (X.length === 1 && Y.length === 1) {
			return (X[0] + Y[0]) / 2;
		}

		if(X.length <= 1) {
			return findMedianOfArrayAndValue(Y, X[0]);
		}
		else if(Y.length <= 1) {
			return findMedianOfArrayAndValue(X, Y[0]);
		}		
		else if(X.length == 1 && Y.length == 1) {
			var testArray = [ X[0], Y[0] ];
			return findMedianIndex(testArray);
		}
		else if(X.length < 1) {
			var testArray = Y.concat(X);
			return findMedianIndex(testArray);	
		}
		else if( Y.length < 1) { var testArray = X.concat(Y); return findMedianIndex(testArray); } if( X.length === 2 && Y.length >= 2 && Y.length % 2 === 0) {
			if(isFirstArrayInTheMiddleOfSecondEvenArray(X, Y)) {
				/*
					in example:
					var X = [1, 2];
					var Y = [-1, 3];
				*/
				return (X[0] + X[1]) / 2;
			}
		}
		if( Y.length === 2 && X.length >= 2 && X.length % 2 === 0) {
			if(isFirstArrayInTheMiddleOfSecondEvenArray(Y, X)) {
				/* and the other way */
				return (Y[0] + Y[1]) / 2;
			}
		}	

		var mX = findMedianIndex(X);
		var mY = findMedianIndex(Y);
		
		if(mX == mY) {
			return mX;
		}
			

		var splicePart = Math.floor(Math.min(X.length / 2 - 1, Y.length / 2 - 1));
		splicePart = splicePart < 1 ? 1 : splicePart;

		if (mX < mY) {
			X.splice(0, splicePart);
			Y.splice(Y.length - splicePart);
		} else {
			X.splice(X.length - splicePart);
			Y.splice(0, splicePart);
		}
	

		return findMedian(X, Y);
	}

	return findMedian(nums1, nums2);
}

Linked Lists

Linked list

Singly-linked list example implementation in Java Script

Let’s store these values from the diagram above in linked list.

Using Object:

const list = {
    head: {
        value: 20,
        next: {
            value: 18,
            next: {
                value: 15,
                next: {
                    value: 67,
                    next: null
                }
            }
        }
    }
};


/* example of retrieving the value at second position */

console.log(list.head.next); // the result should be 18

 

Using class

function ListNode(val) {
    this.val = val;
    this.next = null;
}

var linkList = new ListNode(20);
linkList.next = new ListNode(18);
linkList.next.next = new ListNode(15);
linkList.next.next.next = new ListNode(67);
linkList.next.next.next.next = null;

/* example of retrieving the last value */
console.log(linkList.next.next.next); // the result should be 67

 

Traversing double linked list example

var list  = {
  one: {value: 1, prev: null, next: null},
  two: {value: 2, prev: null, next: null},
  three: {value: 3, prev: null, next: null}
}

var root = list.one;

list.one.next = list.two;
list.two.prev = list.one;
list.two.next = list.three;
list.three.prev = list.two;

var i = 0;

var element = root;
var loop = true;

while(loop == true) {
  console.log(">>", element.value);
  if(element.next == null)
      loop = false;
  element = element.next;
}

 

Two Sum

Task

Task:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Examples :

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

This problem was taken from Leetcode

Solution

One pass hash table.

Let’s take this example: nums = [2, 7, 11, 15], target = 9
The brute force solution might be to loop through each value in the nums array, and to add with each other value in the array and to compare with the target result.

Optimize the algorithm using hash table

The idea is to store the array into a hash table where keys will be the values of the array (i.e: 2, 7, 11, 15) and the values: the element index (i.e: 0,1,2,3)
key:value
2 : 0,
7 : 1,
11:2,
15:3

Two sum diagram

This way all we need to do is:
– Iterate through the array once.
– For each value calculate what number could add to the target value ( x = target – nums[i])
– Dynamically add the next key-value pair into the hashmap

The solution:

Java Script

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
    var hashMap = {};


    for(var i in nums) {                
            
        var test = target - nums[i];
        if(hashMap[test]) {
            return [parseInt(hashMap[test]), parseInt(i)];
        }     
        var key = nums[i];
        hashMap[key] = i;   
    }
};

C++

class Solution {
    
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        
        vector<int> result;

        std::map<int, int> buffer;
        for(int i = 0;i < nums.size(); i++) {
            int key = nums[i];
            int test = target - nums[i];

            if(buffer[test] != 0) {
                result = {buffer[test] -1, i};
                break;
            }
            buffer[key] = i + 1;
        }
        return result;
    }
};

 

Running GraphQL with Express sever

Create the project with all dependencies.

Create new node project -y will answer yes to all questions during setting up the project to save us some time.

yarn init -y

add the libraries:

yarn add graphql express express-graphql

what we just did:
– created new npm project (-y answering yes on all questions)
– installed graphQL (–save locally in project’s node_modules folder)
– installed Expless server with Express-graphQL module locally

Create server.js

Create ./server.js in the root folder with the following contents:

var express = require('express');
var { graphqlHTTP } = require('express-graphql');
var { buildSchema } = require('graphql');

// Construct a schema, using GraphQL schema language
var schema = buildSchema(`
  type Query {
    hello: String
  }
`);
// The root provides a resolver function for each API endpoint

var root = {
  hello: () => {
    return 'Hello world!';
  },
};

var app = express();
app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true,
}));

app.listen(4000);
console.log('Running a GraphQL API server at localhost:4000/graphql');

what we just did:
– we created a schema (lines 6-10)
– created a resolver function for our schema (lines 13-17)
– created Express http server (line 19)
– tell Express http server to use graphQL library (lines 20-24)

Now everything is almost ready. Let’s create a start script and run our server.

Create the start script.

Open ./package.json and add the highlighted lines:

{
  "name": "graphql-test",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "node server.js"
  },  
  "dependencies": {
    "express": "^4.16.4",
    "express-graphql": "^0.7.1",
    "graphql": "^14.0.2"
  }
}

Run GraphQL server.

Open terminal, navigate to the root folder and execute the start script:

yarn start

Since we configured graphqlHTTP with graphiql: true (line 23) we can access GraphQL UI tool and execute queries.
Navigate the browser to http://localhost:4000/graphql and run { hello } and the result should look like the one in the image below:

Congratulations! You just ran your first GraphQL server!

Server Side Rendering

branch-name:  
Click To Copy

The motivation: why doing it?

Now we have a production build which works great, but when search engines look at your site they will see this:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Babel Webpack Boilerplate</title>
        <link rel="stylesheet" type="text/css" href="dist/main.css">
    </head>
    <body>
        <div id="root"></div>
        <script type="text/javascript" src="dist/main-bundle.js"></script>
    </body>
</html>

and will have no idea what this site is about and how to index it.

Good search engines like Google will render the JS and will get the right idea but there are also other benefits of having SSR.

Benefits:
Quicker page render. Once the source code is there, with all assets (CSS, JS, Images, fonts, etc) is sent to the browser, it could start render it and it could show the site like it was already ready for use (although the events won’t be attached at this point and the site won’t be really ‘clickable’ the user will at least see a fully rendered site which gives him the perception of a fully ready site)
SCO benefits
Pages could be pre-rendered on the server and cached.

So. let’s dive into this:

SSR Checklist

This might be more complicated task that we would expect so let’s outline a checklist of what have to be done to achieve SSR:

  • Fetch all GraphQL queries on the backend before start generating the source code.
    Some components rely on having their data fetched from GraphQL before render.
    For example, If you remember we dynamically fetch the page components layout from GraphQL so in order to serve the page source, we have to make the page query and return the list of all components for the current route. For example the ‘/home’ page should hare 2 components: header and Home components.
  • Make sure that bundle splitting will continue work.
  • Fetch only assets that are necessary to be served for each particular route.
    We have to pre-render the page, and figure out which JS and CSS bundles should be added in the source code. For example for the home page ‘/home’ we have to include:
    <script src=’dist/header.js’/></script>
    <link href=”/dist/header.css”/><script src=’dist/home.js’/></script>
    <link href=”/dist/home.css”/>
  • Finally fetch the source code string and send it to the browser.

 

Adding server side rendering  (SSR).

Let’s start with adding the server side rendering script, and the script that will run it.

Adding ssr build script

./package.json

"scripts": {
  "start-cli": "webpack-dev-server --hot --history-api-fallback --config webpack.cli.config.js",
  "start-api": "babel-node server-api.js",
  "start-middleware": "babel-node server-middleware.js",
  "clean": "rm -rf ./dist ./server-build",
  "lint": "eslint .",
  "build-dev": "webpack --mode development",
  "build-prod": "webpack --config webpack.prod.config.js",
  "build-ssr": "webpack --config webpack.server.config.js",
  "run-server": "node ./server-build/server-bundle.js",
  "start": "yarn clean; yarn build-prod; yarn build-ssr; yarn run-server"
},

what we just did:
– (line 9) adding build-ssr script to bundle the express server into a executable JS
– (line 10) adding start script to run the express server which will:
1. send the page source to the browser.
2. serve the static production bundle.
3. serve all other assets (images, fonts, etc)
– remove run-prod-server  and build-and-run-prod-server  since we are replaced them with the new scripts.
– add `server-build` to the cleaning script since this is the location where the server bundle will be dumped.

Creating SSR config

Since most of the configuration will be similar to the production config, let’s start by copying the production config into a new file called ./webpack.ssr.config.js and do some adjustments specific for SSR.

./webpack.ssr.config.js

const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
let config = require('./webpack.base.config.js');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

config.mode = "production";
config.devtool = "";
config.target = "node";
config.externals = [nodeExternals()];

config.entry = {
    server: './ssr-server.js'
  }

config.output = {
    filename: '[name]-bundle.js',
    path: path.resolve(__dirname, 'server-build')    
}

config.module.rules[1].use[0] = MiniCssExtractPlugin.loader;
config.plugins = [ 
    ... config.plugins,
    ... [
        new MiniCssExtractPlugin({
            filename: "[name].css"
        }), 
        new OptimizeCSSAssetsPlugin({}),  
        // on the server we still need one bundle
        new webpack.optimize.LimitChunkCountPlugin({
            maxChunks: 1
        })
    ]
];
module.exports = config;

what we just did:
– (line 10) we told Webpack that this bundle will not run in the browser but in the ‘node’ environment.
– (line 11) we aded Webpack Node Externals which will remove the node_modules which we don’t need when execute in ‘node’ environment.
– (line 14) specifies a new entry point for the SSR, that will run the express server (similar to the one that we built for production)
– (line 31) on the server side we still need one bundle file.

Now let’s add the missing module:

yarn add webpack-node-externals --dev

Adding Express server

This is going to be the same Express server that we added in the previous chapter to serve the  production requests, but settings will be much more complex to fit the SSR needs. Create ssr-server.js with the following content:

./ssr-server.js

import React from 'react';
import express from 'express';
import App from './src/components/App/ssr-index';
import Loadable from 'react-loadable';
import manifest from './dist/loadable-manifest.json';
import { getDataFromTree } from "react-apollo";
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { renderToStringWithData } from "react-apollo"
import { createHttpLink } from 'apollo-link-http';
import { getBundles } from 'react-loadable/webpack';

const PORT = process.env.PROD_SERVER_PORT;
const app = express();

app.use('/server-build', express.static('./server-build'));
app.use('/dist', express.static('dist')); // to serve frontent prod static files
app.use('/favicon.ico', express.static('./src/images/favicon.ico'));

app.get('/*', (req, res) => {
  const GRAPHQL_URL = process.env.GRAPHQL_URL;
  const client = new ApolloClient({
    ssrMode: true,
    link: createHttpLink({
     uri: GRAPHQL_URL,
     fetch: fetch,
     credentials: 'same-origin',
     headers: {
       cookie: req.header('Cookie'),
     },
   }), 
    cache: new InMemoryCache()
  });    

  // Prepare to get list of all modules that have to be loaded for this route
  const modules = [];
  const mainApp = (
    <Loadable.Capture report={moduleName => modules.push(moduleName)}>
      <App req={req} client={client} />
    </Loadable.Capture>    
  );

  // Execute all queries and fetch the results before continue
  getDataFromTree(mainApp).then(() => {        
    // Once we have the data back, this will render the components with the appropriate GraphQL data.
    renderToStringWithData().then( (HTML_content) => {       
      // Extract CSS and JS bundles
      const bundles = getBundles(manifest, modules); 
      const cssBundles = bundles.filter(bundle => bundle && bundle.file.split('.').pop() === 'css');
      const jsBundles = bundles.filter(bundle => bundle && bundle.file.split('.').pop() === 'js');
    
      res.status(200);
      res.send(`<!doctype html>
      <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Server Side Rendering and Bundle Splitting</title>
        <link
        href="/dist/main.css"
        rel="stylesheet"
        as="style"
        media="screen, projection"
        type="text/css"
        charSet="UTF-8"
      />
        <!-- Page specific CSS bundle chunks -->      
        ${
          cssBundles.map( (bundle) => (`
            <link
              href="${bundle.publicPath}"
              rel="stylesheet"
              as="style"
              media="screen, projection"
              type="text/css"
              charSet="UTF-8"
            />`)).join('\n')
        }
        <!-- Page specific JS bundle chunks -->
        ${jsBundles
          .map(({ file }) => `<script src="/dist/${file}"></script>`)
          .join('\n')}
        <!-- =========================== -->
      </head>
      <body cz-shortcut-listen="true">
        <div id="root"/>
          ${HTML_content}
        </div>
        <script>
        window.__APOLLO_STATE__=${JSON.stringify(client.cache.extract())};
        </script>
      
        <script src="/dist/main-bundle.js"></script>
      </body>
    </html>`);
      res.end(); 
    });    

  }).catch( (error) => {
    console.log("ERROR !!!!", error);
  });
});

Loadable.preloadAll().then(() => {
  app.listen(PORT, () => {
    console.log(`? Server is listening on port ${PORT}`);
  });
});

what we just did:
Clearly a lot of stuff so let’s take one step at a time.
– We created express server similar to the one we did for production in the previous chapter.
  – (line 13,14) we created the server, telling it to run on the port that we will specify in the .env file later in this tutorial.
– (line 20) we are telling Express to listen to any request pattern, except for these above described in app.use 
– (line 53) sending the html to the browser.
– We fetch the data for all queries in the app before continue.
  – (lines 21-33) We created the Apollo client.
– (line 44) calling getDataFromTree from react-apollo will walk through the React tree to find any components that make GraphQL requests. It will execute the queries and return a promise.
– (line 46) calling renderToStringWithData  will render the app with the necessary GraphQL data.
– (line 90) since we already fetched all data,  we are going to stringify it, and attach it to the window object so it could be re-used on the client side.  this part is very important. It does so called Store hydration. If we miss it we will end up making twice more queries to GraphQL: one set on the server side, and one set on the client side.
– We get a list of all components that will have to render for the particular route, and create appropriate SCRIPT and LINK tags to load JS and CSS only for these components.
  – (line 38) we use Loadable.Capture from react-loadable to create an array of all components that exist in the particular route and store it in modules = []
– (lines 48 – 50) Will extract the CSS and JS bundle file lists
– ( lines 67 – 83) will traverse CSS and JS arrays and will create the appropriate CSS and JS tags to include the components that are about to render in this particular route.
– (line 104) is going to pre-load all the components before continue so we won’t see just the “loading” component.

One very important step that could be easily forgotten is to add react-loadable/babel plug-in into .babelrc otherwise we are going to wonder why the assets list is never created.

./.babelrc

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import",
    "react-loadable/babel"
  ]  
}

Also let’s add PROD_SERVER_PORT to our .env file

./env

APP_NAME=Webpack React Tutorial
GRAPHQL_URL=http://localhost:4001/graphql
PROD_SERVER_PORT=3006

and make it available on the front end so Express could pick it up.

./getEnvironmentConstants.js

const fs = require('fs');
// Load environment variables from these files
const dotenvFiles = [
  '.env'
];
// expose environment variables to the frontend
const frontendConstants = [
  'APP_NAME',
  'GRAPHQL_URL',
  'PROD_SERVER_PORT'
];
function getEnvironmentConstants() {
  
  dotenvFiles.forEach(dotenvFile => {
    if (fs.existsSync(dotenvFile)) {
      require('dotenv-expand')(
        require('dotenv').config({
          path: dotenvFile,
        })
      );
    }
  });
  
  const arrayToObject = (array) =>
  array.reduce((obj, item, key) => {
    obj[item] = JSON.stringify(process.env[item]);
    return obj
  }, {})
  return arrayToObject(frontendConstants);      
}
module.exports = getEnvironmentConstants;

 

Adding ./components/App/ssr-index.js

Now if we look again at ./ssr-server.js (line 3) we will see that we are not pointing the App module to the index.js but to ssr-index.js instead, and the reason for this is that on the server things will be slightly different.
First we can’t use BrowswerRouter because clearly there is no browser in a node environment. We have to use StaticRouter instead.
Second, we don’t need to instantiate a new ApolloClient since we already did this in ./ssr-server.js file above. We are just going to pass it as a client param.

With that being said, let’s go ahead and create:

./components/App/ssr-index.js

import React from 'react';
import PageLayout from '../../containers/PageLayout';
import { StaticRouter,  Route, Switch } from 'react-router-dom';
import { ApolloProvider } from 'react-apollo';
import { Provider } from 'react-redux';
import { createStore} from 'redux';
import reducers from '../../reducers';
import fetch from 'isomorphic-fetch';

import styles from './styles.scss';

const store = createStore(reducers, {});

export default ( {req, client} ) => {

  const context = {};
  return (
    <div className={styles.appWrapper}>
      <Provider store={store}>   
        <ApolloProvider client={client}>            
          <StaticRouter location={ req.url } context={context}>
            <Switch>
              <Route exact path="*" component={PageLayout} />  
            </Switch>            
          </StaticRouter>
        </ApolloProvider>
      </Provider>
    </div>
  );
}

DOM Hydration

We did almost all necessary steps for SSR but if we run the app we will see that we are not taking the advantage of the server side rendering and the app will reload on the client side.

We still need to do two important things: DOM hydration and Store rehydration.

DOM hydration is going to attach the events to the existing HTML layout returned from the SSR. Adding it is pretty straight forward: we have to replace ReactDOM.render with ReactDOM.hydrate.

./src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
ReactDOM.hydrate(<App/>, document.getElementById('root'));
if (module.hot) {
  module.hot.accept();
}

Apollo store rehydration

This is also pretty straight forward. If we go back in this tutorial we could haver recall that when we create ./ssr-server.js we fetched the data for all queries, and attached it to the window object (line 90)
Now, let’s use this:
./src/components/App/index.js

import React from 'react';
import PageLayout from '../../containers/PageLayout';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore} from 'redux';
import reducers from '../../reducers';

const styles = require('./styles.scss');

const store = createStore(reducers, {});

export default ( {req} ) => {
  const GRAPHQL_URL = process.env.GRAPHQL_URL;
  const client = new ApolloClient({
    link: new HttpLink({ uri:  GRAPHQL_URL }),
    cache: new InMemoryCache().restore(window.__APOLLO_STATE__),
  }); 
  
  return (
    <div className={styles.appWrapper}>
      <Provider store={store}>
        <ApolloProvider client={client}>
          <Router>
            <Switch>
            <Route exact path="*" component={PageLayout} />  
            </Switch>
          </Router>
        </ApolloProvider>
      </Provider>
    </div>        
  );
}

Ready for a test flight

Finally we are ready to test flight this beast. yarn start and navigate the browser there localhost:3006/home

The response time should be mind blowing with all prod settings and SSR in place.
Open the source code and you should see something like this:

<!doctype html>
      <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Server Side Rendering and Bundle Splitting</title>
        <link
        href="/dist/main.css"
        rel="stylesheet"
        as="style"
        media="screen, projection"
        type="text/css"
        charSet="UTF-8"
      />
        <!-- Page specific CSS bundle chunks -->      
        
            <link
              href="/dist/2.css"
              rel="stylesheet"
              as="style"
              media="screen, projection"
              type="text/css"
              charSet="UTF-8"
            />

            <link
              href="/dist/3.css"
              rel="stylesheet"
              as="style"
              media="screen, projection"
              type="text/css"
              charSet="UTF-8"
            />
        <!-- Page specific JS bundle chunks -->
        <script src="/dist/2-bundle.js"></script>
<script src="/dist/3-bundle.js"></script>
        <!-- =========================== -->
      </head>
      <body cz-shortcut-listen="true">
        <div id="root"/>
          <div class="App-appWrapper" data-reactroot=""><div><div><div class="Header-wrapper"><h2> <!-- -->Webpack React Tutorial<!-- --> </h2><ul><li><a href="/home">HOME</a></li><li><a href="/greetings">GREETINGS</a></li><li><a href="/dogs-catalog">DOGS CATALOG</a></li><li><a href="/about">ABOUT</a></li></ul></div></div><div><div class="Home-wrapper">This is my home section!</div></div></div></div>
        </div>
        <script>
        window.__APOLLO_STATE__={"Page:home":{"id":"home","url":"/home","layout":[{"type":"id","generated":true,"id":"Page:home.layout.0","typename":"PageLayout"},{"type":"id","generated":true,"id":"Page:home.layout.1","typename":"PageLayout"}],"__typename":"Page"},"Page:home.layout.0":{"span":"12","components":[{"type":"id","generated":true,"id":"Page:home.layout.0.components.0","typename":"PageComponents"}],"__typename":"PageLayout"},"Page:home.layout.0.components.0":{"name":"Header","__typename":"PageComponents"},"Page:home.layout.1":{"span":"12","components":[{"type":"id","generated":true,"id":"Page:home.layout.1.components.0","typename":"PageComponents"}],"__typename":"PageLayout"},"Page:home.layout.1.components.0":{"name":"Home","__typename":"PageComponents"},"ROOT_QUERY":{"getPageByUrl({\"url\":\"/home\"})":{"type":"id","generated":false,"id":"Page:home","typename":"Page"}}};
        </script>
      
        <script src="/dist/main-bundle.js"></script>
      </body>
    </html>

As you might notice, (lines 15-37) that only the bundles for the components that we need there are loaded.

Also you will see the Apollo client (The GraphQL queries) serialized and attached to the window object (line 44) which we are using to re-hydrate the client and avoid another GraphQL call.

Well, this could have been as far as a production ready stack, but two important things are missing: tests and caching. But this is good enough as an end of this chapter.

 

branch-name:  
Click To Copy