12

I am using webpack and simply trying to apply a background-image specified in a url property to an html element.

I've looked at several threads (this one for instance) but did not find something that works for me.

Here's my setup :

// index.js

import React from 'react'
import styles from './styles.css'

const MyComponent = () => {
  return (
    <div className={styles.container}></div>
  )
}

export default MyComponent

// styles.css

.container {
  background-image: url('../../../static/public/images/my-background.jpg');
}

// webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
  entry: path.join(__dirname, "src", "index.js"),
  output: {
    path: path.join(__dirname, "dist"),
    filename: "index.bundle.js"
  },
  mode: process.env.NODE_ENV || 'development',
  resolve: { 
    modules: [path.resolve(__dirname, "src"), "node_modules"],
  },
  devServer: {
    static: path.join(__dirname, 'src')
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: path.join(__dirname, "src", "index.html"),
    }),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'static',
          to: 'static'
        }
      ]
    })
  ],
  module: {
    rules: [
        { 
            test: /\.(js|jsx)$/, 
            exclude: /node_modules/, 
            use: ["babel-loader"] 
        },
        {
            test: /\.(css)$/,
            use: ["style-loader", "css-loader"],
        },
        {
          test: /\.(jpg|png|svg|gif)$/,
          use: ['url-loader', 'file-loader'],
        },
    ],
},
}

When reaching localhost I do see the path being resolved : enter image description here

However, when I try to reach that url, all I see is a little white square ...

enter image description here

This is definitely not the image. I do find the image present in my build in ./dist/static/public/images/my-background.jpg

Note that the image has a large size : 3842 × 2162

I think this has to do with webpack loader configuration, but did not quite find how to adjust it to get it to work here. Any help would be very appreciated !

3
  • 3
    Try { test: /\.(jpg|png|svg|gif)$/, type: 'asset/resource', }, instead. Commented Nov 9, 2021 at 22:34
  • 1
    EDIT: Thanks a lot. Just tried with { test: /\.(jpg|png|svg|gif)$/, type: 'asset/resource', }, And it did show the image. Could you explain to me why I need to be removing loaders here :O seems all examples I seen online where using those. XD Commented Nov 9, 2021 at 22:40
  • 2
    You're welcome.. basically you are may be using a new version of webpack, where url-loader and file-loader are deprecated and Asset Modules are introduced. I'll put it in an answer :) Commented Nov 9, 2021 at 22:48

4 Answers 4

15

You are may be using a new version of Webpack, where url-loader and file-loader are deprecated and Asset Modules are the alternatives.

Try using:

{
      test: /\.(jpg|png|svg|gif)$/,
      type: 'asset/resource',
},

instead.

For more information click here.

Sign up to request clarification or add additional context in comments.

1 Comment

For anyone who googles this, I am using webpack : 5.62.1. Thanks a lot @SomoKRoceS !
4

I had the same issue and it finally worked by using ~ to reference the project directory and access public folder from there.

background-image: url("~/public/images/person.png");

And this is working fine for me :)

OR And the other alternative would be to move your images to the src directory, webpack will pack them in a folder called static/media as static files

Comments

1

The solution (using a webpack version prior to 5.0) is to turn off css-loader's URL parsing, because the CSS file isn't updating the URL string when webpack builds

module.exports = { 
      ...
     module: {
        rules: [ 
            { //https://webpack.js.org/loaders/css-loader/
                test: /\.css$/, 
                use: ["style-loader"]
            },

            { //https://webpack.js.org/loaders/css-loader/
                test: /\.css$/, 
                loader: "css-loader",
                options: {
                    url: false,
                }
            }
        ]
    }

}

Note that this will make so that the files used in .css will not be hashed and will be structured like the original /public/ folder upon building the project to the /dist/ folder. Which is what makes it work.

For reference see this github issue and this one

Also, I'm using:

  • "css-loader": "^6.7.2",
  • "file-loader": "^6.2.0",
  • "html-webpack-plugin": "^5.5.0",
  • "style-loader": "^3.3.1",
  • "url-loader": "^4.1.1",
  • "webpack-cli": "^4.10.0",
  • "webpack-dev-server": "^4.11.1"

Update: Having a rule object that uses 'url-loader' might override out files from the other rules. So, in that case you should remove it and have the options in the 'css-loader' like so:

{ 
    test: /\.css$/, 
    loader: "css-loader",
    options: {
        url: true,
        esModule: false
    }
}

Try commenting out each option and rules and see the results to check what each option and rule is doing. Delete the .dist/ folder before each build (because it's not automatically clean after each build) to make sure you know what files are produced and when.

Comments

1

I had just upgraded from webpack v4 to v5 and, as per the webpack docs on asset management for images, I had to make sure the images in the css files were actually currently located where I was saying they were and not where they will be.

So, changing from:

...
background: url(/static/images/header.jpg)
...

to:

...
background: url(/images/header.jpg)
...

everywhere fixed this issue for me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.