Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

How to properly use multiple loaders with this plugin? #330

Closed
xeho91 opened this issue Jan 10, 2017 · 34 comments
Closed

How to properly use multiple loaders with this plugin? #330

xeho91 opened this issue Jan 10, 2017 · 34 comments

Comments

@xeho91
Copy link

xeho91 commented Jan 10, 2017

Hello!

I am using webpack@2.2.0-rc3
and extract-text-webpack-plugin@2.0.0-beta.4

I am trying to configure this plugin to extract multiple loaders (start with sass, end with css).
The piece of configuration code in my webpack.config.js looks like this:

...
    module: {
        rules: [
            ...
            // Stylesheets
            {
                test: /\.scss$/,
                include: path.resolve(__dirname, 'src'),
                use: ExtractTextPlugin.extract([{
                    fallbackLoader: 'style-loader',
                    loader: 'css-loader!postcss-loader!sass-loader',
                }]),
            },
            ...
        ],
    },
    ...
    plugins: [
        ...
        new ExtractTextPlugin('./stylesheets/[name].css'),
        ...
    ],
...

I am getting errors output in terminal. The first one looks like this and the rest are similar to this one:

ERROR in ./styles.scss
Module parse failed: C:\Users...\node_modules\extract-text-webpack-plugin\loader.js?{"omit":0,"remove":true}!css-loader!postcss-loader!sass-loader!C:\Users...\src\styles.scss Unexcepted character @ (1:0)
You may need an appropriate loader to handle this file type.
| @import './fonts/fonts';
|
| body,
@ ./index.js 7:0-24

I tried several possible ways to make it work. Everytime the same error output.

After some hours of struggling with it I found the only setup which worked so far:

...
            {
                test: /\.scss$/,
                include: path.resolve(__dirname, 'src'),
                use: [
                    ExtractTextPlugin.extract([{ fallbackLoader: 'style-loader', loader: 'css-loader' }]),
                    'css-loader',
                    'postcss-loader',
                    'sass-loader',
                ],
            },
...

However as you could probably have guessed, the result isn't what I excepted to have.
It bundles every stylesheets in folder to one file, which makes a heavy css file from it.

I've followed documentation, tried setup from webpack version 1 and nothing worked so far.
I believe I could have missed something, since I am still a beginner that's why I seek for a help here and I hope to get an advise in case I missed something important.
Also I found out that on gitter webpack chat someone was struggling with same problem as me and got same error output, so naturally I started to think that it could be a bug and I decided to report it.

@frederikprijck
Copy link
Contributor

frederikprijck commented Jan 10, 2017

