From a82d580501815803d7d4e60ea7a2de43cda79636 Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Tue, 27 Aug 2019 14:13:11 +0800 Subject: [PATCH] feat(mp): optimize-css #697 --- packages/vue-cli-plugin-uni/lib/mp.js | 15 ++- .../optimize-cssnano-plugin/LICENSE | 21 +++ .../optimize-cssnano-plugin/README.md | 40 ++++++ .../optimize-cssnano-plugin/index.js | 121 ++++++++++++++++++ .../optimize-cssnano-plugin/package.json | 58 +++++++++ 5 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/LICENSE create mode 100644 packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/README.md create mode 100644 packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/index.js create mode 100644 packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/package.json diff --git a/packages/vue-cli-plugin-uni/lib/mp.js b/packages/vue-cli-plugin-uni/lib/mp.js index b48172316..5a5d7e25b 100644 --- a/packages/vue-cli-plugin-uni/lib/mp.js +++ b/packages/vue-cli-plugin-uni/lib/mp.js @@ -172,15 +172,24 @@ module.exports = { .uses .delete('cache-loader') + const styleExt = getPlatformExts().style + webpackConfig.plugin('extract-css') .init((Plugin, args) => new Plugin({ - filename: '[name]' + getPlatformExts().style + filename: '[name]' + styleExt })) - if (process.env.NODE_ENV === 'production') { + if ( + process.env.NODE_ENV === 'production' && + process.env.UNI_PLATFORM !== 'app-plus' + ) { + const OptimizeCssnanoPlugin = require('../packages/@intervolga/optimize-cssnano-plugin/index.js') webpackConfig.plugin('optimize-css') - .init((Plugin, args) => new Plugin({ + .init((Plugin, args) => new OptimizeCssnanoPlugin({ sourceMap: false, + filter (assetName) { + return path.extname(assetName) === styleExt + }, cssnanoOptions: { preset: [ 'default', diff --git a/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/LICENSE b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/LICENSE new file mode 100644 index 000000000..b1ecb1eff --- /dev/null +++ b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 INTERVOLGA.RU + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/README.md b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/README.md new file mode 100644 index 000000000..da78735cb --- /dev/null +++ b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/README.md @@ -0,0 +1,40 @@ +# optimize-cssnano-plugin [![Build Status](https://travis-ci.org/intervolga/optimize-cssnano-plugin.svg?branch=master)](https://travis-ci.org/intervolga/optimize-cssnano-plugin) + +It will search for CSS assets during the Webpack build and minimize it with [cssnano](http://github.com/ben-eb/cssnano). +Solves [extract-text-webpack-plugin](http://github.com/webpack/extract-text-webpack-plugin) CSS duplication problem. + +Just like [optimize-css-assets-webpack-plugin](http://github.com/NMFR/optimize-css-assets-webpack-plugin) but more accurate with source maps. + +## Installation: + +Using npm: +```shell +$ npm install --save-dev @intervolga/optimize-cssnano-plugin +``` + +## Configuration: + +``` javascript +const OptimizeCssnanoPlugin = require('@intervolga/optimize-cssnano-plugin'); +module.exports = { + module: { + loaders: [ + { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") } + ] + }, + plugins: [ + new ExtractTextPlugin("styles.css"), + + new OptimizeCssnanoPlugin({ + sourceMap: nextSourceMap, + cssnanoOptions: { + preset: ['default', { + discardComments: { + removeAll: true, + }, + }], + }, + }), + ] +} +``` \ No newline at end of file diff --git a/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/index.js b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/index.js new file mode 100644 index 000000000..f5385ccb7 --- /dev/null +++ b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/index.js @@ -0,0 +1,121 @@ +const cssnano = require('cssnano'); +const postcss = require('postcss'); + +/** + * Optimize cssnano plugin + * + * @param {Object} options + */ +function OptimizeCssnanoPlugin(options) { + this.options = Object.assign({ + sourceMap: false, + filter(assetName){// fixed by xxxxxx custom filter + return /\.css$/i.test(assetName); + }, + 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(self.options.filter);// fixed by xxxxxx custom filter + 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; diff --git a/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/package.json b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/package.json new file mode 100644 index 000000000..17ce0dfbc --- /dev/null +++ b/packages/vue-cli-plugin-uni/packages/@intervolga/optimize-cssnano-plugin/package.json @@ -0,0 +1,58 @@ +{ + "name": "@intervolga/optimize-cssnano-plugin", + "version": "1.0.6", + "description": "WebPack 2+ plugin for CSS minification after ExtractTextPluging", + "main": "index.js", + "scripts": { + "mocha": "mocha --ui tdd test/", + "lint": "eslint index.js lib test/index.js test/helpers", + "test": "npm run lint && npm run mocha" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/intervolga/optimize-cssnano-plugin" + }, + "keywords": [ + "html", + "index", + "webpack", + "loader" + ], + "author": "Shkarupa Alex", + "license": "MIT", + "bugs": { + "url": "https://github.com/intervolga/optimize-cssnano-plugin/issues" + }, + "homepage": "https://github.com/intervolga/optimize-cssnano-plugin#readme", + "peerDependencies": { + "webpack": "^4.0.0" + }, + "dependencies": { + "cssnano": "^4.0.0", + "cssnano-preset-default": "^4.0.0", + "postcss": "^7.0.0" + }, + "devDependencies": { + "autoprefixer": "^8.6.5", + "css-loader": "^0.28.11", + "eslint": "^4.19.1", + "eslint-config-google": "^0.8.0", + "eslint-plugin-promise": "^3.8.0", + "eslint-plugin-standard": "^3.1.0", + "expect.js": "^0.3.1", + "extract-text-webpack-plugin": "^4.0.0-beta.0", + "fs-extra": "^5.0.0", + "mocha": "^5.2.0", + "node-sass": "^4.9.2", + "postcss-loader": "^2.1.6", + "sass-loader": "^6.0.7", + "style-loader": "^0.20.3", + "webpack": "^4.16.1" + }, + "files": [ + "lib", + "index.js", + "README", + "LICENSE" + ] +} -- GitLab