url() in SCSS won't resolve correctly with Webpack 4

Viewed 1295

I have posted my Webpack configs below for a production environment. I am attempting to use background-image: url(../img/chevron-thin-right.svg); in one of my SCSS files but it is being resolved to background-image: url([object Module]) and therefore not working. I am trying to port a purely SCSS and HTML project into a react app being bundled by Webpack so this above approach used to work. Any fixes would be greatly appreciated.

webpack.common.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const outputDirectory = 'dist';

module.exports = {
  entry: './src/client/index.js',
  output: {
    path: path.join(__dirname, outputDirectory),
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Production',
      template: './public/index.html',
      favicon: './public/favicon.ico',
      hash: true,
      filename: 'index.html'
    })
  ],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.(jpg|png|woff|woff2|eot|ttf)$/,
        use: {
          loader: 'file-loader?limit=100000&name=images/[name].[ext]'
        }
      },
      {
        test: /\.svg$/,
        use: [
          "babel-loader",
          {
            loader: "react-svg-loader",
            options: {
              svgo: {
                plugins: [
                  { 
                    removeTitle: true,
                    removeComments: true
                  }
                ],
                floatPrecision: 2
              }
            }
          }
        ]
      }
    ]
  }
};

webpack.prod.js

const merge = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const common = require('./webpack.common.js');
const path = require('path');
const autoprefixer = require('autoprefixer');

module.exports = {};

module.exports = merge(common, {
  mode: 'production',
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        }
      }
    }
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new MiniCssExtractPlugin({
      filename: '[name].css'
    })
  ],
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          MiniCssExtractPlugin.loader, 
          {
            loader: 'css-loader',
            options: {
              sourceMap: true,
              root: path.resolve(__dirname),
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                autoprefixer({
                  'browsers': ['last 2 versions', 'ie >= 10'],
                }),
              ],
              sourceMap: true,
            },
          },
          {
            loader: 'sass-loader',
            options: {
              outputStyle: 'compressed',
              sourceMap: true,
              includePaths: [
                './src/client/style/scss',
              ],
            },
          }
        ]
      }
    ]
  }
});

1 Answers

In case anybody else is looking for an answer I was able to solve it. It was due to not loading the associated SVG through the url-loader. Another problem arose when adding svg back in because my inline SVGs I wanted to use as React components were running into errors as they were now going through the url-loader instead of my react-svg-loader.

Below is the working webpack.common.js and webpack.prod.js stayed the same. The solution was to differentiate my inline and external SVGs by turning all inline extensions from .svg to .inline.svg and adjusting webpack config accordingly

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const outputDirectory = 'dist';

module.exports = {
  entry: './src/client/index.js',
  output: {
    path: path.join(__dirname, outputDirectory),
    filename: 'bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Production',
      template: './public/index.html',
      favicon: './public/favicon.ico',
      hash: true,
      filename: 'index.html'
    })
  ],
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.(jpg|png|woff|woff2|eot|ttf|svg)$/,
        exclude: /\.inline.svg$/,
        use: {
          loader: 'url-loader?limit=1000&name=images/[name].[ext]'
        }
      },
      {
        test: /\.inline.svg$/,
        use: [
          "babel-loader",
          {
            loader: "react-svg-loader",
            options: {
              svgo: {
                plugins: [
                  { 
                    removeTitle: true,
                    removeComments: true
                  }
                ],
                floatPrecision: 2
              }
            }
          }
        ]
      }
    ]
  }
};

Related