Linking my related SO (it's using LESS tho): http://stackoverflow.com/questions/41554983/using-extracttextplugin-with-webpack-2-2-0-rc3-throws-errors

My SO question includes a repro sample to be able to investigate this:

https://dl.dropboxusercontent.com/u/87239305/webpack-less.zip

Steps to reproduce:

npm install
node_modules\ .bin\webpack.cmd --config conf\webpack.conf.js

I've also added a second config file which is working, without ExtractTextPlugin:

node_modules\ .bin\webpack.cmd --config conf\webpack.conf2.js

@toddbluhm
Copy link

Running into this same issue as well. Same setup as @frederikprijck just without the post-css loader.

@miljan-aleksic
Copy link

I also am having those issues trying to load less files.

@415DomSmith
Copy link

I was running in to a similar issue when moving to webpack 2 from 1, and I found:

http://stackoverflow.com/questions/41021614/webpack-2-css-modules-support

Keeping my css-loader line the same as what I had in webpack 1 worked. My rule now looks like:

...
    {
        test: /\.(scss)$/,
        include: [path.join(__dirname, 'src')],
        loader: ExtractTextPlugin.extract({
          fallbackLoader: 'style-loader',
          loader: [
            'css-loader?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
            'sass-loader'
          ]
        })
     }
...

@AlexanderTserkovniy
Copy link

@415DomSmith Thanks a lot! You saved me!

@tlrobinson
Copy link

@415DomSmith's solution worked for me. It appears ExtractTextPlugin doesn't yet support the Webpack 2 { loader: "loader-name", options: { ... } } syntax like:

    {
        test: /\.(scss)$/,
        include: [path.join(__dirname, 'src')],
        loader: ExtractTextPlugin.extract({
          fallbackLoader: 'style-loader',
          loader: [
            { loader: 'css-loader', options: { modules: true, importLoaders: 1, localIdentName: "[path]___[name]__[local]___[hash:base64:5]" },
            { loader: 'sass-loader' }
          ]
        })
     }

It might also make sense to change/alias the loader option to use like in Webpack 2.

@dylanjha
Copy link

dylanjha commented Jan 17, 2017

passing in options into the sass-loader through query params solved this for me:

modules: {
  rules: [
     {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract([
          'css-loader', 'sass-loader?includePaths=./node_modules/compass-mixins/lib'
        ])
      }
  ]
}

webpack 2.2.0-rc.6
extract-text-webpack-plugin 2.1.0-beta.25

@abierbaum
Copy link

I have no idea why, but @dylanjha 's format above with no fallback loader was the only way I could get it to work. Definitely some rough edges here that need fixed up. Spent half a day of trial and error on this one. :(

@jaydenseric
Copy link

This plugin doesn't support Webpack v2 yet, here is the milestone.

@frederikprijck
Copy link
Contributor

frederikprijck commented Jan 19, 2017

@jaydenseric That's not correct. The readme clearly says:

extract text plugin for webpack 2

The API has changed since version 1. For the webpack 1 version, see the README in the webpack-1 branch.

@TheLarkInn confirmed it was a problem with ExtractTextPlugin and should have been fixed with the latest release: https://github.com/webpack/extract-text-webpack-plugin/releases/tag/v2.0.0-beta.5 (I still have to verify this myself tho.)

Link to the twitter conversation with him regarding this issue: https://twitter.com/TheLarkInn/status/818868861000962048

@frederikprijck
Copy link
Contributor

frederikprijck commented Jan 19, 2017

I verified my reproduce app mentioned above (#330 (comment)) is working when upgrading ETP to beta5 using the following syntax:

{ test: /\.(css|less)$/, loader: ExtractTextPlugin.extract(["css-loader", "postcss-loader", "less-loader"]) }

Aswell as using the following syntax

{ 
    test: /\.(css|less)$/, 
    loader: ExtractTextPlugin.extract({
        fallbackLoader: "style-loader",
        loader: ["css-loader", "postcss-loader", "less-loader"]
    }) 
},

This is not 100% according to the readme, but that should be fixed once #341 get's merged.

@xeho91 can you verify this works for u ?

@cascornelissen
Copy link

@frederikprijck, do you have an example for when we want to use plugins as well? Say I want to use autoprefixer with postcss-loader, any idea on how to set that up?

@frederikprijck
Copy link
Contributor

frederikprijck commented Jan 19, 2017

@cascornelissen the postcss-loader is used in my syntax above.

you also have to add this to the plugins section IIRC:

new LoaderOptionsPlugin({
    debug: true,
    options: {
        postcss: {
            plugins: () =>[autoprefixer]
        }
    }
})

It's also in my reproduction example #330 (comment)

@cascornelissen
Copy link

cascornelissen commented Jan 19, 2017

Ah, didn't know about the LoaderOptionsPlugin. I'll see if that works. Is passing a configuration object to autoprefixer also supported this way?

Edit: seems like you can just

postcss: {
    plugins: function() {
        return [
            autoprefixer({
                browsers: [
                    'last 2 version',
                    'ie >= 9',
                    'ios 8'
                ]
            })
        ];
    }
}

@trainiac
Copy link

With regards to postcss plugins specifically. You can also provide a postcss.config.js file at your project root that get's picked up by postcss-loader.

// postcss.config.js
module.exports = () => {
  const pluginConfigs = {
    'import': {
      path: ['somepath']
    }
  }

  const plugins = [{
    name: 'import',
    mod: require('postcss-import')
  }, {
    name: 'mixins',
    mod: require('postcss-mixins')

  }, {
    name: 'simple-vars',
    mod: require('postcss-simple-vars')

  }, {
    name: 'color-function',
    mod: require('postcss-color-function')

  }, {
    name: 'autoprefixer',
    mod: require('autoprefixer')
  }]

  return {
    syntax: 'postcss-scss',
    plugins: plugins.map(plugin => {
      if (plugin.name in pluginConfigs) {
        return plugin.mod(pluginConfigs[plugin.name])
      }

      return plugin.mod()
    })
  }
}

https://github.com/michael-ciniawsky/postcss-load-config

@kb3eua
Copy link

kb3eua commented Jan 20, 2017

I got it to work in webpack 2.0 with the following syntax:

{
  test: /\.s[ac]ss$/,
  use: [
    'to-string-loader',
    ExtractTextPlugin.extract({
      fallbackLoader: 'style-loader',
      loader: [
          'css-loader?-url&sourceMap',
          'postcss-loader',
          'sass-loader?sourceMap'
      ]
    })
  ],
  exclude: [
    root('node_modules')
  ]
}

notice I had to add the "to-string-loader" to get it to work.

@jaydenseric
Copy link

I got it to work with Webpack 2, PostCSS (with postcss-import, postcss-cssnext and postcss-reporter plugins) and sourcemaps:

@Ephem
Copy link

Ephem commented Jan 24, 2017

I wish I would have read @415DomSmith comment more carefully earlier on, would have saved me a few hours. I had the syntax inside of the ExtractTextPlugin.extract({ ... }) correct, but do note that you have to use loader: and not use: in the outer webpack-config as well.

Just to clarify, this does NOT work:

{
  test: /\.s[ac]ss$/,
  use: ExtractTextPlugin.extract({
    fallbackLoader: 'style-loader',
    loader: ['css-loader', 'sass-loader']
  })
}

This DOES work:

{
  test: /\.s[ac]ss$/,
  loader: ExtractTextPlugin.extract({
    fallbackLoader: 'style-loader',
    loader: ['css-loader', 'sass-loader']
  })
}

@kb3eua If you change use to loader in your example you should be able to remove the to-string-loader.

As I understand it ExtractTextPlugin.extract takes the options and returns a string based on the old loader!loader-2-syntax. I guess this needs to return an array with the loaders instead to work with use:? This however would break the current way of using it with loader:. Not sure what the best way forward would be with this, but the readme could probably be clarified in the meantime. :)

@frederikprijck
Copy link
Contributor

frederikprijck commented Jan 24, 2017

Nice catch @Ephem .

I've modified my reproduction sample (webpack-less.zip) and It idd fails when using use. Replacing use with loaders works fine.

Monkeypatching PR #343 (as mentioned by @Ephem below) solved the problem. So I'm excited to see #343 getting merged in!

@Ephem
Copy link

Ephem commented Jan 24, 2017

Returning an array instead of a string so that use: works is actually what PR #343 does and luckily this does NOT break loader: in Webpack 2. In Webpack 1 loader: only works with a string, but I tried it out in Webpack 2 and loader: works fine with arrays there.

@bebraw bebraw added this to the Webpack 2 release milestone Jan 28, 2017
@bebraw
Copy link
Contributor

bebraw commented Jan 28, 2017

@xeho91 Can you update to rc0? Please note that you have to extract with use, not loader. Let me know how it goes.

@bebraw
Copy link
Contributor

bebraw commented Jan 31, 2017

@xeho91 Any news on this? This is a blocking final release. A standalone project to study would be ideal. Note that loader: format should work too. There's rc2 available now.

@frederikprijck
Copy link
Contributor

@bebraw To me it's working. But well, I didn't file the issue so I guess that doesn't matter. But I did solve my reproduction sample mentioned previously (#330 (comment)).

To summarize, I'm succesfully using the following versions:

  • webpack 2.2.0 (final)
  • extract-text-webpack-plugin: 2.0.0-rc.1

Together with the following configuration:

{
    test: /\.(css|less)$/,
    use: ExtractTextPlugin.extract({
        fallbackLoader: 'style-loader',
        loader: ['css-loader', 'postcss-loader', 'less-loader']
    })
}

and

plugins: [new ExtractTextPlugin('index-[contenthash].css')]

@bebraw
Copy link
Contributor

bebraw commented Jan 31, 2017

@frederikprijck Ok, excellent to hear. Often it's hard to work with issues like this as the information tends to be partial (not much to work with), but still cool. 👍

@nryoung
Copy link

nryoung commented Feb 10, 2017

I have tried multiple variations to get chained loaders to get to work with this plugin. I have tried all the examples in this thread and nothing seems to work.

  • webpack 2.2.0
  • extract-text-webpack-plugin: 2.0.0-rc.3

here is my simple configuration:

               test: /\.scss$/,
                use: ExtractTextPlugin.extract({
                    loader: [
                        'css-loader',
                        'resolve-url-loader',
                        'sass-loader?sourceMap=true'
                    ]
                })
            },

with plugins looking like:

 new ExtractTextPlugin('[name].[contenthash].css')

I execute webpack and it seems to compile successfully, but the css file is never emitted. There is no error message or anything that points me in the right direction.

@bebraw
Copy link
Contributor

bebraw commented Feb 10, 2017

@nryoung I would need a project to study to say anything concrete. Based on your description alone I can't see how you refer to CSS in your code.

@dylanjha
Copy link

@nryoung with this bit of code it's difficult to tell what the issue is. Are you using import in your entry file or any of the files that get loaded? It would probably be most beneficial to you to post a question on stack overflow with a complete example.

@nryoung
Copy link

nryoung commented Feb 10, 2017

@bebraw @dylanjha Thanks for the replies. I went back and looked at my entry point file and realized it was basically a global include for all of my other sass modules. I added this to plugins and it worked:

new ExtractTextPlugin({
  filename: '[name].[contenthash].css',
  allChunks: true
)

Notice the allChunks: true, this allowed ExtractTextPlugin to bundle all of the includes in the entry point .scss file.

@xeho91
Copy link
Author

xeho91 commented Feb 12, 2017

@bebraw

Sorry, I was away for a few weeks.

I'm currently using following versions:
"extract-text-webpack-plugin": "^2.0.0-beta.5",
"webpack": "^2.2.0-rc.4","webpack": "^2.2.0-rc.4".
(I know I need to update, but I'm checking the older versions just in case).

and the code for this plugin I've got right now (sorry, I don't have the older - the one which was used to report this issue):

const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = function extractCSS(paths, env) {
    return {
        module: {
            rules: [
                // Extract CSS during build
                {
                    test: /\.scss$/,
                    include: paths,
                    exclude: /node_modules/,
                    loader: ExtractTextPlugin.extract({
                        fallbackLoader: 'style-loader',
                        loader: [
                            {
                                loader: 'css-loader',
                                query: {
                                    sourceMap: (env === 'development'),
                                },
                            },
                            'postcss-loader',
                            {
                                loader: 'sass-loader',
                                query: {
                                    sourceMap: (env === 'development'),
                                    sourceMapContents: (env === 'development'),
                                },
                            },
                        ],
                    }),
                },
            ],
        },

        plugins: [
            new ExtractTextPlugin('stylesheets/[name].css'),
        ],
    };
};

And it works perfectly.

However using 'use' as mentioned before like this:

...
use: ExtractTextPlugin.extract({
...

didn't work.

@bebraw
Copy link
Contributor

bebraw commented Feb 12, 2017

loader and use should work the same. Thanks for confirming it works now. Time to close.

@bebraw bebraw closed this as completed Feb 12, 2017
@jy95
Copy link

jy95 commented May 8, 2017

Not working for me :

{
      test: /\.(scss|sass)$/,
	  loader: ExtractTextPlugin.extract(scssLoader),
      include: [__dirname]
    }
...
plugins: [
  	new ExtractTextPlugin("app.bundle.css")
  ],

My package.json : https://gist.github.com/jy95/99377c113252e6baaa23087abe859814
My webpack.config.js : https://gist.github.com/jy95/e2359fdbc3c5a73c3d2430a9c61f78ad

Any idea ? I become mad with this bug for hours

@vadimshvetsov
Copy link

It's really working with use instead loader I want to expand @bebraw closing comment with an example with some:

Packages: webpack - 3.5.6, extract-text-webpack-plugin - 3.0.0.

module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            'css-loader',
            {
              loader: 'postcss-loader',
              options: {
                plugins: () => [
                  Autoprefixer, // Imported at the top of the file
                ],
              },
            },
          ],
        }),
      },
    ],
},

Also I've tested this with code splitting and webpack pushes all the css imports to the style tag as expected.

@adrian-moisa
Copy link

adrian-moisa commented Jan 12, 2018

For webpack 3 this fixed the issue:

{
    test: /\.scss$/,
    use: [
        'to-string-loader', 
        ...ExtractTextPlugin.extract({
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
        })
    ],
    exclude: /node_modules/
},

@yairEO
Copy link

yairEO commented Apr 7, 2019

Apparently for Webpack v4 you need to switch to mini-css-extract-plugin

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

No branches or pull requests