Advanced React + Webpack 4 + Babel 7 Application Setup
Tags: react, webpack, babel, beginners
Published: 2020-04-13 19:53:29

The world of building user interfaces can be a complex landscape to navigate. The sheer number of tools that are at the disposal of a developer is overwhelming. In my last  [tutorial](https://nasidulislam.hashnode.dev/beginners-guide-to-minimal-react-webpack-4-babel-7-project-setup-ck7m7erad00ec8ss1xzmfntqm) , we discussed a few of those tools (React, Webpack and Babel) and went over the basics of what they are and how they work. More over, we also learnt how we can stitch them together to build an application code base from scratch that is suitable for development.  

The application that was pieced together has minimal features. It does not allow us to test the code we're writing, among other things, and it's certainly not suitable for deploying to production.  **In this guide**, we will build on top of the setup we have and take it further

- Learn Dev + Production environment configs
- Add test frameworks
- Sass
- ESLint
- Static assets (images, SVG icons, font icons, font families)

*The introduction segments can be skipped. Click  [here](#step-1)  to jump straight to the step by step guide .*

## Environment configuration
An application consists of features and every feature has a life cycle --- from it being `developed`, then going through `testing` and finally being deployed to `production`, it lives on different environments (*envs*). The environments serve different purposes and therefore, their needs vary accordingly.

For instance, we don't care about performance or optimization in *dev* env, neither do we care about minifying the code. Often, we enable tools in dev env that helps us write code and debug it, like source maps, linters, etc. On the other hand, on *prod* env, we absolutely care about stuff like application performance and security, caching, etc. The tools we are going to use while walking through this guide is not going to play with all the items we discussed here, however, we will go through basics (and some more) of how environment configuration works and why it is useful.

&nbsp;

## Test Frameworks
A test framework provides us with a platform and a set of rules that allows us to test the code we're writing. Any application that is intended to be deployed for users must be tested. Here is why:
- **It helps reduce the number of bugs** --- and if we write new tests for the ones that *do* come up, we greatly minimize the chance of that particular bug re-appearing.
- **It gives us confidence when attempting to refactor code**. A failing test would mean the refactored code did not satisfy that particular scenario.
- **Improves code quality**, because developers are bound to write code that is *testable*, although writing good tests is an entirely different (and *extremely* valuable) skill of its own
- All the reasons above **reduce overall cost of development** in the long run (fewer bugs, better code quality, etc.)
- Well written tests becomes a form of documentation in itself of the code for which the test is being written.

The frameworks come in various different flavors --- and they all have their pros and cons. For our purposes, we will use two of the more popular frameworks, [Jest](https://jestjs.io/) to test functional JS and [Enzyme](https://enzymejs.github.io/enzyme/) to test our **React** components.

&nbsp;

## Sass
As the application grows in size, it starts to present maintainability and scalability concerns for developers. CSS is one such area where the code can get real messy real fast.  [Sass](https://sass-lang.com/)  is a tool that helps us in this regard:
- **Compiles to CSS**, so the end result is familiar code.
- **It allows nesting selectors**. This enables developers to write cleaner and fewer lines of code *and* opens the door for more maintainable stylesheets.
- **It allows for creating variables, mixins**, further promoting maintainability.
- **Conditional CSS**, exciting stuff !!
- **It is industry approved** --- performant and formidable community support.

No reason to not use a tool that will surely improve our development workflow, right?

&nbsp;

## ESLint
Another point of concern as the code base begins to grow is ensuring high standards of code quality. This is especially more important when there are multiple teams or developers working on the same code base.  [ESLint](https://eslint.org/)  saves the day here --- it enforces common coding standards, or *style guides*, for all devs to follow. There are many industry approved style guides out there, for instance  [Google](https://google.github.io/styleguide/htmlcssguide.html) and  [AirBnB](https://github.com/airbnb/javascript). For our purposes, we will use the AirBnB style guide.

&nbsp;

## Static Assets
This encompasses all the pretty stuff that will be used in the application --- custom fonts, font icons, SVGs and images. They are placed in a `public` folder, although an argument can be made for a different setup.

&nbsp;

__Please note:__ The rest of the guide builds on top of the  [last piece](https://nasidulislam.hashnode.dev/beginners-guide-to-minimal-react-webpack-4-babel-7-project-setup-ck7m7erad00ec8ss1xzmfntqm)  I wrote. You can either follow that first before proceeding here, *or* do the following:

1. Ensure that that you have node version 10.15.3 or above. Open up your terminal and type in `node -v` to check. If the version does not match the requirements, grab the latest from  [here](https://nodejs.org/en/) .
2. Once you're good with the above, grab the  [repo](https://github.com/all-things-javascript/minimal-react-webpack-babel) and follow the installation instructions in the `README`.
3. After installing the dependencies using `npm install`, run `npm start` to compile the code and spin up the dev server. At this point, you should see a new browser tab open, rendering a `hello world` component. Make sure you're inside the repository directory that you just "git cloned" before trying out the command.

&nbsp;

*After having gone through the basics of the tools we're about to use and setting up our base repo, we can finally move forward to the guide.*

&nbsp;

## Step 1
Assuming  [repo](https://github.com/all-things-javascript/minimal-react-webpack-babel) has been successfully downloaded, open it up in a text-editor of your choice. You should see a file called `webpack.config.js`. This is where webpack configs currently live in its entirety.  

In order to separate *production* and *development* builds, we will create separate files to host their configs, and another file will contain settings that are common between them, in the interest of keeping our code DRY.

Since there will be at least 3 config files involved, they will need to `merge` with each other at compile time to render the application. To do this, we need to install a utility package called `webpack-merge` to our dev dependencies.

```
npm install webpack-merge --save-dev
```  

Then rename `webpack.config.js` to `webpack.common.js`. As the name implies, this will contain the common configs. We will create **two** more files
- `webpack.production.js` --- to contain production env settings
- `webpack.development.js` --- to contain development env settings

While we're on the subject of configuring webpack builds, we will take the opportunity to install a couple of npm packages that will help with our tooling and optimize our builds.

First, we will install a package called  [CleanWebpackPlugin](https://github.com/johnagan/clean-webpack-plugin) .

```
npm install clean-webpack-plugin --save-dev
```  

Webpack puts the output bundles and files in the `/dist` folder, because that is what we've configured it to do. Over time, this folder tends to become cluttered as we do a build every time (through hot reloading) we make a code change and save. Webpack struggles to keep track of all those files, so It is good practice to clean up the `/dist` folder *before* each build in order to ensure the proper output files are being used. `CleanWebpackPlugin` takes care of that.

We will install another package called  [path](https://www.npmjs.com/package/path). It will allow us to programmatically set entry and output paths inside webpack.

```
npm install path --save
```  

&nbsp;

Now that we have the necessary packages in place to configure a clean, optimized webpack build, lets change `webpack.common.js` to contain the following code,

```
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            },
            {
                test: /\.html$/,
                use: [
                    {
                        loader: "html-loader"
                    }
                ]
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebPackPlugin({
            template: "./src/index.html",
            filename: "./index.html",
        })
    ]
};

``` 

Add the following lines to `webpack.development.js`

```
const merge = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {
    mode: 'development',
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist',
        hot: true
    }
});
```

... and these lines to `webpack.production.js`

```
const merge = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {
    mode: 'production'
});
```



There are a few changes here from its previous iteration that requires explanation:
* `webpack.common.js` 
  * Note that we've added an `output` property. It renames the bundle file and defines the path to where it can be found.
  * We no longer have the dev server definition in here.
  * We are making use of `CleanWebpackPlugin` to clean up *dist* folder
* `webpack.development.js`
  * The dev server definition has been moved to this file, naturally
  * We have enabled `source maps`
* `webpack.production.js`
  * It only contains *mode* definition at the moment, but opens up the door to add additional tinkering later on.

That was a lot of information! We have accomplished a significant step towards setting up the project. Although I have tried my best to explain the concepts and code changes, I would advise additional reading into each of these topics to get a complete grasp. Webpack is a beast --- it might be a stretch even for the smartest developer to completely understand everything in the first read through.

Let's move on to the next step.

 &nbsp;

## Step 2
We will add test frameworks to our code base in this step! There are two frameworks we need to add, one to test functional JS and the other to test React components. They are called Jest and Enzyme, respectively. Once we configure that, we will write a small, uncomplicated JS module and React component to try them out.

We will set them up and work with them in separate steps. Let's get started!

We will install `Jest` first as a dev dependency, since it is a test framework and it has no use in the production bundle. To install,

```
npm install jest --save-dev
```

Next, we will add a file called `jest.config.js` to the root directory of our codebase that will dictate how we want to configure our tests. This is the  [official documentation](https://jestjs.io/docs/en/23.x/configuration)  page for Jest that contains details of every piece of configuration --- it is worth giving a read.

We will not need all the pieces, thus I have condensed the necessary pieces to write our own custom config file. It contains detailed comments on what each piece is doing. This is what  `jest.config.js` file will look like for the project we're configuring

```
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
	// All imported modules in your tests should be mocked automatically
	// automock: false,

	// Stop running tests after the first failure
	// bail: false,

	// Respect "browser" field in package.json when resolving modules
	// browser: false,

	// The directory where Jest should store its cached dependency information
	// cacheDirectory: "C:\\Users\\VenD\\AppData\\Local\\Temp\\jest",

	// Automatically clear mock calls and instances between every test
	clearMocks: true,

	// Indicates whether the coverage information should be collected while executing the test
	// collectCoverage: false,

	// An array of glob patterns indicating a set of files for which coverage information should be collected
	collectCoverageFrom: ['src/tests/*.test.js'],

	// The directory where Jest should output its coverage files
	coverageDirectory: 'src/tests/coverage',

	// An array of regexp pattern strings used to skip coverage collection
	coveragePathIgnorePatterns: [
	  "\\\\node_modules\\\\"
	],

	// A list of reporter names that Jest uses when writing coverage reports
	coverageReporters: [
	  "json",
	  "text",
	  "lcov",
	  "clover"
	],

	// An object that configures minimum threshold enforcement for coverage results
	coverageThreshold: {
		"global": {
			"branches": 80,
			"functions": 80,
			"lines": 80
		}
	},

	// Make calling deprecated APIs throw helpful error messages
	errorOnDeprecated: false,

	// Force coverage collection from ignored files using an array of glob patterns
	// forceCoverageMatch: [],

	// A path to a module which exports an async function that is triggered once before all test suites
	// globalSetup: null,

	// A path to a module which exports an async function that is triggered once after all test suites
	// globalTeardown: null,

	// A set of global variables that need to be available in all test environments
	// globals: {},

	// An array of directory names to be searched recursively up from the requiring module's location
	// moduleDirectories: [
	//   "node_modules"
	// ],

	// An array of file extensions your modules use
	moduleFileExtensions: ['js', 'json', 'jsx'],

	// A map from regular expressions to module names that allow to stub out resources with a single module
	// moduleNameMapper: {},

	// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
	// modulePathIgnorePatterns: [],

	// Activates notifications for test results
	// notify: false,

	// An enum that specifies notification mode. Requires { notify: true }
	// notifyMode: "always",

	// A preset that is used as a base for Jest's configuration
	// preset: null,

	// Run tests from one or more projects
	// projects: null,

	// Use this configuration option to add custom reporters to Jest
	// reporters: undefined,

	// Automatically reset mock state between every test
	resetMocks: false,

	// Reset the module registry before running each individual test
	// resetModules: false,

	// A path to a custom resolver
	// resolver: null,

	// Automatically restore mock state between every test
	restoreMocks: true,

	// The root directory that Jest should scan for tests and modules within
	// rootDir: null,

	// A list of paths to directories that Jest should use to search for files in
	// roots: [
	//   "<rootDir>"
	// ],

	// Allows you to use a custom runner instead of Jest's default test runner
	// runner: "jest-runner",

	// The paths to modules that run some code to configure or set up the testing environment before each test
	// setupFiles: ['<rootDir>/enzyme.config.js'],

	// The path to a module that runs some code to configure or set up the testing framework before each test
	// setupTestFrameworkScriptFile: '',

	// A list of paths to snapshot serializer modules Jest should use for snapshot testing
	// snapshotSerializers: [],

	// The test environment that will be used for testing
	testEnvironment: 'jsdom',

	// Options that will be passed to the testEnvironment
	// testEnvironmentOptions: {},

	// Adds a location field to test results
	// testLocationInResults: false,

	// The glob patterns Jest uses to detect test files
	testMatch: ['**/__tests__/**/*.js?(x)', '**/?(*.)+(spec|test).js?(x)'],

	// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
	testPathIgnorePatterns: ['\\\\node_modules\\\\'],

	// The regexp pattern Jest uses to detect test files
	// testRegex: "",

	// This option allows the use of a custom results processor
	// testResultsProcessor: null,

	// This option allows use of a custom test runner
	// testRunner: "jasmine2",

	// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
	testURL: 'http://localhost:3030',

	// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
	// timers: "real",

	// A map from regular expressions to paths to transformers
	// transform: {},

	// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
	transformIgnorePatterns: ['<rootDir>/node_modules/'],

	// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
	// unmockedModulePathPatterns: undefined,

	// Indicates whether each individual test should be reported during the run
	verbose: false,

	// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
	// watchPathIgnorePatterns: [],

	// Whether to use watchman for file crawling
	watchman: true,
};
```

According to our configuration, our tests should live inside a directory called `tests` inside `/src`. Let's go ahead and create that --- and while we're on the subject of creating directories, lets create *three* in total that will allow us to set ourselves up for future steps of the guide

- `tests` - directory that will contain our tests
- `core/js` - we will place our functional JS files here, the likes of helper, utils, services, etc.
- `core/scss` - this will contain browser resets, global variable declarations. We will add these in a future piece.

Alright, we are making progress !! Now that we have a sweet test setup, let's create a simple JS module called `multiply.js` inside `core/js`

```
const multiply = (a, b) => {
    return a* b;
};

export default multiply;
```

... and write tests for it, by creating a file called `multiply.spec.js` inside `tests` directory.

```
import multiply from '../core/js/multiply';

describe('The Multiply module test suite', () => {
    it('is a public function', () => {
        expect(multiply).toBeDefined();
    });

    it('should correctly multiply two numbers', () => {
        const expected = 6;
        const actual1 = multiply(2, 3);
        const actual2 = multiply(1, 6);

        expect(actual1).toEqual(expected);
        expect(actual2).toEqual(expected);
    });

    it('should not multiply incorrectly', () => {
        const notExpected = 10;
        const actual = multiply(3, 5);

        expect(notExpected).not.toEqual(actual);
    });
});
```

The final piece of configuration is to add a script in our `package.json` that will run all our tests. It will live inside the `scripts` property

```
"scripts": {
    "test": "jest",
    "build": "webpack --config webpack.production.js",
    "start": "webpack-dev-server --open --config webpack.development.js"
  },
```

Now, if we run `npm run test` in our terminal (inside the root directory of the project), it will run all our tests and produce and output like this.

![Screen Shot 2020-04-08 at 3.15.12 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1586373323504/hHuACv12J.png)

You can keep adding more modules and test suites in similar manner.

Let's move on to the next step !

 &nbsp;

## Step 3
It's time to install Enzyme and test our React components! We need to install a version of Enzyme that corresponds to the version of React we're using, which is **16**. In order to do that, we need to do the following, keeping in mind that this tool will also be installed as a dev dependency because like Jest, the test framework does not need to be compiled to production bundle

```
npm install enzyme enzyme-adapter-react-16 --save dev
```

Next, we will create `enzyme.config.js` at the root directory of the project, similar to what we did for Jest. This is what that file should look like

```
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });
```

Now, if you go take a look at line 119 in `jest.config.js`, you will see that we have done ourselves a favor by preparing for this moment where we setup Enzyme to work with Jest. All that needs to be done is uncomment line 119 and our setup will be complete!

Let's write a test for the `<App />` component to see if what we've set up is working. Create a directory called `components` inside `tests` --- this will hold all the tests for the components you will write in the future. The separate directory is created to keep functional and component tests separate. This segregation can be done in any way, as long as all the tests live inside the `src/tests` directory. It will help in the future when the app starts to grow.

Inside `src/tests/components` directory, create a file called `App.spec.js` and add the following lines

```
import React from 'react';
import { shallow} from 'enzyme';

import App from '../../components/App';

describe('The App component test suite', () => {
    it('should render component', () => {
        expect(shallow(<App />).contains(<div>Hello World</div>)).toBe(true);
    });
});
```

Now if we run our test script in the terminal, you will see this test is running and passing !


![Screen Shot 2020-04-09 at 3.13.21 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1586459620589/dHmcc2BOz.png)

__Please note:__ *In step 2 and 3, we have simply set up Jest and Enzyme to work together in our code base. To demonstrate that the setup is working, we have written two overly simple tests. The art of writing good tests is an entirely different ball game and these tests should not be taken as any form of guide/direction.*



 &nbsp;

## Step 4
In this part of the guide, we will configure our code base to lend `.scss` support. However, before we can learn to run, we need to learn to walk --- that means we will have to get css to load first.

Let's go grab the necessary npm packages

```
npm install css-loader style-loader --save-dev
```

```
npm install node-sass sass-loader --save
```

*In the explanation block below, you can click the names of the tools that appear like `this` to visit their official documentation.*

-  [`css-loader`](https://webpack.js.org/loaders/css-loader/) is a webpack plugin that interprets and resolves syntax like `@import` or `url()` that are used to include `.scss` files in components.

-  [`style-loader`](https://webpack.js.org/loaders/style-loader/) is a webpack plugin that injects the compiled css file in the DOM.

-  [`node-sass`](https://github.com/sass/node-sass) is a Node.js library that binds to a popular stylesheet pre-processor called  [`LibSass`](https://github.com/sass/libsass) . It lets us natively compile `.scss` files to css in a node environment.

-  [`sass-loader`](https://webpack.js.org/loaders/sass-loader/) is a webpack plugin that will allow us to use Sass in our project.

Now that we have installed the necessary npm packages, we need to tell webpack to make use of them. Inside `webpack.common.js`, add the following lines in the `rules` array just below where we're using `babel-loader` and `html-loader`

```
{
    test: /\.s[ac]ss$/i,
    use: [
        // Creates `style` nodes from JS strings
        'style-loader',
        // Translates CSS into CommonJS
        'css-loader',
        // Compiles Sass to CSS
        'sass-loader',
    ]
}
```

The setup is complete ! Let's write some sass !!

In `src/components` directory, create a file called `App.scss` and add the following lines

```
#app-container {
    letter-spacing: 1px;
    padding-top: 40px;

    & > div {
        display: flex;
        font-size: 25px;
        font-weight: bold;
        justify-content: center;
        margin: 0 auto;
    }
}
```

*The explanation of sass syntax is beyond the scope of this article. This is an excellent  [resource](https://blog.teamtreehouse.com/the-absolute-beginners-guide-to-sass)  for beginners to learn more in depth.*

Now, save the file and boot up the project by running  `npm run start`. The application should load with the style rules we just wrote.

 &nbsp;

## Step 5
It's time to install ESLint. Similar to what we've been doing so far, we need to install a few npm packages and then add a config file to our code base. This is a tool that is needed purely for development purpose, so we will install it as a dev dependency.

Let's get started !

```
npm install eslint eslint-config-airbnb-base eslint-plugin-jest --save-dev
```

- `eslint-config-airbnb-base` is the airbnb style guide we're asking `eslint` to apply on our project.
- `eslint-plugin-jest` is the eslint plugin for `jest` test framework.

The airbnb style guide has peer dependencies that needs to be installed as well. You can input
```
npm info "eslint-config-airbnb@latest" peerDependencies
``` 

in your terminal and list them, however, to install, do the following

```
npx install-peerdeps --dev eslint-config-airbnb
```

Next, we need to create a file called `.eslintrc.json` (note the `.` at the beginning, indicating it's a hidden file)at the root directory of the project, similar to how the other config files (webpack, jest, enzyme, babel) have been added,

... and add these lines

```
{
    "extends": "airbnb",
    "plugins": ["jest"],
    "env": {
      "browser": true,
      "jest": true
    },
    "rules": {
      "arrow-body-style": [2, "always"],
      "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
      "no-unused-expressions": "off",
      "max-len": "off",
      "import/no-extraneous-dependencies": "off",
      "react/destructuring-assignment": "off",
      "react/prop-types": "off"
    }
}
```

The  [official documentation](https://eslint.org/docs/user-guide/configuring#top) is a good read if you're looking to understand in details how configuring ESLint works. The most pertinent lines of code in that file is the `rules` object --- here we're basically overriding *some* of the rules from the style guide to suit the specific needs of our project. These are not set in stone, so please feel free to play with them to best suit *your* needs, but it's probably not a good idea to override *too many* of the rules --- that defeats the purpose of using a style guide in the first place.

Let's add a script to `package.json` that will apply the airbnb style guide to our code base. We need to tell Eslint what files and/or directories we would like it to scan --- so we will tell it to scan all JS files

```
"lint": "eslint '**/*.js' --ignore-pattern node_modules"
```

Now, if you run `npm run lint` in your terminal, eslint will scan the file types and patterns specified in the script and display a list of issues. Fair warning, the project will have *quite a few* errors, but if you're using popular code editors like IDEA products, Visual Studio Code, Sublime, etc, they provide out of the box support to fix *most* of these issues in one quick stroke (format document).

*If the large number of errors is proving to be a hindrance to your learning, please feel free to uninstall ESLint by running `npm uninstall eslint eslint-config-airbnb-base eslint-plugin-jest --save-dev` *

 &nbsp;

## Step 6
We're almost done with setting up our project --- the finish line is within our sights !! In this last step, we will configure our project to make use of various static assets like images, SVGs, icons and custom typefaces.

### Custom Typefaces
Any respectable front end setup should have varying fonts displaying information on the page. The weight of the font, along with its size, is an indicator of the context of the text being displayed --- for instance, page or section headers tend to be *larger* and *bolder*,  while helper texts are often *smaller*, *lighter* and may even be in *italics*.

There are multiple ways of pulling in custom fonts into an application. Large enterprise code bases usually buy licenses to fonts and have its static assets as part of the the server that hosts the application. The process to do that is slightly complicated --- we need a dedicated piece to walk through that.

The most convenient way of using custom fonts is to use a public domain library that has a large collection and hosted on a CDN (Content Delivery Network), like  [Google Fonts](https://fonts.google.com/). It is convenient because all we need to do is, select a couple of fonts we like and then simply embed their `url` in our static markup `index.html`

...and we're good to go !! So let's get started. For our purposes, we shall use `Roboto Mono` font family.

Open up `index.html` and paste the following stylesheet `link` in the `head`

```
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono">
```

We're done. Now we can use `font-family: 'Roboto Mono' ` in any of our `.scss` files. We can use any number of fonts in this way.

### Images
Images, like fonts, are an essential part of a front end setup. In order to enable our project to utilize images in the application, we need to install a loader for webpack. This step is identical to what we've done multiple times in this guide --- install the loader and add a few lines to webpack config to make use of it

```
npm install url-loader --save-dev
```

... then add the following lines to the `rules` array in `webpack.common.js`

```
...
{
  test: /\.(jpg|png)$/,
  use: {
    loader: 'url-loader',
  },
},
...
```

The project is now ready to use images of type `.jpg` and `.png` . To demonstrate, create a `public/images` folder at the root directory of the project. Then add *any* image to the subdirectory `images`. For our purposes, I downloaded a free image from Unsplash and named it `coffee.png`

Next, we will create a directory inside `src/components` called Image --- then create the `Image` component.

`Image.js`

```
import React from 'react';

const Image = (props) => {
  return (
    <img
      src={props.src}
      alt={props.alt}
      height={props.height}
      wdth={props.wdth}
    />
  );
};

export default Image;

```

Then, import both the `Image` component and the actual image `coffee.png` in `App.js`. At this point, we will have to make minor edits to the `App.js` to use the image
```
import React from 'react';
import './App.scss';

// component imports
import Image from './Image/Image';

// other imports
import coffee from '../../public/images/coffee.png';

const App = () => {
  return (
    <div>
      <span>Hello World</span>
      <Image
        src={coffee}
        alt="hero"
        height="400"
        width="400"
      />
    </div>
  );
};

export default App;

```

Now, if you start the application, you will see the image is being loaded on the page.


## Conclusion
That concludes our step by step guide to setting up a modern React project from scratch. There was a lot of information to digest here, but to think of it, we have also come a long way from the minimal setup we did earlier. I hope the guide has been helpful in learning some key concepts in the area of modern front end setup tooling.

The future pieces I have planned for this series are
- Learn the basics of containerization and how to deploy this project in a container.
- Add bonus features to our project, like JS docs, comprehensive test runner outputs (with colors and coverage percentages !), more `package.json` scripts and global scss stylesheets like resets and variables.

Please feel free to leave a comment and share among your friends. I will see you in the next piece !

*The repo for the advanced setup can be found  [here](https://github.com/all-things-javascript/advanced-react-webpack-babel) .*

&nbsp;

#### References
1.  [Webpack Environment Variables and Configuration](https://webpack.js.org/guides/production/) 
2.  [Webpack Output Management](https://webpack.js.org/guides/output-management/)
3.  [Sass-loader](https://webpack.js.org/loaders/sass-loader/) 
4.  [The Absolute Beginners Guide to Sass](https://blog.teamtreehouse.com/the-absolute-beginners-guide-to-sass) 
5.  [ESLint configuration](https://eslint.org/docs/user-guide/configuring#top) 
6.  [Google Web Fonts - Get Started](https://developers.google.com/fonts/docs/getting_started)