webpack - scss cannot resolve background-image url
Asked Answered
P

3

6

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)
  }
}
Plasmo answered 29/11, 2021 at 2:28 Comment(10)
Can you confirm that the relative path is correct? It should be relative to the CSS file itself.Microscopic
@Microscopic yes, it's correct.Plasmo
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?Army
@Army If i open the png, it shows image with white background, not my imagePlasmo
But it's an actual, valid PNG image?Army
@Army please check my above updatePlasmo
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 similarArmy
@Army PLEASE check abovePlasmo
What version of Webpack are you using? Are you aware that the url-loader is deprecated in v5?Army
@Army Oh I am using webpack 5.64.2, but I tried below commnent still not workingPlasmo
A
5

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

Army answered 29/11, 2021 at 4:8 Comment(0)
S
2

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

Stereogram answered 13/7, 2022 at 22:11 Comment(0)
O
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

Os answered 29/11, 2021 at 2:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.