Greg Holst
Greg Holst

Reputation: 974

Image file cannot be found when using URL loader of webpack with React & Django

I am struggling with loading images using the img-tag within a React component. Basically I am using webpack's url loader to load the images and add a hash (to avoid later caching issues). When running "npm run dev" the bundle is created and the image file gets created in the specified subfolder "images". However, Chrome cannot find the image and gives me the following error:

GET http://localhost:8000/images/49b281dc3f9e139385f943c7e3f918b1-git.jpeg 404 (Not Found)

More specific: The bundle "main.js" is created in the frontend folder (as given in the index.html) and has a subfolder "images" with the file created by the URL loader: 49b281dc3f9e139385f943c7e3f918b1-git.jpeg

I tried loading the image with css, which works (i.e. is shown in the browser), however the url-loader seems not to be used in this case as the hash does not get added and the file is loaded from the original location and not the place of the bundle.

I saw another thread about the topic (How to load image files with webpack file-loader) but cannot see how publicpath should be of help for my case. The problem might also be related with my setup with Django: I have put a frontend app into the Django project, where all the React stuff resides (following this tutorial:https://www.youtube.com/watch?v=GieYIzvdt2U and its source code: https://github.com/bradtraversy/lead_manager_react_django)

This is the webpack.config.js

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader"
                }
            },
            {
                test: /.*\.(gif|png|jpe?g)$/i,
                use: [
                  {
                    loader: 'url-loader',
                    options: {
                        limit: 8000,
                        name: 'images/[hash]-[name].[ext]'
                    },
                  },
                ]
            }
        ]
    }
};

This is the index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="https://bootswatch.com/4/flatly/bootstrap.min.css">
    <title>Title</title>
</head>
<body>
    <div id="app"></div>
    {% load static %}
    <script src="{% static "frontend/main.js" %}"></script>
    <link rel="stylesheet" href="{% static 'css/styles.css' %}">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>

React component MainHeader.js

import React, {Component} from 'react';
import logo from '../../../static/img/git.jpeg';

class MainHeader extends Component {
    render() {
        return (

            <div className="container">
                <nav className="navbar navbar-expand-sm navbar-light">
                    <img src={logo} className="img-fluid" alt="Logo" width={800} height={800}/>
                    <a className="navbar-brand" href="#">Title</a>
                    <button className="navbar-toggler" type="button" data-toggle="collapse"
                            data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
                            aria-expanded="false" aria-label="Toggle navigation">
                        <span className="navbar-toggler-icon"></span>
                    </button>

                    <div className="collapse navbar-collapse d-flex justify-content-end" id="navbarSupportedContent">
                        <ul className="navbar-nav">
                            <li className="nav-item active">
                                <a className="nav-link" href="#">Welcome, customer!<span className="sr-only">(current)</span></a>
                            </li>
                            <li className="nav-item dropdown">
                                <a className="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
                                   data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                    Dropdown
                                </a>
                                <div className="dropdown-menu" aria-labelledby="navbarDropdown">
                                    <a className="dropdown-item" href="#">Action</a>
                                    <a className="dropdown-item" href="#">Another action</a>
                                    <div className="dropdown-divider"></div>
                                    <a className="dropdown-item" href="#">Something else here</a>
                                </div>
                            </li>
                        </ul>
                    </div>
                </nav>
            </div>
        );
    }
}

export default MainHeader;

My App.js:

import React, { Component } from 'react';
import { Fragment } from 'react';
import ReactDOM from 'react-dom';

import Header from './layout/Header';
import Dashboard from './analytics/Dashboard';
import MainHeader from "./layout/MainHeader";

class App extends Component {
    render() {
        return (
            <Fragment>
                <MainHeader/>
                <Header />
                <div className="container">
                    <Dashboard/>
                </div>

            </Fragment>

        )
    }
}

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

These are my static file settings in settings.py of Django:

STATIC_ROOT = os.path.join(BASE_DIR, "..", "www", "static")
STATIC_URL = '/static/'

Upvotes: 1

Views: 2116

Answers (1)

Greg Holst
Greg Holst

Reputation: 974

I tried a number of changes in the Django settings, but none of them made the application look into the folder where the image files are located (http://localhost:8000/static/frontend/images/)

Finally, the only thing that worked successfully is to add the following to the webpack.config.js

output: {
    filename: "main.js",
    publicPath: "/static/frontend/"
},

Upvotes: 2

Related Questions