javascriptreactjswebpackwebpack-4urlloader

Webpack 4 - unable to load images with absolute path in src using url-loader


I have been been struggling with an issue with Webpack. I have tried searching everywhere online for a solution but did not manage to solve my problem.

I am building a React application with the following project structure:

package.json
webpack.config.js
src
- images
- components
-- Display
--- Display.js
--- config.js
- Frame
-- Frame.js
index.js
index.html

Here is webpack.config.js:

var path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "index.js",
    publicPath: "/"
  },
  module: {
    rules: [
      { test: /\.(js)$/, use: "babel-loader" },
      {
        test: /\.(jpg|png|gif)$/,
        use: {
          loader: "url-loader",
          options: {
            name: "[name].[ext]"
          }
        }
      },
      { test: /\.css$/, use: ["style-loader", "css-loader"] },
      { test: /\.json$/, loader: "json-loader" }
    ]
  },
  mode: "development",
  plugins: [
    new HtmlWebpackPlugin({
      template: "src/index.html"
    })
  ]
};

config.js provides a variable with the image path to Display.js, which then passes it to Frame.js as a prop. Frame.js renders the image with the provided path.

//config.js
export const imgPath = "/src/images/icon.gif";

//Display.js
import {imgPath} from "./config.js";
<Frame imgSrc={imgPath} />

//Frame.js
<img src={this.props.imgSrc} />

The problem I am facing is that the image icon.gif is not put in-line in the javascript bundle but instead the browser makes a request to fetch the file, which is not the expected behaviour. When I build the application in production mode, the image is not displayed at all.

Could someone please help me get this right? Basically, there are two problems I am facing:

  1. The images are not made inline by the url-loader
  2. The images are not displayed at all in production build.

Thank you!


Solution

  • You have to import the file first. But since your publicPath is set to '/', and your images are emitted into dist, the actual path to the image you need to use is /icon.gif.

    1) Import all the possible files (Be sure to use the correct path here)

    // includes.js
    
    import './src/images/icon1.gif';
    import './src/images/icon2.gif';
    import './src/images/icon3.gif';
    

    2) Export the production file path function

    //config.js
    
    import './includes.js';
    
    export const imgPathFunc = num => `/icon${num}.gif`;
    

    3) Import it in Display.js

    //Display.js
    
    import { imgPath } from "./config.js";
    
    {serverResponse && <Frame imgSrc={imgPath(serverResponse)} />}