diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..2801def3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment (please complete the following information):** + - OS: [e.g. iOS] + - Package [e.g. purgecss, postcss-purgecss] + - Version [e.g. 4.0.1] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..9d347210 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: Feature request +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/CHANGELOG.md b/CHANGELOG.md index b6ff6cca..8de5c654 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# [](https://github.com/FullHuman/purgecss/compare/v4.0.0...v) (2021-01-17) + +### Breaking Changes +Drop PostCSS 7 support, use @fullhuman/postcss-purgecss 3.0 with PostCSS 7. + # [](https://github.com/FullHuman/purgecss/compare/v3.1.3-alpha.0...v) (2020-12-15) * **postcss-purgecss** remove postcss 8 as peer dependency diff --git a/README.md b/README.md index 205b7420..96b5992b 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ This repository is a monorepo that we manage using [Lerna](https://github.com/le | [purgecss-webpack-plugin](/packages/purgecss-webpack-plugin) | ![npm](https://img.shields.io/npm/v/purgecss-webpack-plugin?style=flat-square) | Webpack plugin for PurgeCSS | | [gulp-purgecss](/packages/gulp-purgecss) | ![npm](https://img.shields.io/npm/v/gulp-purgecss?style=flat-square) | Gulp plugin for PurgeCSS | | [grunt-purgecss](/packages/grunt-purgecss) | ![npm](https://img.shields.io/npm/v/grunt-purgecss?style=flat-square) | Grunt plugin for PurgeCSS | +| [rollup-plugin-purgecss](/packages/rollup-plugin-purgecss) | ![npm](https://img.shields.io/npm/v/rollup-plugin-purgecss?style=flat-square) | Rollup plugin for PurgeCSS | | [purgecss-from-html](/packages/purgecss-from-html) | ![npm](https://img.shields.io/npm/v/purgecss-from-html?style=flat-square) | Html extractor for PurgeCSS | | [purgecss-from-pug](/packages/purgecss-from-pug) | ![npm](https://img.shields.io/npm/v/purgecss-from-pug?style=flat-square) | Pug extractor for PurgeCSS | | [purgecss-with-wordpress](/packages/purgecss-with-wordpress) | ![npm](https://img.shields.io/npm/v/purgecss-with-wordpress?style=flat-square) | Collection of safelist items for WordPress | diff --git a/docs/api.md b/docs/api.md index be4236e4..276168ce 100644 --- a/docs/api.md +++ b/docs/api.md @@ -36,7 +36,7 @@ In the following examples, the options passed to PurgeCSS are the same as the on ### ES Module Import Syntax ```javascript -import PurgeCSS from 'purgecss' +import { PurgeCSS } from 'purgecss' const purgeCSSResult = await new PurgeCSS().purge({ content: ['**/*.html'], css: ['**/*.css'] diff --git a/docs/guides/next.md b/docs/guides/next.md index 198bd7e9..972f1095 100644 --- a/docs/guides/next.md +++ b/docs/guides/next.md @@ -34,6 +34,8 @@ To customize the PostCSS configuration, create a postcss.config.js file in the r > Warning: When you define a custom PostCSS configuration file, Next.js completely disables the default behavior. Be sure to manually configure all the features you need compiled, including [Autoprefixer](https://github.com/postcss/autoprefixer). You also need to install any plugins included in your custom configuration manually, i.e. `npm install postcss-flexbugs-fixes postcss-preset-env`. +> By default, the outer document containing `html` and `body` is inside nextjs node module. Add `safelist:["html", "body"]` to make sure PurgeCSS does not remove those style. + Add PurgeCSS to the default configuration: ```js @@ -59,7 +61,8 @@ module.exports = { './pages/**/*.{js,jsx,ts,tsx}', './components/**/*.{js,jsx,ts,tsx}' ], - defaultExtractor: content => content.match(/[\w-/:]+(? content.match(/[\w-/:]+(?", "homepage": "https://purgecss.com", @@ -26,7 +26,7 @@ "url": "https://github.com/FullHuman/purgecss/issues" }, "dependencies": { - "purgecss": "^4.0.0" + "purgecss": "^4.0.1" }, "devDependencies": { "postcss": "^8.2.1" diff --git a/packages/purgecss-webpack-plugin/package-lock.json b/packages/purgecss-webpack-plugin/package-lock.json index 4ba495a0..3e0113e3 100644 --- a/packages/purgecss-webpack-plugin/package-lock.json +++ b/packages/purgecss-webpack-plugin/package-lock.json @@ -1,6 +1,6 @@ { "name": "purgecss-webpack-plugin", - "version": "4.0.0", + "version": "4.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -23,9 +23,9 @@ } }, "@types/estree": { - "version": "0.0.45", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz", - "integrity": "sha512-jnqIUKDUqJbDIUxm0Uj7bnlMnRm1T/eZ9N+AVMqhPgzrba2GhGG5o/jCTwmdPK709nEZsGoMzXEDUjcXHa3W0g==" + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", + "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==" }, "@types/json-schema": { "version": "7.0.6", @@ -204,9 +204,9 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "acorn": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.4.tgz", - "integrity": "sha512-XNP0PqF1XD19ZlLKvB7cMmnZswW4C/03pRHgirB30uSJTaS3A3V1/P4sS3HPvFmjoriPCJQs+JDSbm4bL1TxGQ==" + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.5.tgz", + "integrity": "sha512-v+DieK/HJkJOpFBETDJioequtc3PfxsWMaxIdIwujtF7FEV/MAyDQLlm6/zPvr7Mix07mLh6ccVwIsloceodlg==" }, "ajv": { "version": "6.12.6", @@ -245,15 +245,15 @@ } }, "browserslist": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.1.tgz", - "integrity": "sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==", + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.3.tgz", + "integrity": "sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==", "requires": { - "caniuse-lite": "^1.0.30001173", + "caniuse-lite": "^1.0.30001181", "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.634", + "electron-to-chromium": "^1.3.649", "escalade": "^3.1.1", - "node-releases": "^1.1.69" + "node-releases": "^1.1.70" } }, "buffer-from": { @@ -268,9 +268,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001174", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001174.tgz", - "integrity": "sha512-tqClL/4ThQq6cfFXH3oJL4rifFBeM6gTkphjao5kgwMaW9yn0tKgQLAEfKzDwj6HQWCB/aWo8kTFlSvIN8geEA==" + "version": "1.0.30001181", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001181.tgz", + "integrity": "sha512-m5ul/ARCX50JB8BSNM+oiPmQrR5UmngaQ3QThTTp5HcIIQGP/nPBs82BYLE+tigzm3VW+F4BJIhUyaVtEweelQ==" }, "chrome-trace-event": { "version": "1.0.2", @@ -321,9 +321,9 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, "electron-to-chromium": { - "version": "1.3.635", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.635.tgz", - "integrity": "sha512-RRriZOLs9CpW6KTLmgBqyUdnY0QNqqWs0HOtuQGGEMizOTNNn1P7sGRBxARnUeLejOsgwjDyRqT3E/CSst02ZQ==" + "version": "1.3.649", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.649.tgz", + "integrity": "sha512-ojGDupQ3UMkvPWcTICe4JYe17+o9OLiFMPoduoR72Zp2ILt1mRVeqnxBEd6s/ptekrnsFU+0A4lStfBe/wyG/A==" }, "emojis-list": { "version": "3.0.0", @@ -332,14 +332,19 @@ "dev": true }, "enhanced-resolve": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz", - "integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz", + "integrity": "sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==", "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, + "es-module-lexer": { + "version": "0.3.26", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz", + "integrity": "sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==" + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -537,9 +542,9 @@ } }, "mini-css-extract-plugin": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.3.tgz", - "integrity": "sha512-7lvliDSMiuZc81kI+5/qxvn47SCM7BehXex3f2c6l/pR3Goj58IQxZh9nuPQ3AkGQgoETyXuIqLDaO5Oa0TyBw==", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.5.tgz", + "integrity": "sha512-tvmzcwqJJXau4OQE5vT72pRT18o2zF+tQJp8CWchqvfQnTlflkzS+dANYcRdyPRWUWRkfmeNTKltx0NZI/b5dQ==", "dev": true, "requires": { "loader-utils": "^2.0.0", @@ -584,9 +589,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node-releases": { - "version": "1.1.69", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.69.tgz", - "integrity": "sha512-DGIjo79VDEyAnRlfSqYTsy+yoHd2IOjJiKUozD2MV2D85Vso6Bug56mb9tT/fY5Urt0iqk01H7x+llAruDR2zA==" + "version": "1.1.70", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.70.tgz", + "integrity": "sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw==" }, "once": { "version": "1.4.0", @@ -698,9 +703,9 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "purgecss": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-3.1.3.tgz", - "integrity": "sha512-hRSLN9mguJ2lzlIQtW4qmPS2kh6oMnA9RxdIYK8sz18QYqd6ePp4GNDl18oWHA1f2v2NEQIh51CO8s/E3YGckQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.0.0.tgz", + "integrity": "sha512-j/y6OtNpEiggw/ipCJUOMNLgLpeAv9L8q+SqzEdDzyVEZOfdWjg8yvgOxhBflNyYgJ8SZ+tTwPxrHT9vQUpEPw==", "requires": { "commander": "^6.0.0", "glob": "^7.0.0", @@ -850,19 +855,20 @@ } }, "webpack": { - "version": "5.12.3", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.12.3.tgz", - "integrity": "sha512-7tiQmcTnKhZwbf7X7sEfXe0pgkGjUZjT6JfYkZHvvIb4/ZsXl1rJu5PxsJoN7W3v5sNSP/8TgBoiOdDqVdvK5w==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.19.0.tgz", + "integrity": "sha512-egX19vAQ8fZ4cVYtA9Y941eqJtcZAK68mQq87MMv+GTXKZOc3TpKBBxdGX+HXUYlquPxiluNsJ1VHvwwklW7CQ==", "requires": { "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.45", + "@types/estree": "^0.0.46", "@webassemblyjs/ast": "1.11.0", "@webassemblyjs/wasm-edit": "1.11.0", "@webassemblyjs/wasm-parser": "1.11.0", "acorn": "^8.0.4", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.3.1", + "enhanced-resolve": "^5.7.0", + "es-module-lexer": "^0.3.26", "eslint-scope": "^5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", diff --git a/packages/purgecss-webpack-plugin/package.json b/packages/purgecss-webpack-plugin/package.json index a9245567..6e34f7bb 100644 --- a/packages/purgecss-webpack-plugin/package.json +++ b/packages/purgecss-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "purgecss-webpack-plugin", - "version": "4.0.0", + "version": "4.0.1", "description": "PurgeCSS plugin for webpack - Remove unused css", "author": "Ffloriel", "homepage": "https://purgecss.com", @@ -36,7 +36,7 @@ "test": "echo \"Error: run tests from root\" && exit 1" }, "dependencies": { - "purgecss": "^4.0.0", + "purgecss": "^4.0.1", "webpack": "^5.4.0", "webpack-sources": "^2.0.0" }, diff --git a/packages/purgecss-webpack-plugin/src/index.ts b/packages/purgecss-webpack-plugin/src/index.ts index e1c7b9ad..f5b6fcf3 100644 --- a/packages/purgecss-webpack-plugin/src/index.ts +++ b/packages/purgecss-webpack-plugin/src/index.ts @@ -103,6 +103,10 @@ export default class PurgeCSSPlugin { options.safelist = options.safelist(); } + if (typeof options.blocklist === "function") { + options.blocklist = options.blocklist(); + } + const purgecss = await new PurgeCSS().purge({ content: options.content, css: options.css, @@ -114,6 +118,7 @@ export default class PurgeCSSPlugin { rejected: options.rejected, variables: options.variables, safelist: options.safelist, + blocklist: options.blocklist, }); const purged = purgecss[0]; diff --git a/packages/purgecss-webpack-plugin/src/types/index.ts b/packages/purgecss-webpack-plugin/src/types/index.ts index fc85bb69..6de1a09c 100644 --- a/packages/purgecss-webpack-plugin/src/types/index.ts +++ b/packages/purgecss-webpack-plugin/src/types/index.ts @@ -17,8 +17,8 @@ export interface Extractors { } type PathFunction = () => string[]; - type SafelistFunction = () => ComplexSafelist; +type BlocklistFunction = () => StringRegExpArray; export interface UserDefinedOptions { paths: string[] | PathFunction; @@ -34,7 +34,7 @@ export interface UserDefinedOptions { variables?: boolean; verbose?: boolean; safelist?: StringRegExpArray | ComplexSafelist | SafelistFunction; - blocklist?: StringRegExpArray; + blocklist?: StringRegExpArray | BlocklistFunction; only?: string[]; } diff --git a/packages/purgecss/__tests__/attributes.test.ts b/packages/purgecss/__tests__/attributes.test.ts index 87bcf189..421605a7 100644 --- a/packages/purgecss/__tests__/attributes.test.ts +++ b/packages/purgecss/__tests__/attributes.test.ts @@ -63,8 +63,13 @@ describe("attributes", () => { it("handles [attribute*=value]", () => { // keep used css - expect(purgedCSS.includes('a[title~="thin"]')).toBe(true); + expect(purgedCSS.includes('a[title*="thin"]')).toBe(true); // remove unused css - expect(purgedCSS.includes('a[title~="fat"]')).toBe(false); + expect(purgedCSS.includes('a[title*="fat"]')).toBe(false); + }); + + it("handles spaces in attribute selector", () => { + expect(purgedCSS.includes('[class*=" class2"]')).toBe(true); + expect(purgedCSS.includes('[class*="class1 class2 "]')).toBe(true); }); }); diff --git a/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.css b/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.css index 57dc6dcf..5a3f5362 100644 --- a/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.css +++ b/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.css @@ -66,10 +66,18 @@ a[href$="http"] { /* CSS [attribute*="value"] Selector */ -a[title~="thin"] { +a[title*="thin"] { border: 5px solid yellow; } -a[title~="fat"] { +a[title*="fat"] { border: 5px solid yellow; +} + +/* CSS [attribute*="value"] Selector with spaces */ +[class*=" class2"] { + color: green; +} +[class*="class1 class2 "] { + color: blue; } \ No newline at end of file diff --git a/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.html b/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.html index 3ceee0a8..feb101ad 100644 --- a/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.html +++ b/packages/purgecss/__tests__/test_examples/attributes/attribute_selector.html @@ -5,4 +5,5 @@ pdf go to website hello +
hello
diff --git a/packages/purgecss/package-lock.json b/packages/purgecss/package-lock.json index 965e682b..71fc1114 100644 --- a/packages/purgecss/package-lock.json +++ b/packages/purgecss/package-lock.json @@ -1,6 +1,6 @@ { "name": "purgecss", - "version": "4.0.0", + "version": "4.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/purgecss/package.json b/packages/purgecss/package.json index 898a5fb3..246e2e7d 100644 --- a/packages/purgecss/package.json +++ b/packages/purgecss/package.json @@ -1,6 +1,6 @@ { "name": "purgecss", - "version": "4.0.0", + "version": "4.0.1", "description": "Remove unused css selectors", "author": "Ffloriel", "homepage": "https://purgecss.com", diff --git a/packages/purgecss/src/ExtractorResultSets.ts b/packages/purgecss/src/ExtractorResultSets.ts index 65ae0e49..18e111a3 100644 --- a/packages/purgecss/src/ExtractorResultSets.ts +++ b/packages/purgecss/src/ExtractorResultSets.ts @@ -65,7 +65,10 @@ class ExtractorResultSets { } hasAttrSubstr(substr: string): boolean { - return this.someAttrValue((value) => value.includes(substr)); + const wordSubstr = substr.trim().split(" "); + return wordSubstr.every((word) => + this.someAttrValue((value) => value.includes(word)) + ); } hasAttrValue(value: string): boolean { diff --git a/packages/rollup-plugin-purgecss/README.md b/packages/rollup-plugin-purgecss/README.md new file mode 100644 index 00000000..e2d57777 --- /dev/null +++ b/packages/rollup-plugin-purgecss/README.md @@ -0,0 +1,43 @@ +# rollup-plugin-purgecss +![David](https://img.shields.io/david/FullHuman/purgecss?path=packages%2Frollup-plugin-purgecss&style=for-the-badge) +![David](https://img.shields.io/david/dev/FullHuman/purgecss?path=packages%2Frollup-plugin-purgecss&style=for-the-badge) +![Dependabot](https://img.shields.io/badge/dependabot-enabled-%23024ea4?style=for-the-badge) +![npm](https://img.shields.io/npm/v/rollup-plugin-purgecss?style=for-the-badge) +![npm](https://img.shields.io/npm/dw/rollup-plugin-purgecss?style=for-the-badge) +![GitHub](https://img.shields.io/github/license/FullHuman/purgecss?style=for-the-badge) + +[Rollup](https://github.com/rollup/rollup) plugin to remove unused css. + +## Install + +```sh +npm i rollup-plugin-purgecss -D +``` + +## Usage + +```js +import { rollup } from 'rollup'; +import purgecss from 'rollup-plugin-purgecss'; + +rollup({ + entry: 'main.js', + plugins: [ + purgecss({ + content: ["index.html"] + }) + ] +}); +``` + +## Contributing + +Please read [CONTRIBUTING.md](./../../CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us. + +## Versioning + +We use [SemVer](http://semver.org/) for versioning. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details \ No newline at end of file diff --git a/packages/rollup-plugin-purgecss/__tests__/assets/actual_a.css b/packages/rollup-plugin-purgecss/__tests__/assets/actual_a.css new file mode 100644 index 00000000..634493c8 --- /dev/null +++ b/packages/rollup-plugin-purgecss/__tests__/assets/actual_a.css @@ -0,0 +1,8 @@ +html, body { + color: red; +} + +.used, +.there { + color: green; +} diff --git a/packages/rollup-plugin-purgecss/__tests__/assets/expect_a.css b/packages/rollup-plugin-purgecss/__tests__/assets/expect_a.css new file mode 100644 index 00000000..634493c8 --- /dev/null +++ b/packages/rollup-plugin-purgecss/__tests__/assets/expect_a.css @@ -0,0 +1,8 @@ +html, body { + color: red; +} + +.used, +.there { + color: green; +} diff --git a/packages/rollup-plugin-purgecss/__tests__/assets/test_a.css b/packages/rollup-plugin-purgecss/__tests__/assets/test_a.css new file mode 100644 index 00000000..6c9ffe07 --- /dev/null +++ b/packages/rollup-plugin-purgecss/__tests__/assets/test_a.css @@ -0,0 +1,12 @@ +html, body { + color: red; +} + +.used, +.there { + color: green; +} + +.unused { + color: #ff00ff; +} diff --git a/packages/rollup-plugin-purgecss/__tests__/assets/test_a.html b/packages/rollup-plugin-purgecss/__tests__/assets/test_a.html new file mode 100644 index 00000000..8d0b31aa --- /dev/null +++ b/packages/rollup-plugin-purgecss/__tests__/assets/test_a.html @@ -0,0 +1,8 @@ + + + Hello +
+
+
+ + \ No newline at end of file diff --git a/packages/rollup-plugin-purgecss/__tests__/fixtures/basic/index.js b/packages/rollup-plugin-purgecss/__tests__/fixtures/basic/index.js new file mode 100644 index 00000000..e0c3d63c --- /dev/null +++ b/packages/rollup-plugin-purgecss/__tests__/fixtures/basic/index.js @@ -0,0 +1,5 @@ +import "../../assets/test_a.css"; + +export default function noop() { + return; +} diff --git a/packages/rollup-plugin-purgecss/__tests__/index.test.ts b/packages/rollup-plugin-purgecss/__tests__/index.test.ts new file mode 100644 index 00000000..427364a2 --- /dev/null +++ b/packages/rollup-plugin-purgecss/__tests__/index.test.ts @@ -0,0 +1,27 @@ +import fs from "fs"; +import path from "path"; +import { rollup } from "rollup"; +import purgecss from "./../src/"; + +describe("rollup-plugin-purgecss", () => { + it("remove unused css", async () => { + const bundle = await rollup({ + input: path.resolve(__dirname, "fixtures/basic/index.js"), + plugins: [ + purgecss({ + content: [path.resolve(__dirname, "assets/test_a.html")], + output: path.resolve(__dirname, "assets/actual_a.css"), + }), + ], + }); + await bundle.generate({ format: "cjs", exports: "auto" }); + + const actualA = fs + .readFileSync(path.resolve(__dirname, "assets/actual_a.css")) + .toString(); + const expectA = fs + .readFileSync(path.resolve(__dirname, "assets/expect_a.css")) + .toString(); + expect(actualA).toEqual(expectA); + }); +}); diff --git a/packages/rollup-plugin-purgecss/package-lock.json b/packages/rollup-plugin-purgecss/package-lock.json new file mode 100644 index 00000000..47216af4 --- /dev/null +++ b/packages/rollup-plugin-purgecss/package-lock.json @@ -0,0 +1,21 @@ +{ + "name": "rollup-plugin-purgecss", + "version": "4.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==" + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "requires": { + "estree-walker": "^0.6.1" + } + } + } +} diff --git a/packages/rollup-plugin-purgecss/package.json b/packages/rollup-plugin-purgecss/package.json new file mode 100644 index 00000000..7c568eaa --- /dev/null +++ b/packages/rollup-plugin-purgecss/package.json @@ -0,0 +1,38 @@ +{ + "name": "rollup-plugin-purgecss", + "version": "4.0.1", + "description": "Rollup plugin for purgecss", + "main": "lib/rollup-plugin-purgecss.js", + "module": "./lib/rollup-plugin-purgecss.es.js", + "jsnext:main": "./lib/rollup-plugin-purgecss.es.js", + "directories": { + "lib": "lib", + "test": "__tests__" + }, + "scripts": { + "build": "npx rollup -c rollup.config.js", + "test": "npx ava __tests__/index.test.js -s", + "lint": "npx eslint -c .eslintrc src/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/FullHuman/rollup-plugin-purgecss.git" + }, + "keywords": [ + "rollup-plugin", + "purgecss", + "remove", + "unused", + "css" + ], + "author": "Ffloriel", + "license": "MIT", + "bugs": { + "url": "https://github.com/FullHuman/rollup-plugin-purgecss/issues" + }, + "homepage": "https://github.com/FullHuman/rollup-plugin-purgecss#readme", + "dependencies": { + "purgecss": "^4.0.1", + "rollup-pluginutils": "^2.8.0" + } +} diff --git a/packages/rollup-plugin-purgecss/src/index.ts b/packages/rollup-plugin-purgecss/src/index.ts new file mode 100644 index 00000000..af7a5c4e --- /dev/null +++ b/packages/rollup-plugin-purgecss/src/index.ts @@ -0,0 +1,71 @@ +import fs from "fs"; +import { PurgeCSS } from "purgecss"; +import { Plugin } from "rollup"; +import { createFilter } from "rollup-pluginutils"; +import { UserDefinedOptions } from "./types"; + +function pluginPurgeCSS(options: UserDefinedOptions): Plugin { + const filter = createFilter( + options.include || ["**/*.css"], + options.exclude || "node_modules/**" + ); + + const styles: string[] = []; + let dest = ""; + + return { + name: "purgecss", + transform: async (code, id) => { + if (!filter(id)) return null; + + const v = await new PurgeCSS().purge({ + content: options.content, + css: [ + { + raw: code, + }, + ], + }); + let css = v[0].css; + + styles.push(css); + + css = JSON.stringify(css); + if (options.insert) { + // do thing + } else if (!options.output) { + code = css; + } else { + code = `"";`; + } + + return { + code: `export default ${code}`, + map: { mappings: "" }, + }; + }, + generateBundle() { + if (!options.insert && (!styles.length || options.output === false)) { + return; + } + const css = styles.reduce((acc, value) => { + return acc + value; + }, ""); + if (typeof options.output === "string") { + return fs.writeFileSync(options.output, css); + } + if (typeof options.output === "function") { + return options.output(css, styles); + } + if (!options.insert && dest) { + if (dest.endsWith(".js") || dest.endsWith(".ts")) { + dest = dest.slice(0, -3); + } + dest = `${dest}.css`; + return fs.writeFileSync(dest, css); + } + }, + }; +} + +export default pluginPurgeCSS; diff --git a/packages/rollup-plugin-purgecss/src/types/index.ts b/packages/rollup-plugin-purgecss/src/types/index.ts new file mode 100644 index 00000000..9c7fc991 --- /dev/null +++ b/packages/rollup-plugin-purgecss/src/types/index.ts @@ -0,0 +1,40 @@ +import { + StringRegExpArray, + UserDefinedSafelist, +} from "../../../purgecss/src/types/index"; + +export interface RawContent { + extension: string; + raw: T; +} +export interface RawCSS { + raw: string; +} +type ExtractorFunction = (content: T) => string[]; +export interface Extractors { + extensions: string[]; + extractor: ExtractorFunction; +} + +type OutputFunction = (css: string, styles: string[]) => void; + +export interface UserDefinedOptions { + content: Array; + contentFunction?: (sourceFile: string) => Array; + defaultExtractor?: ExtractorFunction; + extractors?: Array; + fontFace?: boolean; + keyframes?: boolean; + output?: string | OutputFunction | boolean; + rejected?: boolean; + stdin?: boolean; + stdout?: boolean; + variables?: boolean; + safelist?: UserDefinedSafelist; + blocklist?: StringRegExpArray; + + insert?: boolean; + include?: string | RegExp | (string | RegExp)[]; + exclude?: string | RegExp | (string | RegExp)[]; + dest?: string; +} diff --git a/packages/vue-cli-plugin-purgecss/generator/index.js b/packages/vue-cli-plugin-purgecss/generator/index.js index 253a1ae4..25949367 100644 --- a/packages/vue-cli-plugin-purgecss/generator/index.js +++ b/packages/vue-cli-plugin-purgecss/generator/index.js @@ -1,7 +1,7 @@ module.exports = (api, options) => { api.extendPackage({ devDependencies: { - "@fullhuman/postcss-purgecss": "^3.0.0", + "@fullhuman/postcss-purgecss": "^4.0.0", }, }); api.render("./templates", options); diff --git a/packages/vue-cli-plugin-purgecss/package.json b/packages/vue-cli-plugin-purgecss/package.json index 0dade9e9..76e2f37d 100644 --- a/packages/vue-cli-plugin-purgecss/package.json +++ b/packages/vue-cli-plugin-purgecss/package.json @@ -1,6 +1,6 @@ { "name": "@fullhuman/vue-cli-plugin-purgecss", - "version": "4.0.0", + "version": "4.0.1", "description": "vue-cli plugin to add PurgeCSS", "author": "Ffloriel", "homepage": "https://purgecss.com", diff --git a/scripts/build.ts b/scripts/build.ts index 2bce4278..e6ec5f86 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -1,7 +1,7 @@ +import typescript from "@wessberg/rollup-plugin-ts"; import path from "path"; import { rollup } from "rollup"; import { terser } from "rollup-plugin-terser"; -import typescript from "@wessberg/rollup-plugin-ts"; const packagesDirectory = path.resolve(__dirname, "./../packages"); @@ -25,6 +25,10 @@ const packages = [ name: "purgecss-webpack-plugin", external: ["fs", "path", "purgecss", "webpack", "webpack-sources"], }, + { + name: "rollup-plugin-purgecss", + external: ["fs", "rollup-pluginutils", "purgecss"], + }, { name: "gulp-purgecss", external: ["through2", "plugin-error", "purgecss", "glob"],