3

Is there any way in Angular app without ejecting webpack configuration to have inlined resources, as SVGs in CSS background properties?

I have already tried custom webpack builder to remove built-in file-loader rule and add uri-loader, but, SVGs are not inlined.

I suspect that it may be somehow related to internal SCSS/CSS processing using postcss.

1

1 Answer 1

5
+500

As you said, url-loader does not handle urls in style files. To do that, you need to use postcss-url package.

To use a custom webpack configuration without ejecting, you need to install this package. After configuring your workspace with the directions provided in that package, you can use the following webpack configuration:

const url = require('postcss-url');    
const urlPlugin = url([{ filter: '**/*.svg', url: 'inline' }]);
    
module.exports = config => {
  for (const rule of config.module.rules) {
      const loader = rule.use && rule.use.find(x => x.loader === 'postcss-loader');
      if (loader) {
          loader.options.plugins = [urlPlugin];
      }
  }
    
  return config;
};

Basically, this code adds postcss-url plugin to every postcss-loader in Angular's default webpack configuration.

You can edit this configuration to customize for your needs. For example, you can use maxSize parameter to exclude files greater than a certain size. Read postcss-url repo for all options.

EDIT by Zygimantas:

I am accepting your answer as correct and adding a Typescript version of webpack.config.ts

import { Configuration, NewLoader } from 'webpack'
import * as PostCssUrlPlugin from 'postcss-url'

export default (config: Configuration) => {
    if (config.module === undefined) {
        throw new Error()
    }

    let patched = false
    for (const rule of config.module.rules) {
        if ('use' in rule && Array.isArray(rule.use)) {
            const loader = rule.use.find(
                (a): a is NewLoader =>
                    typeof a !== 'string' &&
                    'options' in a &&
                    a.loader !== undefined &&
                    a.loader.includes('postcss-loader'),
            )

            if (loader !== undefined && loader.options !== undefined) {
                loader.options.plugins = [PostCssUrlPlugin([{
                  filter: '**/*.svg',
                  url: 'inline',
                }])]

                patched = true
            }
        }
    }

    if (!patched) {
        throw new Error('Could not patch webpack configuration')
    }

    return config
}

NOTE:

In Javascript version, I had to use x.loader.includes('postcss-loader') instead of x.loader === 'postcss-loader' because loader value was a full path in my case.

2
  • I will be able to award a bounty in 17 hours since now.
    – Zygimantas
    Commented Aug 8, 2020 at 22:10
  • 1
    @Zygimantas thanks for the edit. By the way, Angular may change their webpack configuration from version to version, so watch out for that. My original answer was for Angular 8. Commented Aug 8, 2020 at 22:27

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.