From f8e4c2c48440c26ca612b2486a6e9561be6f56d0 Mon Sep 17 00:00:00 2001 From: Mehmet Can OZDEMIR Date: Mon, 4 Jul 2022 23:43:56 +0300 Subject: [PATCH] fix: Purgecss webpack plugin/only filter fix (#933) * fix: check if file exists in chunk after only filter * test: update simple-with-exclusion test case of purgecss-webpack-plugin to actually test for purgecss exclusion * docs: only option checks against chunk names instead of entrypoints --- docs/plugins/webpack.md | 91 +++++++++---------- .../expected/{styles.css => bundle.css} | 20 ---- .../simple-with-exclusion/expected/legacy.css | 14 +++ .../simple-with-exclusion/webpack.config.js | 14 +-- packages/purgecss-webpack-plugin/src/index.ts | 4 +- 5 files changed, 64 insertions(+), 79 deletions(-) rename packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/{styles.css => bundle.css} (51%) create mode 100644 packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/legacy.css diff --git a/docs/plugins/webpack.md b/docs/plugins/webpack.md index 27f15839..0e1c5e74 100644 --- a/docs/plugins/webpack.md +++ b/docs/plugins/webpack.md @@ -7,7 +7,7 @@ meta: - itemprop: description content: PurgeCSS is a tool for removing CSS that you're not actually using in your project. You can use it with webpack with a plugin. - property: og:url - content: https://purgecss.com/plugins/webpack + content: https://purgecss.com/plugins/webpack - property: og:site_name content: purgecss.com - property: og:type @@ -39,55 +39,54 @@ npm i purgecss-webpack-plugin -D ### With mini-css-extract-plugin ```js -const path = require('path') -const glob = require('glob') -const MiniCssExtractPlugin = require('mini-css-extract-plugin') -const PurgecssPlugin = require('purgecss-webpack-plugin') +const path = require("path"); +const glob = require("glob"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const PurgecssPlugin = require("purgecss-webpack-plugin"); const PATHS = { - src: path.join(__dirname, 'src') -} + src: path.join(__dirname, "src"), +}; module.exports = { - entry: './src/index.js', + entry: "./src/index.js", output: { - filename: 'bundle.js', - path: path.join(__dirname, 'dist') + filename: "bundle.js", + path: path.join(__dirname, "dist"), }, optimization: { splitChunks: { cacheGroups: { styles: { - name: 'styles', + name: "styles", test: /\.css$/, - chunks: 'all', - enforce: true - } - } - } + chunks: "all", + enforce: true, + }, + }, + }, }, module: { rules: [ { test: /\.css$/, - use: [ - MiniCssExtractPlugin.loader, - "css-loader" - ] - } - ] + use: [MiniCssExtractPlugin.loader, "css-loader"], + }, + ], }, plugins: [ new MiniCssExtractPlugin({ filename: "[name].css", }), new PurgecssPlugin({ - paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), + paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), }), - ] -} + ], +}; ``` + ### Multiple paths + If you need multiple paths use the npm package `glob-all` instead of `glob`, then you can use this syntax: ```js @@ -97,70 +96,70 @@ new PurgecssPlugin({ ]) }), ``` + to filter out directories see the glob-all documentation [here](https://www.npmjs.com/package/glob-all#filtering-out-directories). ## Options The options available in purgecss [Configuration](https://www.purgecss.com/configuration.html) are also available in the webpack plugin, with the exception of the `css` and `content` options. -* #### paths +- #### paths With the webpack plugin, you can specify the content that should be analyzed by purgecss by providing an array of filenames. These can be html, pug, blade, ... files. You can also use a module like `glob` or `glob-all` to easily get a list of files. > You likely need to pass `{ noDir: true }` as an option to `glob.sync()` as `glob.sync` is matching a dir which the plugin can't operate on. ```js -const PurgecssPlugin = require('purgecss-webpack-plugin') -const glob = require('glob') +const PurgecssPlugin = require("purgecss-webpack-plugin"); +const glob = require("glob"); const PATHS = { - src: path.join(__dirname, 'src') -} + src: path.join(__dirname, "src"), +}; // In the webpack configuration new PurgecssPlugin({ - paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }) -}) + paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), +}); ``` If you want to regenerate the list of paths on every compilation (e.g. when using `--watch`), then you can also pass a function to the `paths` option as in the following example: ```js new PurgecssPlugin({ - paths: () => glob.sync(`${PATHS.src}/**/*`, { nodir: true }) -}) + paths: () => glob.sync(`${PATHS.src}/**/*`, { nodir: true }), +}); ``` -* #### only +- #### only -You can specify entrypoints to the purgecss-webpack-plugin with the option `only`: +You can specify chunk names to the purgecss-webpack-plugin with the option `only`: ```js new PurgecssPlugin({ paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), - only: ['bundle', 'vendor'] -}) + only: ["bundle", "vendor"], +}); ``` -* #### safelist +- #### safelist Similar as for the `paths` option, you also can define a function for this option: ```js function collectSafelist() { return { - standard: ['safelisted', /^safelisted-/], + standard: ["safelisted", /^safelisted-/], deep: [/^safelisted-deep-/], - greedy: [/^safelisted-greedy/] - } + greedy: [/^safelisted-greedy/], + }; } // In the webpack configuration new PurgeCSSPlugin({ - safelist: collectSafelist -}) + safelist: collectSafelist, +}); ``` - -* #### rejected +- #### rejected When this option is set to `true` all removed selectors are added to the [Stats Data](https://webpack.js.org/api/stats/) as `purged`. diff --git a/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/styles.css b/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/bundle.css similarity index 51% rename from packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/styles.css rename to packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/bundle.css index e0271a4f..9343bab2 100644 --- a/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/styles.css +++ b/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/bundle.css @@ -5,10 +5,6 @@ color: red; } -.unused { - color: blue; -} - .safelisted { color: green; } @@ -16,19 +12,3 @@ md\:w-2\/3 { color: red; } - -/*!******************************************************************************!*\ - !*** css ../../../../../node_modules/css-loader/dist/cjs.js!./src/style.css ***! - \******************************************************************************/ -.legacy-unused-class { - color: red; -} - -.unused-too { - color: blue; -} - -.hello { - color: red; -} - diff --git a/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/legacy.css b/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/legacy.css new file mode 100644 index 00000000..201f3cde --- /dev/null +++ b/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/expected/legacy.css @@ -0,0 +1,14 @@ +/*!******************************************************************************!*\ + !*** css ../../../../../node_modules/css-loader/dist/cjs.js!./src/style.css ***! + \******************************************************************************/ +.legacy-unused-class { + color: red; +} + +.unused-too { + color: blue; +} + +.hello { + color: red; +} diff --git a/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/webpack.config.js b/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/webpack.config.js index 7f0fa1c5..c6f183c9 100644 --- a/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/webpack.config.js +++ b/packages/purgecss-webpack-plugin/__tests__/cases/simple-with-exclusion/webpack.config.js @@ -1,7 +1,7 @@ const path = require("path"); const glob = require("glob"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const {PurgeCSSPlugin} = require("../../../src/"); +const { PurgeCSSPlugin } = require("../../../src/"); const customExtractor = (content) => content.match(/[A-z0-9-:/]+/g) || []; @@ -17,17 +17,7 @@ module.exports = { legacy: "./src/legacy.js", }, optimization: { - splitChunks: { - cacheGroups: { - styles: { - name: "styles", - type: "css/mini-extract", - test: /\.css$/, - chunks: "all", - enforce: true, - }, - }, - }, + splitChunks: { chunks: "all" }, }, module: { rules: [ diff --git a/packages/purgecss-webpack-plugin/src/index.ts b/packages/purgecss-webpack-plugin/src/index.ts index efccb900..a85b5fa9 100644 --- a/packages/purgecss-webpack-plugin/src/index.ts +++ b/packages/purgecss-webpack-plugin/src/index.ts @@ -167,7 +167,9 @@ export class PurgeCSSPlugin { for (const chunk of compilation.chunks) { const assetsToPurge = assetsFromCompilation.filter(([name]) => { if (this.options.only) { - return this.options.only.some((only) => name.includes(only)); + if (!(this.options.only.some((only) => name.includes(only)))) { + return false; + } } return chunk.files.has(name);