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