11

I am trying to figure out how to run postcss on my final output css file.

'strict';

const path = require('path');
const webpack = require('webpack');
const StatsPlugin = require('stats-webpack-plugin');

/* POSTCSS Optimizations of CSS files */
const clean = require('postcss-clean');
const colorMin = require('postcss-colormin');
const discardDuplicates = require('postcss-discard-duplicates');
const discardEmpty = require('postcss-discard-empty');
const mergeRules = require('postcss-merge-rules');
const mergeLonghand = require('postcss-merge-longhand');
const minifyFonts = require('postcss-minify-font-values');
const orderedValues = require('postcss-ordered-values');
const uniqueSelectors = require('postcss-unique-selectors');

/* EXTRACT CSS for optimization and parallel loading */
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: './src/index',
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js',
        chunkFilename: '[id].bundle.js',
        publicPath: '/dist/',
        soureMapFilename: '[file].map'
    },
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.NoErrorsPlugin(),
        new StatsPlugin('stats.json'),
        new ExtractTextPlugin('assets/css/[name].css?[hash]-[chunkhash]-[contenthash]-[name]', {
            disable: false,
            allChunks: true
        })
    ],
    node: {
        net: 'empty',
        tls: 'empty',
        dns: 'empty'
    },
    module: {
        loaders: [{
            test: /\.js$/,
            loaders: ['babel'],
            exclude: /node_modules/,
            include: __dirname
        },
        {
            test: /\.scss$/i,
            loader: ExtractTextPlugin.extract('style', ['css', 'postcss', 'sass'])
        },
        {
            test: /\.css$/,
            loader: ExtractTextPlugin.extract('style', ['css'])
        },
        {
            test: /\.(eot|woff|woff2|ttf|svg|png|jpg)$/,
            loader: 'url-loader?limit=30000&name=[name]-[hash].[ext]'
        }]
    },
    postcss() {
        return [mergeRules, mergeLonghand, colorMin, clean, discardEmpty,
                orderedValues, minifyFonts, uniqueSelectors, discardDuplicates];
    },
    sassLoader: {
        includePaths: [path.resolve(__dirname, './node_modules')]
    }
};

My current configuration works well at compiling all of the dependent SASS and taking that and the static CSS imports and extracting them using ExtractTextPlugin.

It also appears that I can run POSTCSS optimizations on chunks of the CSS, but not the final product. This means I can't get rid of duplicate CSS rules.

How do I run POSTCSS on the end-state CSS file AFTER sass-loader and extractTextPlugin have worked their magic?

nhavar
  • 198
  • 1
  • 8
  • You can move `postcss` loaders to `module.postLoaders` ( https://webpack.github.io/docs/configuration.html#module-preloaders-module-postloaders ) but I'm not sure that it will be work with `ExtractTextPlugin `. – Bob Sponge Mar 21 '16 at 06:40
  • Unfortunately it doesn't appear to work. I'm assuming because of the way the the loaders work, by the time I've gotten to the postLoader to execute the POSTCSS there's no longer any CSS left in the files to manipulate and no way to point postcss to the newly merged CSS file/files in the dist. I don't think loaders can just point to any arbitrary file on the filesystem, I think it has to be connected to a JS entry point. – nhavar Mar 21 '16 at 14:27

2 Answers2

9

I was having problems to make a similar setup work with ExtractTextPlugin and my problem was on how I was using the ExtractTextPlugin plugin.

I'm only using it for production builds and this is what worked for me:

module: {
    loaders: [
        {   // styles
            test: /\.scss$/,
            include: [ path.join(__dirname, 'source/styles') ],
            loader: ExtractTextPlugin.extract('style', ['css', 'postcss', 'sass'])
        }
    ]
},

Note the Array for ['css', 'postcss', 'sass']. That's the part that I was missing. This array will resolve first and then run style that will be finally extracted by the plugin.

And, on the array of plugins I'm using new ExtractTextPlugin('styles-[chunkhash].css').

rafaelbiten
  • 6,074
  • 2
  • 31
  • 36
  • I have almost that exact code (excluding the include line) already listed above in my example, it and almost any variation of it has not helped. I've tried both separated and piped examples. The extract works fine and always has, but there's heavy duplication – nhavar Jun 02 '16 at 16:57
  • I just had a crazy idea that 'might' help. What happens if you try something like: `loader: ExtractTextPlugin.extract('style', 'postcss', ['css', 'postcss', 'sass'])`. Note the post css outside the array but before (right to left) the style task. – rafaelbiten Jun 02 '16 at 21:23
0

Since ExtractTextPlugin doesn't currently support an "onComplete" callback or similar, you could use WebpackShellPlugin.

Set up a script that runs the required postcss plugin and execute your script in onBuildExit to process your compiled CSS.

Lochlan
  • 101
  • 6