Spaces:
Sleeping
Sleeping
const cssnano = require('cssnano'); | |
const postcss = require('postcss'); | |
/** | |
* Optimize cssnano plugin | |
* | |
* @param {Object} options | |
*/ | |
function OptimizeCssnanoPlugin(options) { | |
this.options = Object.assign({ | |
sourceMap: false, | |
cssnanoOptions: { | |
preset: 'default', | |
}, | |
}, options); | |
if (this.options.sourceMap) { | |
this.options.sourceMap = Object.assign( | |
{inline: false}, | |
this.options.sourceMap || {}); | |
} | |
} | |
OptimizeCssnanoPlugin.prototype.apply = function(compiler) { | |
const self = this; | |
compiler.hooks.emit.tapAsync('OptimizeCssnanoPlugin', | |
function(compilation, callback) { | |
// Search for CSS assets | |
const assetsNames = Object.keys(compilation.assets) | |
.filter((assetName) => { | |
return /\.css$/i.test(assetName); | |
}); | |
let hasErrors = false; | |
const promises = []; | |
// Generate promises for each minification | |
assetsNames.forEach((assetName) => { | |
// Original CSS | |
const asset = compilation.assets[assetName]; | |
const originalCss = asset.source(); | |
// Options for particalar cssnano call | |
const postCssOptions = { | |
from: assetName, | |
to: assetName, | |
map: false, | |
}; | |
const cssnanoOptions = self.options.cssnanoOptions; | |
// Extract or remove previous map | |
const mapName = assetName + '.map'; | |
if (self.options.sourceMap) { | |
// Use previous map if exist... | |
if (compilation.assets[mapName]) { | |
const mapObject = JSON.parse(compilation.assets[mapName].source()); | |
// ... and not empty | |
if (mapObject.sources.length > 0 || mapObject.mappings.length > 0) { | |
postCssOptions.map = Object.assign({ | |
prev: compilation.assets[mapName].source(), | |
}, self.options.sourceMap); | |
} else { | |
postCssOptions.map = Object.assign({}, self.options.sourceMap); | |
} | |
} | |
} else { | |
delete compilation.assets[mapName]; | |
} | |
// Run minification | |
const promise = postcss([cssnano(cssnanoOptions)]) | |
.process(originalCss, postCssOptions) | |
.then((result) => { | |
if (hasErrors) { | |
return; | |
} | |
// Extract CSS back to assets | |
const processedCss = result.css; | |
compilation.assets[assetName] = { | |
source: function() { | |
return processedCss; | |
}, | |
size: function() { | |
return processedCss.length; | |
}, | |
}; | |
// Extract map back to assets | |
if (result.map) { | |
const processedMap = result.map.toString(); | |
compilation.assets[mapName] = { | |
source: function() { | |
return processedMap; | |
}, | |
size: function() { | |
return processedMap.length; | |
}, | |
}; | |
} | |
} | |
).catch(function(err) { | |
hasErrors = true; | |
throw new Error('CSS minification error: ' + err.message + | |
'. File: ' + assetName); | |
} | |
); | |
promises.push(promise); | |
}); | |
Promise.all(promises) | |
.then(function() { | |
callback(); | |
}) | |
.catch(callback); | |
}); | |
}; | |
module.exports = OptimizeCssnanoPlugin; | |