Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify importLoaders documentation? #228

Closed
BerndWessels opened this issue Feb 3, 2016 · 34 comments
Closed

Clarify importLoaders documentation? #228

BerndWessels opened this issue Feb 3, 2016 · 34 comments

Comments

@BerndWessels
Copy link

I tried to understand importLoaders from the readme but completely don't get it.

Can anybody please give a better explanation of what importLoaders do?

Thank you
Bernd

@mummybot
Copy link

mummybot commented Feb 9, 2016

I'm new to Webpack as well and as I understand it, It does what is says on the tin:

importLoaders allow to configure which loaders should be applied to @imported resources.

Given the following CSS:

/* File style.css */
@import "body.css";
body {
    /*background: yellow;*/
    font-size: 20px;
}
div {
    display: flex;
}
/* File body.css */
$color: red;
body {
    background: $color;
}
div {
    color: white;
    a {
        color: green;
    }
}
div {
    display: flex;
}

On a basic set up with using PostCSS the following would only apply PostCSS plugins to style.css, NOT the @imported body.css:

module: {
    loaders: [
        {
            test:   /\.css$/,
            loader: "style-loader!css-loader!postcss-loader"
        }
    ]
},
postcss: function() {
    return [autoprefixer, precss];
}

To get autoprefixer (and precss) working on @imported CSS files we use importLoaders instead:

module: {
    loaders: [
        {
            test:   /\.css$/,
            loader: 'style!css?importLoaders=1!postcss'
        }
    ]
},
postcss: function() {
    return [autoprefixer, precss];
}

I assume this has something to do with how Webpack loaders parse assets. You have to explicitly tell the loader to interpret @import directives. Why that isn't done by default or as an option in style-loader or css-loader I don't know - maybe there is a way of doing it that I am missing.

@BerndWessels
Copy link
Author

Thanks @mummybot for the explanation. That helped me to get a bit better understanding.

Any idea what the number after importLoaders= means?

@mummybot
Copy link

As far as I can tell it is simply to make sure that the value of importLoaders is true:

module.exports = function getImportPrefix(loaderContext, query) {
    if(query.importLoaders === false)
        return "";
    var importLoaders = parseInt(query.importLoaders, 10) || 0;
    var loadersRequest = loaderContext.loaders.slice(
        loaderContext.loaderIndex,
        loaderContext.loaderIndex + 1 + importLoaders
    ).map(function(x) { return x.request; }).join("!");
    return "-!" + loadersRequest + "!";
};

https://github.com/webpack/css-loader/blob/master/lib/getImportPrefix.js

On an expanded note to my earlier reply, here is the webpackconfig.js I have currently assembled (based on the Webpack getting started example) which does the following:

  1. Uses postcss with the autoprefixer and precss plugins. Precss is SASS syntax but the underlying code is written in Javascript instead of Ruby. The future is Javascript!
  2. Assembles the Precss files into a single file called main.css.
  3. Generates a source map which can then be used with Chrome Dev tools.
var ExtractTextPlugin = require('extract-text-webpack-plugin'),
    autoprefixer = require('autoprefixer'),
    precss = require('precss');

module.exports = {
    entry: [
        "./entry.js",
    ],
    output: {
        path: __dirname,
        filename: "bundle.js"
    },
    devtool: "source-map",
    module: {
        loaders: [
            { 
                test: /\.css$/,
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader?sourceMap&modules&importLoaders=1!postcss-loader')
            },
        ]
    },
    postcss: function() {
        return [autoprefixer, precss];
    },
    plugins: [
        // Set the name of the single CSS file here.
        new ExtractTextPlugin('main.css', { allChunks: true })
    ]
};

@BerndWessels
Copy link
Author

Thanks for that @mummybot .

Not sure that the number really comes down to true/false though. For now I just put 1, but still feel a bit uncomfortable about that.

@randycoulman
Copy link

My understanding is that the number specifies how many loaders after css-loader should be applied to imports. The README says:

importLoaders (int): That many loaders after the css-loader are used to import resources.

If all you have is postcss, then 1 is fine. But if you had more loaders than that, you'd want to bump the number up.

@lvthanh101
Copy link

Thanks @randycoulman, your answer help me alot

@alisonailea
Copy link

what if I want my @import files to use a different set of loaders? For example my project's CSS is postcss but I'm using a npm package with .less files

@BerndWessels
Copy link
Author

@alisonailea Just have multiple loader sections in your webpack config which include/exclude the folders you want.

@qbaty
Copy link

qbaty commented Oct 31, 2016

{
       test: /\.less$/,
       loader: ExtractTextPlugin.extract(
          'style' ,
          'css?sourceMap&importLoaders=1!' +
          'postcss-loader!' +
          'less?sourceMap'
       )
}

I found that if I set importLoaders = 1, less-loader still work for @import file. In this case,
@import file will only use postcss-loader, right ?
But in fact, it does not. and if I remove importLoaders=1, @import files still will bundle.
I can not figure out why..

@rbellamy
Copy link

rbellamy commented Nov 22, 2016

I have to say that the order in which loaders are executed, and the language used here and in the docs is totally confusing.

'style!css!resolve-url!postcss!sass!./main.scss'

Let's look at the order of chaining.

main.scss => sass-loader => postcss-loader => resolve-url-loader => css-loader => style-loader

Now, tell me - which "after" are we talking about? From my understanding of the docs, and what's been said here, what people mean by "after" is the order when reading from left-to-right.

So, "chain order" is right-to-left. importLoaders is from left-to-right.

@silvenon
Copy link

Yeah, it's a bit confusing. What the docs are missing is another example, with an additional loader (sass-loader, less-loader, whatever), just so users can realize that they need to bump the number.

@quantuminformation
Copy link

I would have thought that importing would apply the same rules as the parent document. Ah well.

@silvenon
Copy link

@quantuminformation but maybe you don't want everything applied. Although, it would be a nice default 👍 but I'm not sure if current webpack API supports that.

@yanghuabei
Copy link

yanghuabei commented Jan 2, 2017

I read all the comment above. But still confused.

module.exports = {
    entry: "./entry.js",
    output: {
        path: __dirname,
        filename: "bundle.js"
    },
    module: {
        rules: [
            {
                test: /\.less$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1
                        }
                    },
                    'less-loader'
                ]
            }
        ]
    }
};

I tried with the recommended configuration. No matter what provided to importLoaders, import statements in less file are handled by less loader and make none difference. I am more confused.

@silvenon
Copy link

silvenon commented Jan 7, 2017

@yanghuabei what are you trying to achieve? Don't you want imported Less files to be handled by less-loader?

@codeboyim
Copy link

it seems only have an effect on imported .css resource. If you're importing .scss or .less, they will be handled as normal by webpack.

@joshwiens joshwiens changed the title What does importLoaders do? Clarify importLoaders documentation? Jan 20, 2017
@michael-ciniawsky
Copy link
Member

Fixed by #500

@guidobouman
Copy link

guidobouman commented Jul 4, 2017

@codeboyim's comment did it for me. This is exactly what is missing in the docs.

Explanation of importLoaders

importLoaders only has effect on unresolved @imports. So when using postCSS with nextCSS (no @import resolver) you'll want to set importLoaders. This way nextCSS will also be applied to imported .css files. But when using sass, it already handles the @import statements, so no importLoaders is required.

So, this only happens when css-loader finds an unresolved @import. When using sass-loader for example; All imports are resolved (and concatenated) before css-loader even gets the chance to look for an @import.

@silvenon
Copy link

silvenon commented Jul 5, 2017

@guidobouman whoa, I had no idea it works that way… do you mind adding that to the docs?

@guidobouman
Copy link

@silvenon I've updated my previous comment with my most recent learnings. ☝️

It's a tad bit simpler than you'd think.

@roymiloh
Copy link

@guidobouman I think it's better to include sass-loader in the importLoaders counter anyway, the reason is scenarios like .some-rule { composes: foo from './base.scss'; } where you want sass-loader to run over these files (base.scss in my example) as well.

@guidobouman
Copy link

@roymiloh That feels a bit weird to me, mixing css modules with SASS. Then you'd be better off using the full future CSS spec with just postCSS and it's plugins, and completely dropping anything like SASS, LESS or Stylus.

@dvakatsiienko
Copy link

dvakatsiienko commented Jan 29, 2018

I guess would be great to put a small real-life example of a importLoaders option use case. Because it becomes clear that this option may come in handy more like 'sometimes', rather than 'often', so people won't tend to apply it by default even if they don't need it at all (using sass-loader for example).

@alexander-akait
Copy link
Member

@dvakatsiienko PR welcome

@mnpenner
Copy link

The documentation is still strange. They show this:

{
  test: /\.css$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        importLoaders: 2 // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
      }
    },
    'postcss-loader',
    'sass-loader'
  ]
}

But when would you ever want to include sass-loader if importLoaders only affects .css (non-sass/less) files? So you wouldn't want to set it to 2 here. You probably do want postcss-loader (autoprefixer/cssnano) to run over @imported files though. So the only number that makes sense here is 1, right?

@guidobouman
Copy link

@mnpenner Sass in this case already handles importing of .sass, .scss and extensionless files. One thing this would allow is using sass in .css. No idea why that would be something you want though.

It does make sense to let PostCSS run on imported .css files. So yes a value of 1 does make some sense.

@bugzpodder
Copy link

original issue + PR: #21

@wlxscn
Copy link

wlxscn commented Dec 21, 2018

@mnpenner Sass in this case already handles importing of .sass, .scss and extensionless files. One thing this would allow is using sass in .css. No idea why that would be something you want though.

It does make sense to let PostCSS run on imported .css files. So yes a value of 1 does make some sense.

I think sass-loader will resolve @import, there will be no @import. importLoaders only has effect on unresolved @imports, so value shuld be 0?

@jayarjo
Copy link

jayarjo commented Feb 18, 2019

It still doesn't make any sense. Also pipe syntax is catastrophe and should be deprecated immediately.

@slavafomin
Copy link

The docs totally need clarification. This option is extremely confusing, especially when you use sass-loader, which resolves imports vs. plugins that does not.

@alexander-akait
Copy link
Member

What here need clarify?

options: {
              importLoaders: 2, // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
            },

@guidobouman
Copy link

@evilebottnawi The value 2 does not make sense. See my previous comments.

@joeshub
Copy link

joeshub commented May 26, 2020

TLDR; if you use sass-loader, you don't need to set importLoaders in css-loader

@dongjinc
Copy link

dongjinc commented Sep 24, 2022

    {

            loader: "css-loader",
            options: {
              importLoaders: 0, //   I think this can be realized by referencing @import './xxx.scss' in the css file
              modules: {
                exportGlobals: true,
                localIdentName: "[path][name]__[local]--[hash:base64:5]",
                namedExport: true,
                exportLocalsConvention: "camelCaseOnly",
              },
            },
          }

webpack will throw an error, example:
@ ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[2].use[1]!./src/scss/style/name.css 5:0-137 8:26-59
@import './xxx.scss' in the css file , config -> importLoader is 0, It can be seen that this file has not been parsed by postcss-loader and sass-loader
@ ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[2].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[2].use[2]!./node_modules/sass-loader/dist/cjs.js!./src/scss/style/index.scss 4:0-134 6:26-59

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests