How can I resolve background image URL inside sass file using webpack-4?

29,499

Solution 1

Problem is not in the webpack. Your problem is in the background url path. As you have imported all css to a single main.scss you need to do the following in the backgroud url -

.img-container {
      background: url('./../img/homepage-login-prog.jpg') no-repeat center center fixed;
      background-size: cover;
 }

Solution 2

Ran into a similar problem and what worked for me was to move my main.scss file into my sass folder. Before, it was in the src folder. The main.scss file imports all my other .scss files. Inside my index.js, which is the entry point, I import the main.scss file.

My file structure however is different than yours.

file structure

I have a dist folder for the output, and the src folder for input.

index.js:

import "./sass/main.scss";

main.scss:

@import "./footer";
@import "./header";
@import "./home";
@import "./navigation";
@import "./reset";
@import "./typography";
@import "./variables";

_header.scss:

  #hero {
  background-image: url("../assets/heroImage.jpg");
  background-size: cover;
  height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: center;
}

I have been getting the same exact error because of the background-image: url() problem in my scss code. This import structure solved it for me.

For my webpack, I have a very similar config split into 3, common, dev, and prod. The only plugin I added is 'resolve-url-loader' in webpack.dev. I've tried the publicpath in miniCssExtractPlugin to no avail.

My common is almost the exact same as yours except for the entrypoint. Mine is index.js in the src folder and not app.js.

webpack.dev.js

const path = require("path");
const common = require("./webpack.common");
const merge = require("webpack-merge");
var HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = merge(common, {
  mode: "development",
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist")
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/template.html"
    })
  ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          {
            loader: "style-loader"
          },
          {
            loader: "css-loader"
          },
          {
            loader: "resolve-url-loader"
          },
          {
            loader: "sass-loader"
          }
        ]
      }
    ]
  }
});

This solved it for me after countless hours. Let me know if you this helps in any way. Cheers.

Share:
29,499
dedZombie
Author by

dedZombie

Updated on July 09, 2022

Comments

  • dedZombie
    dedZombie almost 2 years

    this is my first time writing here so please bear that in mind. I'm first time using webpack in a project and I have a problem where I'm trying to set a background image using background url() function in my sass file, something like this:

    .img-container {
      background: url('../../img/homepage-login-prog.jpg') no-repeat center center fixed;
      background-size: cover;
    }
    

    My folder structure is:

    - css
      | app.css
    - dist (this folder is created after building for production)
    - img
      | some-image.jpg
    - js
      | app.js (entry point for webpack output, 
                this is where I import main.scss file)
    - js-vendor
      | vendor.js (third-party libraries like bootstrap, jquery)
    - sass  (this is where I keep all my sass files which get compiled using 
             webpack loaders)
      | components
        | greetings-section.scss
        | navbar.scss
      | main.scss
      | variables.scss
    - template.html
    - webpack.common.js
    - webpack.dev.js
    - webpack.prod.js
    

    Because I have webpack configured both for development and production, I have separate files for both of them, where both extend on general (common) configuration file. That one looks like this:

    const path = require("path");
    
    module.exports = {
      entry:{
        main: "./js/app.js",
        vendor: "./js-vendor/vendor.js"
      },
      module: {
        rules: [
          {
            test: /\.html$/,
            use: ["html-loader"]
          },
          {
            test: /\.(svg|png|jp(e*)g|gif)$/,
            use: [{
              loader: "file-loader",
              options: {
                name: "[name].[hash].[ext]",
                outputPath: "img",
              }
            }]
          }
        ]
      }
    };
    

    My webpack dev configuration looks like this:

    const common = require("./webpack.common");
    const merge = require("webpack-merge");
    const path = require("path");
    var HtmlWebpackPlugin = require("html-webpack-plugin");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    
    module.exports = merge(common, {
      mode: "development",
      output: {
        filename: "[name].bundle.js",
        path: path.resolve(__dirname, "dist")
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: "./template.html"
        }),
        new MiniCssExtractPlugin({
          filename: "[name].[contentHash].min.css"
        }),
      ],
      module: {
        rules: [
          {
            test: /\.scss$/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader,
                options: {
                  publicPath: "../../"
                }
              },
              "css-loader",
              "sass-loader"
            ]
          }
        ]
      }
    });
    

    So, after webpack-dev-server starts, it pops an error:

    ERROR in ./sass/main.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/lib/loader.js!./sass/main.scss)
    Module not found: Error: Can't resolve '../../img/homepage-login-prog.jpg' in 'C:\Users\...\...\...\sass'
    

    As you can see I've tried setting a relative path using publicPath option in mini-css-extract-plugin, but it doesn't solve it for me. I've also been reading that other people have similar problems, but none of their solutions worked for me, so what I'm trying to ask is, does anyone know how can i configure webpack to recognize the url of a image inside my sass files, and properly bind it?

    Sorry for the long post, any help would be greatly appreciated.

  • dedZombie
    dedZombie over 4 years
    It still doesn't work, I still get the same error :/ In case you missed it, i am using file-loader to resolve all types of images, but that only works if i already have an image with the src attribute in my html. I need a way to load urls of a background images from sass :/ Still thank you for quick response, hopefully someone else will come up with solution.
  • Tanvir Islam Streame
    Tanvir Islam Streame almost 4 years
    this should work - background-image: url("./assets/heroImage.jpg");