Search code examples
webpackpostcsssass-loadercssnextpostcss-loader

How do I get postcss-loader, postcss-cssnext and sass-loader to work together in webpack?


This is my Webpack configs for scss/css files.

...
{
    test: /\.s?css$/,
    use: [
      'style-loader',
      { loader: 'css-loader', options: { importLoaders: 2 } },
      {
        loader: 'postcss-loader',
        options: {
          ident: 'postcss',
          plugins: loader => [
            require('postcss-import')({ root: loader.resourcePath }),
            require('cssnano')(),
            require('postcss-cssnext')(),
          ]
        }
      },
      'sass-loader',
    ]
}
...

The problem is that when I use cssnext functions like gray(100), the output CSS file has an empty value where the function was placed. I would like to know what I did wrong here.

i.e. background-color: gray(100); outputs to background-color: ;

I'm new to postcss so I don't really know how it works or how to configure it properly as of yet.


Solution

  • For your exact problem, the cssnext functions, you must put cssnano after postcss-cssnext, like below:

    ...
    {
        test: /\.s?css$/,
        use: [
          'style-loader',
          { loader: 'css-loader', options: { importLoaders: 2 } },
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: loader => [
                require('postcss-import')({ root: loader.resourcePath }),
                require('postcss-cssnext')(),
                require('cssnano')(),
              ]
            }
          },
          'sass-loader',
        ]
    }
    ...
    

    BUT I don't know, why did you use sass-loader? when you have postcss in your project.

    Actually PostCSS can do all jobs like sass even better, it is up to you for syntax style, I suggest see THIS REPO, it has complete configuration of PostCSS on Webpack, also in this repo, the SCSS syntax is used.

    For clearness I write a part of configuration below:

    rules: [
        {
            test: /\.(js|jsx)$/,
            exclude: /(node_modules\/)/,
            use: [
                {
                    loader: 'babel-loader',
                }
            ]
        },
        {
            test: /\.pcss$/,
            use: ExtractTextPlugin.extract({
                fallback: 'style-loader',
                use: [
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true,
                            importLoaders: 1,
                            localIdentName: '[hash:base64:10]',
                            sourceMap: false,
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            config: {
                                path: `${__dirname}/../postcss/postcss.config.js`,
                            }
                        }
                    }
                ]
            })
        }
    ]
    

    Even I use *.pcss instead of *.scss, *.sass or *.css, it is just for consistency and no different.

    The PostCSS configuration is in separated file, it is:

    module.exports = {
        ident: 'postcss',
        syntax: 'postcss-scss',
        map: {
            'inline': true,
        },
        plugins: {
            'postcss-partial-import': {
                'prefix': '_',
                'extension': '.pcss',
                'glob': false,
                'path': ['./../src/styles']
            },
            'postcss-nested-ancestors': {},
            'postcss-apply': {},
            'postcss-custom-properties': {},
            'postcss-nested': {},
            'postcss-cssnext': {
                'features': {
                    'nesting': false
                },
                'warnForDuplicates': false
            },
            'postcss-extend': {},
            'css-mqpacker': {
                'sort': true
            },
            'autoprefixer': {
                'browsers': ['last 15 versions']
            },
        }
    };
    

    Absolutely cssnext works well, I used color() function and it works well.