Importing images in React
Published: 2017-10-10 20:49:11

---
title: Importing images in React
published: true
description: 
tags: images, react, workflows
---

![Importing images in React](https://thepracticaldev.s3.amazonaws.com/i/3kxgqotmyxpg61t1wep9.jpg)

As some of you who are following my posts may already know, I have been working on a `React` version of my **Front End Developer Portfolio**. As much as I love my `Jekyll` version, I wanted to try new things. I also wanted to get going on my own projects using `React` while continuing my deep dive into various **React workflows**.

I'll be getting into the various changes I made to my developer toolkit related to the app's worklow in other articles. Here I just want to talk about what I had to do to make images I used work properly in my app both `locally` AND `remotely`.

# webpack

First I want to talk about what `webpack` tools you need in order to be able to add images to your **React** application. It's not just about what you need to do with `React`. If your workflow emanates from `webpack`, you have to take care of the `webpack` requirements first.

There are two native webpack loaders that load images: the `url-loader` and the `file-loader`. The `url-loader` is good for development. It works like the `file-loader`, but it returns a `DataURL` if the file is < 10000 bytes.

My `url-loader` configuration in `webpack-dev.config.js`:

```
{
    test: /\.(pdf|jpg|png|gif|svg|ico)$/,
    use: [
        {
            loader: 'url-loader'
        },
    ]
},

```
For example, when I inspect my `footerTwitter.png` file in **Chrome DevTools**, it shows up in the following way:

```
<li>
    <a href="https://twitter.com/letsbsocial1">
        <img class="footerTwiiter" src="data:image/png:base64, iVBOR....AZaPAJx1SWgAAAAASUVORK5CYII=" width="40" alt="twitter">
    </a>
</li>

```
That's because `footerTwitter.png` < 10,000 bytes. However, my `profileSmall.png` is > 10,000 bytes, and it shows up in Devtools like so:

```
<div class="Home-content">
    <div class="Home-profile">
        <img src="0688089....png" class="Profile-image" alt="Profile image">
    </div>
</div>

```
I don't mind if my image shows up as an ugly, indeterminate file, but I don't like having it that way in production. I want to add a `[hash]` to the name, but I also want to keep the original name of the file so I can recognize it. That's where the `file-loader` comes in.

The `file-loader` is good for production. This is what my `file-loader` configuration looks like in my `webpack-prod.config.js`:

```
{
    test: /\.(jpg|png|gif|svg|pdf|ico)$/,
    use: [
        {
            loader: 'file-loader',
            options: {
                name: '[path][name]-[hash:8].[ext]'
            },
        },
    ]
},

```
If I didn't add an `options` object, the names of my files would be those long ugly hashes followed by their native extension by default. But by adding the `name` property along with customizations, I am able to change the `behavior` of the `file-loader` and emit my own `custom filename`.

`[path]` refers to the path of the file relative to entry.  The value of the entry property in my `webpack-prod.config.js` file is:

```
entry: {
    bundle: './src/index.js',
},

```
Since everything needed for the application is included in `index.js`, and `index.js` is in the `src` directory, `[path]` refers to the path to a file relative to `src`. And since I am also using `[name]`, which refers to the name of ANY given file, and therefore includes ANY GIVEN FILE in `src`, all files in `src` are copied into the `dist` folder relative to `src`. Since the `images` directory is outside of `src`, it gets copied into `dist` as its original `images` directory including any sub-directories, in `dist`. No `src` directory is added before it. But there is a little glitch to this setup. There is a little file called `favicon.ico` which resides at the top of `src`. I need to add `|ico` to my `file-loader` `test` property so that webpack knows to load it into the application. I am also using `[path][name]` which ends up copying all files within `src` into `dist`. When I run a `production` build, webpack creates a `src` directory in `dist` that contains  `favicon-[hash].ico`. I haven't found a way to prevent `src` from being created in `dist` yet, and I don't know that there is any. Others have encountered similar issues, and to my knowledge, a solution has not yet been found. Perhaps it's time for a `feature request`?

`[hash:8]` refers to the hash that is added after the filename, and the number 8 refers to the length of the hash. the default length is just way too long! As for choosing a separator, the best practice seems to be either a `.` or a `-`. I personally like to clearly see my separator, so I went with `-`.

`.[ext]` refers to the file extension. By using `[ext]` instead of just one extension means that any file extension that has been defined in the `file-loader` `test` property will be included.

# React

STRUCTURE is so important. Anyone who has created `Gulp` workflows for their `HTML5`, `JS`, and `CSS3` apps knows what I am talking about. Paths to images, which are related to the structure, are so important as well. Proper structure in both your `React App` and in your `webpack.config.js` also ensures that Webpack will correctly move your images into your dist folder, and provide the correct PATHS.

In order to be able to import images into `React components`, you have to make sure that locally the images reside within the same parent directory as the components OR that the images are exported from the directory they reside in so they can be imported into any of your components. In my `Portfolio React` application, my components folder looks like this:

```
components/
    About.js
    Calendar.js
    Contact.js
    Footer.js
    Header.js
    Home.js
    Skills.js

```
It resides in `src`:

```
src/
    -components/
        About.js
        Calendar.js
        Contact.js
        Footer.js
        Header.js
        Home.js
        Skills.js
        Work.js

```
And this is what my `images` folder looks like:

```
images/
    -icons/
        footerGithub.png
        footerGoogle.png
        footerLinkedin.png
        footerTwitter.png
        github.svg
        googleplus.svg
        linkedin.svg
        twitter.svg
    -resume/
        mdcResume8217.pdf
    index.js
    profileSmall.png

```
However, my `images` directory does not reside in the same directory as my components, the `components` directory. It resides in the `root` direcory.

Why? Because this was the only way in which `webpack` would exactly replicate my `image` directory structure. This is what I have in my `webpack-prod.config.js`:

```
module: {
    rules: [
        {
            test: /\.(jpg|png|gif|svg|pdf|ico)$/,
            use: [
                {
                    loader: 'file-loader',
                    options: {
                        name: '[path][name]-[hash:8].[ext]'
                    },
                },
            ]
        },
    ],
},

```
The `name` property refers to the `name` of an `image` file. `[path]` refers to the `path` to that image file STARTING with its `root` directory. I use this term loosely, as technically the `root` directory of an application is its topmost directory. In my example here, it would be `portfolio-react`. However, the `src` directory, where `webpack` extracts the data it needs to bundle the files our applications depend on to run, and then the rest of the path to a file is what is replicated in our `destination` folder in `production`, i.e. `dist`. So if the path to an image in development was `src/images/img.jpg`, it would replicate to the `dist` directory in the same way but with `dist` as the topmost directory: `dist/src/images/img.jpg`. That just would be too weird and would not work!

By placing the `images` directory outside of `src` in `root`, the images directory was replicated in the following way in `dist`:

```
dist/
        -images/
            profileSmall-0688089a.png
            -icons/
                footerGithub-8d086876.png
                footerGoogle-c7c39c36.png
                footerLinkedin-9a80860c.png
                footerTwitter-cf5ffa5b.png
                github-ff66eb8e.svg
                googleplus-603de14e.svg
                linkedin-bc8e55bb.svg
                twitter-93a9fd6a.svg
            -resume/
                mdcResume8217-17c81764.pdf
        -src/
            favicon-08080867.ico

```
I created a little `script` in my `package.json` to get rid of the source folder after running a new build:

```
"cleanSrc": "rimraf dist/src",

```
I already had the `rimraf` npm package installed and use it for my `"clean": "rimraf dist"` `script`, so it was easy to create another one.

There is a last and crucial step that was needed in order for the loading of my images to work properly in my `Portfolio React` app, since the components and the images directory did not reside in the same directory. I created an `index.js` file within the images directory. It consisted of exporting all files within the `images` directory and any of its `sub-directories`:

```
export profileSmall from './profileSmall.png';

export mdcResume8217 from './resume/mdcResume8217.pdf';

export linkedin from './icons/linkedin.svg';
export googleplus from './icons/googleplus.svg';
export github from './icons/github.svg';
export twitter from './icons/twitter.svg';

export footerTwitter from './icons/footerTwitter.png';
export footerGithub from './icons/footerGithub.png';
export footerGoogle from './icons/footerGoogle.png';
export footerLinkedin from './icons/footerLinkedin.png';

```

If I hadn't done this last step, my images would not have appeared! I also would not have been able to import them into my components in the following (and proper) way:


```
import React from 'react';
import Typist from 'react-typist';

import linkedin from '../../images/icons/linkedin.svg';
import googleplus from '../../images/icons/googleplus.svg';
import github from '../../images/icons/github.svg';
import twitter from '../../images/icons/twitter.svg';

export const Contact = () => (
    <div className="Contact-content">
        <div className="contact-social">
            <h2 className="title-social">Follow me</h2>
            <ul>
                <li>
                    <a href="https://twitter.com/letsbsocial1" target="_blank">
                        <img className="twitter" src={twitter} width="40" alt="twitter"/>
                    </a>
                </li>
                <li>
                    <a href="https://github.com/interglobalmedia" target="_blank">
                        <img className="github" src={github} width="40" alt="github"/>
                    </a>
                </li>
                <li>
                    <a href="https://plus.google.com/u/0/110861192597778984723" target="_blank">
                        <img className="google-plus" src={googleplus} width="40" alt="google plus"/>
                    </a>
                </li>
                <li>
                    <a href="https://www.linkedin.com/in/mariacampbell/" target="_blank">
                        <img className="linkedin" src={linkedin} width="40" alt="linkedin"/>
                    </a>
                </li>
            </ul>
            <div className="follow">
                <li>
                    <a href="https://medium.com/@letsbsocial1" target="_blank">Medium</a>
                </li>
                <br/>
                <li>
                    <a href="http://www.mariadcampbell.com/" target="_blank">Dev. Blog</a>
                </li>
                <li>
                    <a href="http://interglobalmedianetwork.com/" target="_blank">co. blog</a>
                </li>
            </div>
            <div className="email">
                <h2 className="title-social">Email</h2>
                <li>
                    <a href="mailto:interglobalmedia@gmail.com">interglobalmedia@gmail.com</a>
                </li>
            </div>
            <div className="contribute">
                <h2 className="title-social">Contributor to</h2>
                <li>
                    <a href="https://blog.hellojs.org/" trget="_blank">hello.js</a>
                </li>
                <br/>
                <li>
                    <a href="https://dev.to/letsbsocial1" target="_blank">The Practical Dev</a>
                </li>
            </div>
        </div>
    </div>
)

```
And presto! You have structured your `React` application in such a way that `React` correctly interprets your image files. This ensures that you can import them into your components. AND you have successfully configured your `webpack-dev.js` and `webpack-prod.config.js` so that it loads all your images and image `types` correctly into your `React` application's development AND production builds.

**Related resources:**

[Portfolio React App on Github](https://github.com/interglobalmedia/portfolio-react)

[webpack url-loader](https://webpack.js.org/loaders/url-loader/)

[webpack file-loader](https://webpack.js.org/loaders/file-loader/)