13

I have an app scaffolded using create-react-app. I would like to have the folder structure like this:

src/
  components/
    CustomAppBar.js
  images/
    logo.svg
  App.js
  index.tsx
images.d.ts

Currently I would like to use the logo.svg in the images folder in CustomAppBar.js. Currently this file looks like this:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import logo from '*.svg';

const styles = {
  flex: {
    flex: 1,
  },
  menuButton: {
    marginLeft: -12,
    marginRight: 20,
  },
  root: {
    flexGrow: 1,
  },
};

function ButtonAppBar(props) {
  const { classes } = props;
  return (
    <div className={classes.root}>
      <AppBar position="static" title={<img styles={{height: '50px'}} src={logo} />}>
        <Toolbar>
          <IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
            <MenuIcon />
          </IconButton>
          <Typography variant="title" color="inherit" className={classes.flex}>
            Title
          </Typography>
          <Button color="inherit">Login</Button>
        </Toolbar>
      </AppBar>
    </div>
  );
}

ButtonAppBar.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(ButtonAppBar);

As expected, this fails with:

Module not found: Can't resolve '*.svg' in 'some\path\src\components

The content of images.d.ts is stock standard:

declare module '*.svg'
declare module '*.png'
declare module '*.jpg'

I have found a couple of suggestions elsewhere that mention modifying Webpack config. It seems create-react-app has hidden away Webpack config stuff. What's the best practice when it comes to this?

codedog
  • 2,488
  • 9
  • 38
  • 67

2 Answers2

22

What I normally do for assets under /public/assets i import my files then in my react components using src i can access them using process.env.PUBLIC_URL + '/assets/{ENTER REST OF PATH HERE}'

here is a code sample how I implement it.

import React, { Component } from 'react';

const iconPath = process.env.PUBLIC_URL + '/assets/icons/';

export default class TestComponent extends Component {
    constructor(props) {
        super(props);
    }
    render(){
    return (<img
        src={`${iconPath}icon-arrow.svg`}
        alt="more"
    />)
    }
}

Here is the link that got me started implementing it this way. https://github.com/facebook/create-react-app/issues/2854

I also noticed you are importing logo incorrectly and should be import logo from '../images/logo.svg' or if logo.svg does not have an export default you should be using import {logo} from '../images/logo.svg'

Joshua Fermin
  • 647
  • 9
  • 19
  • Thanks, that works for now... but I will wait and see if there are any cleaner solutions. I guess if not I can always wrap something like this in helper functions. – codedog Jun 07 '18 at 01:45
  • made a few updates to my answer hope that's a little cleaner. – Joshua Fermin Jun 07 '18 at 03:05
  • I have tried the `../images/logo.svg` import but that raised an error too. – codedog Jun 07 '18 at 07:24
  • if logo.svg does not have an export default you should be using `import {logo} from '../images/logo.svg'` if I could see the contents of logo.svg it would be very helpful. – Joshua Fermin Jun 07 '18 at 20:43
  • Your last sentence was actually the answer. I have edited it to removed the use of `PUBLIC_URL`. Using the correct import will include the benefits of cache busting. – codedog Jun 07 '18 at 23:31
  • Is there any other way other than using the public url or importing each an every image in the case of an array of images? – Akhila Jan 10 '21 at 14:12
2

You can use ES6 import to locate any file (images, audio, etc) from the root folder and add them to your app.

import React from 'React'
import errorIcon from './assets/images/errorIcon.svg'
import errorSound from './assets/sounds/error.wav'

class TestComponent extends React.Component 
{ 
    render() 
    {
        return (

            <div>
                <img src={ errorIcon }
                     alt="error Icon" />

                <audio src={ errorSound } />
            </div>
        )
    }
}
anonym
  • 4,460
  • 12
  • 45
  • 75
  • 1
    What if I have multiple images and I'm importing an object array which has all the image paths? I can't do import for every other image right? @anonym – Akhila Jan 10 '21 at 14:11