csswebpackcss-loader

Can't resolve '/images/bg.jpg' after updating css-loader to v4


css-loader was at 3.5.3 and my app worked fine. updated it and only it to 4.3.0, and now i get the below compilation error. i'm having trouble figuring out why when looking through the "breaking changes" inherent with an upgrade to v4.

Possibly something to do with my use of a url in a .scss file where the only reference to /images/bg.jpg exists? I have a styles.scss file which imports a "_box-layout.scss" file wherein lies:

.box-layout {
  align-items: center;
  background: url('/images/bg.jpg');
  background-size: cover;
  display: flex;
  height: 100vh;
  justify-content: center;
  width: 100vw;
}

The compilation error:

ERROR in ./src/styles/styles.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/css-loader/dist/cjs.js):
Error: Can't resolve '/images/bg.jpg' in 'C:\Users\gwich\dev\javascript\react\rental-props\src\styles'
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\enhanced-resolve\lib\Resolver.js:209:21
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\enhanced-resolve\lib\Resolver.js:285:5
    at eval (eval at create (C:\Users\gwich\dev\javascript\react\rental-props\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:13:1)
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\enhanced-resolve\lib\UnsafeCachePlugin.js:44:7
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\enhanced-resolve\lib\Resolver.js:285:5
    at eval (eval at create (C:\Users\gwich\dev\javascript\react\rental-props\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:13:1)
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\enhanced-resolve\lib\Resolver.js:285:5
    at eval (eval at create (C:\Users\gwich\dev\javascript\react\rental-props\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:25:1)
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\enhanced-resolve\lib\DescriptionFilePlugin.js:67:43
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\enhanced-resolve\lib\Resolver.js:285:5
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\webpack\lib\NormalModule.js:316:20
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\loader-runner\lib\LoaderRunner.js:367:11
    at C:\Users\gwich\dev\javascript\react\rental-props\node_modules\loader-runner\lib\LoaderRunner.js:233:18
    at context.callback (C:\Users\gwich\dev\javascript\react\rental-props\node_modules\loader-runner\lib\LoaderRunner.js:111:13)
    at Object.loader (C:\Users\gwich\dev\javascript\react\rental-props\node_modules\css-loader\dist\index.js:154:5)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
 @ ./src/app.js 13:0-30
 @ multi babel-polyfill ./src/app.js

My webpack config if interesting:

const path = require("path");
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

process.env.NODE_ENV = process.env.NODE_ENV || "development";

if (process.env.NODE_ENV === "test") {
  require("dotenv").config({ path: ".env.test" });
} else if (process.env.NODE_ENV === "development") {
  require("dotenv").config({ path: ".env.development" });
}

module.exports = (env) => {
  const isProduction = env === "production";

  return {
    entry: ["babel-polyfill", "./src/app.js"],
    output: {
      path: path.join(__dirname, "public", "dist"),
      filename: "[name].js",
    },
    optimization: {
      splitChunks: {
        cacheGroups: {
          commons: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'initial',
          },
        },
      },
    },
    mode: isProduction ? 'production' : 'development',
    module: {
      rules: [
        {
          loader: "babel-loader",
          test: /\.js$/,
          exclude: /node_modules/,
        },
        {
          test: /\.less$/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader,
                options: {
                  sourceMap: !isProduction,
                },
              },
              {
                loader: "css-loader",
                options: {
                  sourceMap: !isProduction,
                },
              },
              {
                loader: "less-loader",
                options: {
                  sourceMap: !isProduction,
                  modifyVars: {
                    "primary-color": "#1c88bf",
                    "link-color": "#1c88bf",
                    "border-radius-base": "2px",
                  },
                  javascriptEnabled: true,
                },
              }
            ],
        },
        {
          test: /\.s?css$/,
          use: [
            {
              loader: MiniCssExtractPlugin.loader,
              options: {
                sourceMap: !isProduction,
              },
            },
            {
              loader: "css-loader",
              options: {
                sourceMap: !isProduction,
              },
            },
            {
              loader: "sass-loader",
              options: {
                sourceMap: !isProduction,
              },
            },
          ],
        },
        {
          test: /\.(svg|eot|ttf|woff|woff2)$/,
          use: {
            loader: "file-loader",
            options: {
              name: "[name].[ext]",
              outputPath: "fonts/",
            },
          },
        },
      ],
    },
    plugins: [
      // new BundleAnalyzerPlugin(),
      new MiniCssExtractPlugin({ filename: '[name].css'}),
      new webpack.DefinePlugin({
        "process.env.FIREBASE_API_KEY": JSON.stringify(process.env.FIREBASE_API_KEY),
        "process.env.FIREBASE_AUTH_DOMAIN": JSON.stringify(process.env.FIREBASE_AUTH_DOMAIN),
        "process.env.FIREBASE_DATABASE_URL": JSON.stringify(process.env.FIREBASE_DATABASE_URL),
        "process.env.FIREBASE_PROJECT_ID": JSON.stringify(process.env.FIREBASE_PROJECT_ID),
        "process.env.FIREBASE_STORAGE_BUCKET": JSON.stringify(process.env.FIREBASE_STORAGE_BUCKET),
        "process.env.FIREBASE_MESSAGING_SENDER_ID": JSON.stringify(process.env.FIREBASE_MESSAGING_SENDER_ID),
      }),
    ],
    devtool: isProduction ? "source-map" : "inline-source-map",
    devServer: {
      contentBase: path.join(__dirname, "public"),
      historyApiFallback: true,
      publicPath: "/dist/",
    },
  };
};

Solution

  • I managed to solve this problem thanks to this article.

    First, I installed url-loader

    npm install url-loader --save-dev
    

    Next, I updated the path in the background url in my webpack.config.js file in the rules section (the image was located in /public/images/bg.jpg while my _box-layout.scss file was in /src/styles/components/ imported by /src/styles/styles.scss):

      rules: [
        {
          test: /\.(png|jpg)$/,
          loader: 'url-loader'
        },
    

    Lastly, I updated my _box-layout.scss file:

    .box-layout {
      align-items: center;
      background: url('../../public/images/bg.jpg');
      background-size: cover;
      display: flex;
      height: 100vh;
      justify-content: center;
      width: 100vw;
    }