laravel-mix: Overriding file loader rules to add exceptions

I’m using Quill in a Vue component. To avoid loading everything from the distributable build, I have prepared a quill entry file (like this one).

When doing this, however, webpack moves the svg icons used by Quill theme in /fonts/vendor/quill and returns their path, instead of returning the svg content, as Quill expects. I end up with this:

schermata 2018-01-19 alle 11 19 18

This doesn’t happen when using the distributable build in the npm package.

Quill’s build guide and related webpack example say that icons should be loaded with html loader: https://github.com/quilljs/webpack-example/blob/master/webpack.conf.js#L39

Now to my question: how can I replace/override Laravel Mix’s svg loader so it doesn’t match Quill icon paths, and instead setup html-loader just for that path?

Thanks

Edit: A past issue (closed unanswered) asks the same thing: #942.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 2
  • Comments: 28 (12 by maintainers)

Most upvoted comments

Since this issue is now closed I don’t expect any more replies. In the meantime, my custom solution was to add an exception to the webpack rule by cycling through Mix’s webpack configuration, like this:

const mix = require('laravel-mix');
const quillIconsRegex = /node_modules\/quill\/assets\/icons\/(.*)\.svg$/;

// Exclude quill icons
Mix.listen('configReady', function(config) {
  const rules = config.module.rules;
  const targetRe = /(\.(png|jpe?g|gif)$|^((?!font).)*\.svg$)/;

  for (let rule of rules) {
    if (rule.test.toString() == targetRe.toString()) {
      rule.exclude = quillIconsRegex;
      break;
    }
  }
});

// Use a custom loader for Quill inline icons
mix.webpackConfig({
  module: {
    rules: [{
      test: quillIconsRegex,
      use: [{
        loader: 'html-loader',
        options: {
          minimize: true
        }
      }]
    }]
  }
});

I’d like a better way to do this though, the file loader regex that I’m using to find the rule could change anytime.

I also need to be able to not use Laravel Mix’s built-in SVG handling. I was able to do so building upon @tegola’s code.

First I did console.info() on the rules to find this:

{ rule: { test: /\.html$/, loaders: [ 'html-loader' ] } }
{ rule:
   { test: /(\.(png|jpe?g|gif|webp)$|^((?!font).)*\.svg$)/,
     loaders: [ [Object], [Object] ] } }
{ rule:
   { test: /(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/,
     loader: 'file-loader',
     options: { name: [Function: name], publicPath: '//127.0.0.1:8080/' } } }
...

It’s the second rule that does the loading of SVGs along with images.

To be able to remove the built-in SVG loading, but keep the image loading, I had to modify the regex to remove the SVG part.

Based on @tegola’s code, this is the code I wrote with which I was able to remove the built-in SVG loader so that I could use my own:

const mix = require('laravel-mix');

// Do not use Laravel mix's built-in SVG loader.
Mix.listen('configReady', function(config) {
  const rules = config.module.rules;
  const svgRegexPart = '|^((?!font).)*\\.svg';

  for (let rule of rules) {
    if (rule.test) {
      if (('' + rule.test).indexOf(svgRegexPart) > -1) {
        // Recreate the RegExp with just the SVG part removed from
        // the built-in mix RegExp for loading SVGs and images.
        rule.test = new RegExp(('' + rule.test).replace(svgRegexPart, ''));
      }
    }
  }
});

// ...

Though note that after I did this to use a loader that turns SVGs into Vue components (vue-svg-loader), SVGs linked from CSS (e.g. for background-image) don’t work anymore.

@tpraxl PR looks very nice, I’m gonna give it a spin tomorrow. Great work, thank you!

@tpraxl thanks for spending your time looking into this. I currently have no spare time to dedicate to the project, and don’t even know well webpack and laravel mix config builder, actually. I’ll keep a look at this thread and help in any possible way.