123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- 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;
|