Skip to content

Instantly share code, notes, and snippets.

@mistakster
Last active December 30, 2016 06:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mistakster/d655d0199a4acf4fccd5e61a0ca6cb17 to your computer and use it in GitHub Desktop.
Save mistakster/d655d0199a4acf4fccd5e61a0ca6cb17 to your computer and use it in GitHub Desktop.
A webpack plugin to process generated assets with PostCSS pipeline. Also, there is an npm version — https://github.com/mistakster/postcss-pipeline-webpack-plugin
const RawSource = require('webpack-sources').RawSource;
const postcss = require('postcss');
const MASK = /\.css$/;
/**
* @param {Function} options.predicate is a function invoked per CSS file
* @param {String} options.suffix is a string attached to the new file
* @param {Array} options.pipeline is a list of PostCSS plugins
* @param {Object} options.map is a PostCSS source maps configuration
*/
function PostCssPipelineWebpackPlugin(options) {
this._options = Object.assign({
predicate: () => true,
suffix: 'processed',
pipeline: []
}, options);
}
PostCssPipelineWebpackPlugin.prototype.apply = function (compiler) {
compiler.plugin('emit', (compilation, callback) => (
this.generate(compilation)
.then(() => callback())
.catch(err => callback(err))
));
};
PostCssPipelineWebpackPlugin.prototype.generate = function (compilation) {
const _options = this._options;
const predicate = _options.predicate;
const suffix = _options.suffix;
const pipeline = _options.pipeline;
const map = _options.map;
return Promise
.all(
Object.keys(compilation.assets)
.filter(k => (
MASK.test(k) && predicate(k)
))
.map(name => {
const prevMap = compilation.assets[name + '.map'];
return {
from: name,
to: suffix ? name.replace(MASK, '.' + suffix + '.css') : name,
map: prevMap ? Object.assign({prev: prevMap.source()}, map) : map
}
})
.map(options => (
postcss(pipeline)
.process(compilation.assets[options.from].source(), options)
.then(result => {
compilation.assets[options.to] = new RawSource(result.css);
if (result.map) {
compilation.assets[options.to + '.map'] = new RawSource(result.map.toString());
}
})
))
)
.then(() => compilation);
};
module.exports = PostCssPipelineWebpackPlugin;
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PostCssPipelineWebpackPlugin = require('./postcss-pipeline-webpack-plugin');
const criticalSplit = require('postcss-critical-split');
const csso = require('postcss-csso');
module.exports = {
entry: './src/index.css',
output: {
path: path.resolve('./dest/'),
filename: '[name].js'
},
module: {
loaders: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'css?sourceMap&-autoprefixer')
}
]
},
plugins: [
new ExtractTextPlugin('styles.css'),
new PostCssPipelineWebpackPlugin({
suffix: 'critical',
pipeline: [
criticalSplit({
output: criticalSplit.output_types.CRITICAL_CSS
})
]
}),
new PostCssPipelineWebpackPlugin({
suffix: 'min',
pipeline: [
csso({
restructure: false
})
]
})
]
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment