103

When I have a loader configuration with multiple tests matching a file, I would expect only the first matching loader to be used but that doesn't seem to be the case.

I tried reading the source but even when I found the bit that I think implements the loading I can't understand how it behaves.

The documentation doesn't mention how that situation should behave either.

w00t
  • 17,944
  • 8
  • 54
  • 62

3 Answers3

124
{
    test: /\.css$/,
    loaders: ['style'],
},
{
    test: /\.css$/,
    loaders: ['css'],
},

and

{
    test: /\.css$/,
    loaders: ['style', 'css'],
},

appear to be equal. In function terms, this is the same as style(css(file)) (thanks Miguel).

Note that within loaders they are evaluated from right to left.

Juho Vepsäläinen
  • 26,573
  • 12
  • 79
  • 105
  • 2
    Hmm, not very useful behavior I think :-/ I would rather use preLoaders for that behavior... – w00t Aug 26 '15 at 18:54
  • I rather use the latter form. `preLoaders` have their uses for linting and such checks. There are also `postLoaders` but so far I haven't found any good use for those. That said, maybe there's some. – Juho Vepsäläinen Aug 26 '15 at 18:59
  • Apparently the use case for `postLoaders` is code coverage. Source: https://webpack.github.io/docs/loaders.html . – Juho Vepsäläinen Aug 26 '15 at 19:00
  • Hmmm weird that you should compress images in a preloader but convert coffeescript in a loader... rather arbitrary. – w00t Aug 26 '15 at 19:07
  • Yeah, that's true. There are some bits in the configuration that could probably be dropped without losing anything of value (`loader` vs. `loaders` and so on). – Juho Vepsäläinen Aug 26 '15 at 19:13
  • The most important note in the post is evaluating RIGHT to LEFT. That is confusing! – Evan Layman Dec 22 '15 at 20:21
  • 25
    Loaders act like functions, that's why it's from right to left. When you use this `"style!css"`, imagine them like functions: `style( css( file ) )`... in this case `css` is called first. – Miguel Angelo Mar 02 '16 at 20:08
  • 17
    Evaluating from RIGHT to LEFT made me struggled for a while. @miguel-angelo your `style( css( file ) )` explanation is a relief to me. – Evi Song Apr 24 '16 at 11:12
  • 1
    RIGHT to LEFT most likely essentially means BOTTOM to TOP, when we are looking at Webpack 3 Syntax... most bottom: _first_ aka _innermost_ function... – Frank N Sep 19 '17 at 11:26
  • AUGH! They also load from the bottom up! WHAT – light24bulbs Jan 18 '18 at 16:22
  • @light24bulbs It's a legacy thing. Impossible to change without breaking. Note that plugins go from top to bottom. – Juho Vepsäläinen Jan 22 '18 at 18:25
  • @JuhoVepsäläinen that behavior should be much more heavily documented than it is – light24bulbs Jan 30 '18 at 14:38
  • 1
    I don't know when this was added but there's finally documentation about the order: https://webpack.js.org/concepts/loaders/#loader-features Loaders can be chained. Each loader in the chain applies transformations to the processed resource. A chain is executed in reverse order. The first loader passes its result (resource with applied transformations) to the next one, and so forth. Finally, webpack expects JavaScript to be returned by the last loader in the chain. – Eric Majerus Feb 06 '19 at 05:12
  • Does it process on all loaders if it's match with multiple rule's tests? I mean the first case when we have 2 separate rules but with the same test, does it process on both loader or just the first match – Quoc Van Tang Jan 15 '22 at 05:58
  • @QuocVanTang It processes all the matches. – Juho Vepsäläinen Jan 17 '22 at 08:57
  • @JuhoVepsäläinen so it will process all the matches from bottom to top, and if inside 1 match with multiple loaders, it will process all from right to left, is it correct? – Quoc Van Tang Jan 17 '22 at 09:33
  • @QuocVanTang It will process from bottom to top and for each of these from left to right (and then from right to left in the "pitching" phase which is useful for tasks like caching). I have more info and explanations at https://survivejs.com/webpack/loading/loader-definitions/ as there's more to the topic. – Juho Vepsäläinen Jan 17 '22 at 13:34
  • @JuhoVepsäläinen Thank you very much – Quoc Van Tang Jan 18 '22 at 07:35
80

Official documentation explains it really well. Unfortunately all the necessary info are spread in different sections of documentation. Let me wrap up all that you need to know.

1.

Make sure they are in correct order (bottom to top).

2.

They are functions that take the source of a resource file as the parameter and return the new source.

3.

Loaders can be chained. They are applied in a pipeline to the resource. The final loader is expected to return JavaScript; each other loader can return source in arbitrary format, which is passed to the next loader.

So...

If you have somefile.css and you are passing it through loaderOne, loaderTwo, loaderThree is behaves like a regular chained function.

{
    test: /\.css$/,
    loaders: ['loaderOne', 'loaderTwo', 'loaderThree']
}

means exactlly the same as...

loaderOne(loaderTwo(loaderThree(somefile.css)))

If you are coming from grunt || gulp world it is confusing. Just read loaders order from right to left.

Paweł Grzybek
  • 1,093
  • 7
  • 14
4

This answer was helpful to me but I'd like to complement with another point which affects loader order, which is the loadername! approach.

Let's say you have an url-loader in your config with an higher priority than file-loader and you'd like to import an image path with the latter. Doing nothing would import the file via url-loader (which creates an encoded data-url).

Prefixing the import with file-loader! would direct the import to that loader.

import image from 'file-loader!./my-img.png'
E. Sundin
  • 4,103
  • 21
  • 30
  • 3
    Yes, although I like to avoid that because then you cannot decide at build time if the file should be a link or embedded. You can also start with `!!` to skip any other loaders BTW… – w00t Sep 29 '17 at 09:39