webpack - scss cannot resolve background-image url

4.4k views Asked by At

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)
  }
}
3

There are 3 answers

0
Phil On BEST ANSWER

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'.

0
joseluismurillorios On

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

0
Abraham On

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