From 7b2244efcd943f324d471a41a459be6a2d80215e Mon Sep 17 00:00:00 2001 From: Tony Air Date: Wed, 22 Jan 2020 16:49:07 +0700 Subject: [PATCH] Webpack Image compression, other improvements --- package.json | 7 +- webpack.config.js | 291 +++++++++++++++++++++++++++------------------- 2 files changed, 177 insertions(+), 121 deletions(-) diff --git a/package.json b/package.json index a5b0067..f09ec9a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@a2nt/ss-bootstrap-ui-webpack-boilerplate", - "version": "1.5.8", + "version": "1.5.9", "author": "Tony Air ", "license": "MIT", "description": "This UI Kit allows you to build Bootstrap 4 webapp with some extra UI features. It's easy to extend and easy to convert HTML templates to CMS templates.", @@ -86,6 +86,11 @@ "file-loader": "^1.1.5", "html-loader": "^0.5.5", "html-webpack-plugin": "^4.0.0-beta.11", + "imagemin-gifsicle": "^7.0.0", + "imagemin-jpegtran": "^6.0.0", + "imagemin-optipng": "^7.1.0", + "imagemin-svgo": "^7.0.0", + "imagemin-webpack": "^5.1.1", "lost": "^8.3.1", "material-design-color": "^2.3.2", "node-sass": "^4.13.0", diff --git a/webpack.config.js b/webpack.config.js index 0b896aa..a3eeebe 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,62 +6,94 @@ const webpack = require('webpack'); const path = require('path'); const filesystem = require('fs'); - const autoprefixer = require('autoprefixer'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin'); const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); +const ImageminPlugin = require('imagemin-webpack'); const plugins = [ new webpack.DefinePlugin({ 'process.env': { - 'NODE_ENV': JSON.stringify('production') - } + NODE_ENV: JSON.stringify('production'), + }, }), new webpack.LoaderOptionsPlugin({ minimize: COMPRESS, - debug: false + debug: false, }), new ExtractTextPlugin({ filename: 'css/[name].css', - allChunks: true + allChunks: true, }), /**/ new HtmlWebpackPlugin({ - template: './src/index.html' + template: './src/index.html', }), ]; if (COMPRESS) { - plugins.push(new OptimizeCssAssetsPlugin({ - //assetNameRegExp: /\.optimize\.css$/g, - cssProcessor: require('cssnano'), - cssProcessorPluginOptions: { - preset: ['default'], - }, - cssProcessorOptions: { - zindex: true, - cssDeclarationSorter: true, - reduceIdents: false, - mergeIdents: true, - mergeRules: true, - mergeLonghand: true, - discardUnused: true, - discardOverridden: true, - discardDuplicates: true, - discardComments: { - removeAll: true + plugins.push( + new OptimizeCssAssetsPlugin({ + //assetNameRegExp: /\.optimize\.css$/g, + cssProcessor: require('cssnano'), + cssProcessorPluginOptions: { + preset: ['default'], }, - }, - canPrint: true - })); + cssProcessorOptions: { + zindex: true, + cssDeclarationSorter: true, + reduceIdents: false, + mergeIdents: true, + mergeRules: true, + mergeLonghand: true, + discardUnused: true, + discardOverridden: true, + discardDuplicates: true, + discardComments: { + removeAll: true, + }, + }, + canPrint: true, + }), + ); + + plugins.push( + new ImageminPlugin({ + bail: false, // Ignore errors on corrupted images + cache: true, + filter: (source, sourcePath) => { + if (source.byteLength < 512000) { + return false; + } + + return true; + }, + imageminOptions: { + plugins: [ + ['gifsicle', { interlaced: true }], + ['jpegtran', { progressive: true }], + ['optipng', { optimizationLevel: 5 }], + [ + 'svgo', + { + plugins: [ + { + removeViewBox: false, + }, + ], + }, + ], + ], + }, + }), + ); } const includes = {}; -const _addAppFiles = (theme) => { - +const _addAppFiles = theme => { const dirPath = path.resolve(__dirname, theme); const themeName = path.basename(theme); @@ -75,7 +107,7 @@ const _addAppFiles = (theme) => { const dirPath = path.resolve(__dirname, dir); let results = []; - filesystem.readdirSync(dirPath).forEach((file) => { + filesystem.readdirSync(dirPath).forEach(file => { if (file.charAt(0) === '_') { return; } @@ -84,7 +116,9 @@ const _addAppFiles = (theme) => { const stat = filesystem.statSync(filePath); if (stat && stat.isDirectory() && includeSubFolders) { - results = results.concat(_getAllFilesFromFolder(filePath, includeSubFolders)); + results = results.concat( + _getAllFilesFromFolder(filePath, includeSubFolders), + ); } else { results.push(filePath); } @@ -97,7 +131,7 @@ const _addAppFiles = (theme) => { const typesJSPath = path.join(theme, 'js/types'); if (filesystem.existsSync(typesJSPath)) { const pageScripts = _getAllFilesFromFolder(typesJSPath, true); - pageScripts.forEach((file) => { + pageScripts.forEach(file => { includes[`app_${path.basename(file, '.js')}`] = file; }); } @@ -106,7 +140,7 @@ const _addAppFiles = (theme) => { const typesSCSSPath = path.join(theme, 'scss/types'); if (filesystem.existsSync(typesSCSSPath)) { const scssIncludes = _getAllFilesFromFolder(typesSCSSPath, true); - scssIncludes.forEach((file) => { + scssIncludes.forEach(file => { includes[`app_${path.basename(file, '.scss')}`] = file; }); } @@ -126,15 +160,16 @@ module.exports = { filename: path.join('js', '[name].js'), publicPath: path.resolve(__dirname, 'dist'), }, - devtool: (COMPRESS ? '' : 'source-map'), + devtool: COMPRESS ? '' : 'source-map', externals: { - 'jquery': 'jQuery', + jquery: 'jQuery', }, optimization: { namedModules: true, // NamedModulesPlugin() - splitChunks: { // CommonsChunkPlugin() + splitChunks: { + // CommonsChunkPlugin() name: 'vendor', - minChunks: 2 + minChunks: 2, }, noEmitOnErrors: true, // NoEmitOnErrorsPlugin concatenateModules: true, //ModuleConcatenationPlugin @@ -151,94 +186,110 @@ module.exports = { }, }, }), - ] + ], }, module: { - rules: [{ - test: /\.jsx?$/, - exclude: /node_modules/, - use: { - loader: 'babel-loader', - options: { - presets: [ - ['es2015', { - modules: false, - }], - ['stage-2'], - ], - plugins: [ - ['transform-react-jsx'], - ['react-hot-loader/babel'], - ], + rules: [ + { + test: /\.jsx?$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + presets: [ + [ + 'es2015', + { + modules: false, + }, + ], + ['stage-2'], + ], + plugins: [['transform-react-jsx'], ['react-hot-loader/babel']], + }, }, }, - }, { - test: /\.tsx?$/, - use: 'ts-loader', - exclude: /node_modules/, - }, { - test: /\.coffee?$/, - use: 'coffee-loader', - }, { - test: /\.worker\.js$/, - use: { - loader: 'worker-loader', + { + test: /\.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, }, - }, { - test: /\.s?css$/, - use: ExtractTextPlugin.extract({ - fallback: "style-loader", - use: [{ - loader: 'css-loader', - options: { - sourceMap: !COMPRESS - } - }, { - loader: 'postcss-loader', - options: { - sourceMap: !COMPRESS, - plugins: [ - autoprefixer() - ] - } - }, { - loader: 'resolve-url-loader' - }, { - loader: 'sass-loader', - options: { - sourceMap: !COMPRESS - } - }, ] - }) - }, { - test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, - use: [{ + { + test: /\.coffee?$/, + use: 'coffee-loader', + }, + { + test: /\.worker\.js$/, + use: { + loader: 'worker-loader', + }, + }, + { + test: /\.s?css$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: [ + { + loader: 'css-loader', + options: { + sourceMap: !COMPRESS, + }, + }, + { + loader: 'postcss-loader', + options: { + sourceMap: !COMPRESS, + plugins: [autoprefixer()], + }, + }, + { + loader: 'resolve-url-loader', + }, + { + loader: 'sass-loader', + options: { + sourceMap: !COMPRESS, + }, + }, + ], + }), + }, + { + test: /fontawesome([^.]+).(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'fonts/', + publicPath: '../fonts/', + }, + }, + ], + }, + { + test: /\.(ttf|otf|eot|svg|woff(2)?)$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'fonts/', + publicPath: '../fonts/', + }, + }, + ], + }, + { + test: /\.(png|jpg|jpeg|gif|svg)$/, loader: 'file-loader', options: { name: '[name].[ext]', - outputPath: 'fonts/', - publicPath: '../fonts/' - } - }] - }, { - test: /\.(ttf|otf|eot|svg|woff(2)?)$/, - use: [{ - loader: 'file-loader', - options: { - name: '[name].[ext]', - outputPath: 'fonts/', - publicPath: '../fonts/' - } - }] - }, { - test: /\.(png|jpg|jpeg|gif|svg)$/, - loader: 'file-loader', - options: { - name: '[name].[ext]', - outputPath: 'img/', - publicPath: '../img/' + outputPath: 'img/', + publicPath: '../img/', + }, }, - }, ], + ], }, resolve: { modules: [ @@ -246,8 +297,8 @@ module.exports = { path.resolve(__dirname, 'node_modules'), ], alias: { - 'jquery': require.resolve('jquery'), - 'jQuery': require.resolve('jquery'), + jquery: require.resolve('jquery'), + jQuery: require.resolve('jquery'), }, }, plugins: plugins, @@ -266,10 +317,10 @@ module.exports = { //watchContentBase: true, overlay: { warnings: true, - errors: true + errors: true, }, headers: { 'Access-Control-Allow-Origin': '*', - } + }, }, };