15

Here's my use-case: Most svgs should be inlined. So I setup a rule like this:

{test: /\.svg$/, use: "svg-inline-loader"},

In some instances I just want the url of an svg rather than inlining it. In webpack 1.x I required them like this: require('path/to/file.svg?external').

Here's the corresponding rule:

{test: /\.svg\?external$/, use: "file-loader!image-webpack-loader"},

It seems like webpack 2 does not include the ? part anymore when testing for a rule since only the first rule is being applied to all my svgs after migrating.

Is there a way around this? Is there maybe a different strategy of how to apply different set of loaders for files of the same extension when requireing them?

PS: I'm aware that I could require the file like this: require('!file-loader!image-webpack-loader!path/to/file.svg') but my loaders are a bit more complex than this and I don't want to repeat their configuration all the time.

PSS: This doesn't seem to work either (it still only applies the first rule)

{test: /\.svg$/, use: "svg-inline-loader", exclude: /\?external/},
{test: /\.svg$/, use: "file-loader?!image-webpack-loader", include: /\?external/}
Daniel
  • 2,642
  • 1
  • 26
  • 28

3 Answers3

26

So I recently attended a talk by webpack's Juho Vepsäläinen and found the answer in this slide:

{
  test: /.css$/,

  oneOf: [
    {
      resourceQuery: /inline/, // foo.css?inline
      use: 'url-loader',
    },
    {
      resourceQuery: /external/, // foo.css?external
      use: 'file-loader',
    },
  ],
}

resourceQuery to the rescue!

hitautodestruct
  • 20,081
  • 13
  • 69
  • 93
Daniel
  • 2,642
  • 1
  • 26
  • 28
  • I have the same issue. I want to use less-loader for `*.less` files by default and custom loader for `*.less?module` files. But i don't want to add anything like `?default` to all '.less' files. Can you share your config? – c4off Jul 05 '17 at 11:46
  • 3
    `oneOf` uses the first matching rule. So for your use case put the `resourceQuery: /module/ ` into the first entry and no `resourceQuery` at all into the second. – Daniel Jul 05 '17 at 15:52
  • @Daniel the life saver! – Vishal Sharma Jun 04 '21 at 07:40
8

resolveLoader.alias will be solution for you.

Your config will look like this:

resolveLoader: {
  alias: {
    myLoader1: "svg-inline-loader", // and much more
    myLoader2: "file-loader!image-webpack-loader" // and much more
  }
}

and usage:

require('myLoader1!path/to/file1.svg');
require('myLoader2!path/to/file2.svg');

Or if you want for example myLoader1 config to be default and from time to time use myLoader2 loaders use this kind of config:

{
  test: /\.svg$/,
  use: "svg-inline-loader" // and much more
}

// ...

resolveLoader: {
  alias: {
    myLoader: "file-loader!image-webpack-loader" // and much more
  }
}

and use like this:

require('path/to/file1.svg'); // default svg-inline-loader
require('!myLoader!path/to/file2.svg'); // specific file-loader!image-webpack-loader
// ! at the beginning - disables loaders from default
// and myLoader enables file-loader and image-webpack-loader

PS. I had similar question here it's for webpack 1 but documentation says that resolveLoader.alias works the same.

Community
  • 1
  • 1
Everettss
  • 15,475
  • 9
  • 72
  • 98
  • 3
    Ah brilliant! Yes this is looking very very helpful indeed :) – Daniel Feb 06 '17 at 22:19
  • It seems like loader chaining isn't supported though: `require('!myLoader!path/to/file2.svg');` results in `./file-1234.svg!image-webpack-loader` – Daniel Feb 07 '17 at 11:06
  • Thank you so much, I've been trying to figure out how to disable default loaders... spent a lot of time, not in vein, but nevertheless... a simple exclamation mark at the beginning of the path... lol – maqduni May 04 '19 at 16:39
1

In addition to test, you can specify include/exclude conditions. From the docs on configuration options:

{
    test: /\.jsx?$/,
    include: [
      path.resolve(__dirname, "app")
    ],
    exclude: [
      path.resolve(__dirname, "app/demo-files")
    ]
    // these are matching conditions, each accepting a regular expression or string
    // test and include have the same behavior, both must be matched
    // exclude must not be matched (takes preferrence over test and include)
    // Best practices:
    // - Use RegExp only in test and for filename matching
    // - Use arrays of absolute paths in include and exclude
    // - Try to avoid exclude and prefer include
}
simon04
  • 3,054
  • 29
  • 25