5

In my scss file, I use background-image: url("../../../assets/images/home/banner-mobile.png");

The application runs successfully, but no background image is shown:

The background image URL is not resolved. enter image description here

webpack/webpack.base.js

const webpack = require("webpack");
const path = require("path");

const utils = require("./utils");

const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  entry: "./src/index.jsx",
  resolve: {
    alias: {
      "@": utils.resolve("src")
    },
    extensions: ["*", ".js", ".jsx"],
    fallback: {...},
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
          {
            loader: "sass-loader"
          },
          {
            loader: "sass-resources-loader",
            options: {
              resources: ["./src/assets/scss/main.scss"],
            },
          },
        ],
      },
      {
        test: /\.(png|jpg|gif)$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 8192
            },
          },
        ],
      }
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "public/index.html",
      filename: "index.html",
      inject: true,
    })
  ],
};

webpack/webpack.dev.js

const { merge } = require("webpack-merge");
const base = require("./webpack.base");

const Dotenv = require("dotenv-webpack");

module.exports = merge(base, {
  mode: "development",
  devtool: "inline-source-map",
  output: {
    publicPath: '/',
  },
  devServer: {
    port: 3000,
    static: true,
    static: 'dist'
  },
  plugins: [new Dotenv({ path: "./.env.development" })],
});

Update 1
When I view the png in Web Inspector > Sources: enter image description here

When I open the image with its URL in the browser: enter image description here

Update 2:
When I build and view the image via VSCode, it shows below: enter image description here

Not sure if the below file-is related

webpack/Util.js

const path = require('path')

module.exports = {
  resolve: function(dir) {
    return path.join(__dirname, '..', dir)
  }
}
Muzammil Ismail
  • 303
  • 4
  • 9
CCCC
  • 5,665
  • 4
  • 41
  • 88
  • Can you confirm that the relative path is correct? It should be relative to the CSS file itself. – Terry Nov 29 '21 at 02:42
  • @Terry yes, it's correct. – CCCC Nov 29 '21 at 02:45
  • I mean, it certainly looks like Webpack resolved _some_ image. It didn't come up with `1caaf59….png` from nothing. What do you see if you open that image URL directly? – Phil Nov 29 '21 at 02:55
  • @Phil If i open the png, it shows image with white background, not my image – CCCC Nov 29 '21 at 03:15
  • But it's an actual, valid PNG image? – Phil Nov 29 '21 at 03:17
  • @Phil please check my above update – CCCC Nov 29 '21 at 03:21
  • FYI, that little white square is the _"not an actual image"_ image. Can you try building your app (so it produces static files) and see exactly what that image is? Check it in a hex editor or similar – Phil Nov 29 '21 at 03:24
  • @Phil PLEASE check above – CCCC Nov 29 '21 at 03:47
  • What version of Webpack are you using? Are you aware that the [url-loader](https://v4.webpack.js.org/loaders/url-loader/) is deprecated in v5? – Phil Nov 29 '21 at 03:58
  • @Phil Oh I am using webpack `5.64.2`, but I tried below commnent still not working – CCCC Nov 29 '21 at 04:01

3 Answers3

4

Since you're using Webpack 5, I'd recommend using Asset Modules instead of the deprecated loaders

module: {
  rules: [
    // ...
    {
      test: /\.(png|jpg|gif)$/i,
      type: "asset",
      parser: {
        dataUrlCondition: {
          maxSize: 8192
        }
      }
    }
  ]
}

I suspect you were running into a resource handling duplication issue as noted in the documentation...

When using the old assets loaders (i.e. file-loader / url-loader / raw-loader) along with Asset Module in webpack 5, you might want to stop Asset Module from processing your assets again as that would result in asset duplication. This can be done by setting asset's module type to 'javascript/auto'.

Phil
  • 157,677
  • 23
  • 242
  • 245
1

Solution

After a long search, the only solution I found is to use ~ to reference the initial project directory and accessing public folder from there.

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

And this is working fine for me :)

OR And the other alternative would be to move images to the src directory, and this won't be a problem since webpack would pack them in a folder called static/media as static files

Abraham
  • 12,140
  • 4
  • 56
  • 92
0

I use file-loader as shown in this rule, it allow me to preserve the file name and relative path, so having my folder structure like assets > images, I just have to strip "assets" from the path:

{
  test: /\.(gif|png|jpg|jpeg)$/,
  loader: 'file-loader',
  options: {
    name: '[path][name].[ext]',
    outputPath: (file) => {
      const p = file.split('assets/')[1];
      return p;
    },
  },
},

This will let you with all images within "assets" folder right into the root bundle and every path will be replicated (ex. assets/images/home/banner.png will be on images/home/banner.png in your dist directory), just be sure all your images are inside your assets folder to avoid getting name conflicts

joseluismurillorios
  • 1,005
  • 6
  • 11