Rose
Rose

Reputation: 2809

Resolving css background-image url with Webpack

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 !

Upvotes: 12

Views: 18215

Answers (4)

Akaisteph7
Akaisteph7

Reputation: 6486

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.

Upvotes: 1

pedagogyfirst
pedagogyfirst

Reputation: 53

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.

Upvotes: 1

Abraham
Abraham

Reputation: 15670

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

Upvotes: 4

SomoKRoceS
SomoKRoceS

Reputation: 3043

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.

Upvotes: 14

Related Questions