Chris Chris - 2 months ago 30
React JSX Question

Can't load images using webpack dev server middleware

So I've spent the past 24 hours tweaking my code and trying to get this to work and scoured SO and Google, but no luck - maybe someone can help!

My React app is running on Express but using webpack-dev-server middleware. When I load the page, the images are coming up blank, as if they don't exist. I'm not getting any error messages in my console (e.g. no 404 error) but the image element is just showing the

alt
text and not displaying the actual
png
or
svg
that should be there.

Incidentally it's not just the react components that are failing to render images - I tried hardcoding an image file into my index.html file as a test and this yielded the same result.

Here's my code:

server.js (truncated to exclude database setup and additional express routes)

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const path = require('path');
const mongoose = require('mongoose');
const config = require('./webpack.dev.config');

// SERVER SETUP

const app = express();
const router = express.Router();

var publicPath = path.resolve(__dirname, 'public');

compiler=webpack(config);

app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
stats: {colors: true}
}));

app.use(webpackHotMiddleware(compiler, {
log: console.log
}));

//Routes

// ...additional routes

app.get('*', function(req, res){
res.sendFile(path.resolve(publicPath, 'index.html'));
})

app.use(express.static(publicPath));

app.listen(3000, function(){
console.log('Server running on port 3000');
});


webpack.dev.config.js

var webpack = require('webpack');
var path = require('path');
var nodeModulesPath = path.resolve(__dirname, 'node_modules');
var buildPath = path.resolve(__dirname, 'public', 'build');
var mainPath = path.resolve(__dirname, 'app', 'main.js');

var config = {

devtool: 'eval-source-map',
devServer: {
historyApiFallback: true
},
entry: [

'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'whatwg-fetch',
//Our application
mainPath
],
output: {
path: '/',
publicPath: 'http://localhost:3000/build/',
assetsPublicPath: 'http://localhost:3000/',
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js?$/,
loader: 'babel',
exclude: nodeModulesPath
},
{
test: /\.css$/,
loader: 'style!css?modules!postcss'
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'url-loader'
}
]
},
postcss: [
require('autoprefixer'),
require('precss')
],
plugins: [
new webpack.HotModuleReplacementPlugin()
],
target: 'web'
};

module.exports = config;


Here's an example React component that should access an image:

import React, {Component, PropTypes} from 'react';
import TopMenu from "./TopMenu";
import styles from '../cssPartials/TopBar.css';

const logo = './images/svg/xenonLogo.svg';

const TopBar = () => {

return (
<div className={styles.topBar}>
<div className={styles.logoHolder}>
<img src={logo} alt="Xenon Logo" />
</div>
<TopMenu />
</div>
)

}

export default TopBar


And this is the file structure for the app:

root
|-app
|-admin
|-components //React components
|-users
|-components //React components
|-data //contains database and redux files
|-node_modules
|-public //This is the public folder specified in server.js and webpack.dev.config.js
|-images
|-svg //contains the svg files
|-index.html
|-bundle.js
|-.babelrc // babel config file
|-nodemon.json //nodemon config file
|-package.json
|-server.js
|-webpack.dev.config.js


I think that's everything, but let me know if there's any more code required. Thanks everyone!

Answer

There are couple of things you have to check in your webpack config.

First - Make sure that you have installed url-loader, file-loader npm packages

Try changing your output config to this one -

  output: {
    path: path.join(__dirname, 'public'),
    publicPath: 'http://localhost:8080/public/',
    filename: 'bundle.js'
  }

and loader for images

 {
    test: /\.(jpe?g|png|gif|svg)$/i,
    include : path.join(__dirname, 'images'),
    loader  : 'url-loader?limit=30000&name=images/[name].[ext]'
 }, // inline base64 URLs for <=30k images, direct URLs for the rest

Also In your react component, you need to import svg file.

import React, {Component, PropTypes} from 'react';
import TopMenu from "./TopMenu";
import styles from '../cssPartials/TopBar.css';

import logo from './images/svg/xenonLogo.svg';

const TopBar = () => {

    return (
        <div className={styles.topBar}>
            <div className={styles.logoHolder}>
                <img src={logo} alt="Xenon Logo" />
            </div>
            <TopMenu />
        </div>
    )

}
Comments