diff --git a/config/webpack.prod.config.js b/config/webpack.prod.config.js index c72585ed2..6a53ad13e 100644 --- a/config/webpack.prod.config.js +++ b/config/webpack.prod.config.js @@ -14,6 +14,10 @@ const path = require('path'); const PostCssAutoprefixerPlugin = require('autoprefixer'); const PostCssRTLCSS = require('postcss-rtlcss'); +// Reduce CSS file size by ~70% +const { PurgeCSSPlugin } = require('purgecss-webpack-plugin') +const glob = require('glob') + const HtmlWebpackNewRelicPlugin = require('../lib/plugins/html-webpack-new-relic-plugin'); const commonConfig = require('./webpack.common.config'); const presets = require('../lib/presets'); @@ -23,6 +27,10 @@ dotenv.config({ path: path.resolve(process.cwd(), '.env'), }); +const PATHS = { + src: path.join(__dirname, 'src') +} + const extraPlugins = []; if (process.env.ENABLE_NEW_RELIC !== 'false') { // Enable NewRelic logging only if the account ID is properly defined @@ -183,6 +191,13 @@ module.exports = merge(commonConfig, { new MiniCssExtractPlugin({ filename: '[name].[chunkhash].css', }), + + // The recommend usage by official docs + // https://purgecss.com/getting-started.html + new PurgeCSSPlugin({ + paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }) + }), + // Generates an HTML file in the output directory. new HtmlWebpackPlugin({ inject: true, // Appends script tags linking to the webpack bundles at the end of the body diff --git a/package-lock.json b/package-lock.json index fecde1814..a38ba3162 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,6 +68,7 @@ "@babel/preset-typescript": "^7.18.6", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.11", + "purgecss-webpack-plugin": "^5.0.0", "typescript": "^4.8.2" }, "peerDependencies": { @@ -15021,6 +15022,83 @@ "node": ">=6" } }, + "node_modules/purgecss": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz", + "integrity": "sha512-RAnuxrGuVyLLTr8uMbKaxDRGWMgK5CCYDfRyUNNcaz5P3kGgD2b7ymQGYEyo2ST7Tl/ScwFgf5l3slKMxHSbrw==", + "dev": true, + "dependencies": { + "commander": "^9.0.0", + "glob": "^8.0.3", + "postcss": "^8.4.4", + "postcss-selector-parser": "^6.0.7" + }, + "bin": { + "purgecss": "bin/purgecss.js" + } + }, + "node_modules/purgecss-webpack-plugin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/purgecss-webpack-plugin/-/purgecss-webpack-plugin-5.0.0.tgz", + "integrity": "sha512-u8J0SxXdMekVOsbyV6hK1x6LlzJbE/mrC+UbNX0mLz5Jo/Jle8o4S3IFIRCgdzGdxtOBPCKW+UNgaULfKVmx2w==", + "dev": true, + "dependencies": { + "purgecss": "^5.0.0", + "webpack": ">=5.0.0" + }, + "peerDependencies": { + "webpack": ">=5.0.0" + } + }, + "node_modules/purgecss/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/purgecss/node_modules/commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/purgecss/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/purgecss/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/qs": { "version": "6.10.5", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.5.tgz", @@ -29773,6 +29851,67 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "purgecss": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-5.0.0.tgz", + "integrity": "sha512-RAnuxrGuVyLLTr8uMbKaxDRGWMgK5CCYDfRyUNNcaz5P3kGgD2b7ymQGYEyo2ST7Tl/ScwFgf5l3slKMxHSbrw==", + "dev": true, + "requires": { + "commander": "^9.0.0", + "glob": "^8.0.3", + "postcss": "^8.4.4", + "postcss-selector-parser": "^6.0.7" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "commander": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz", + "integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==", + "dev": true + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "purgecss-webpack-plugin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/purgecss-webpack-plugin/-/purgecss-webpack-plugin-5.0.0.tgz", + "integrity": "sha512-u8J0SxXdMekVOsbyV6hK1x6LlzJbE/mrC+UbNX0mLz5Jo/Jle8o4S3IFIRCgdzGdxtOBPCKW+UNgaULfKVmx2w==", + "dev": true, + "requires": { + "purgecss": "^5.0.0", + "webpack": ">=5.0.0" + } + }, "qs": { "version": "6.10.5", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.5.tgz", diff --git a/package.json b/package.json index 9f5822824..295158297 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "@babel/preset-typescript": "^7.18.6", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.11", + "purgecss-webpack-plugin": "^5.0.0", "typescript": "^4.8.2" }, "peerDependencies": {