From 87c3d4a06ce88b9f1d5185085530939d00f5cc55 Mon Sep 17 00:00:00 2001 From: Kelly Mears Date: Sun, 10 Sep 2023 03:55:29 -0400 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9C=A8=20improve(patch):=20reasonable=20?= =?UTF-8?q?defaults=20for=20purgecss?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/purgecss/bud.config.js | 11 --- examples/purgecss/bud.config.ts | 5 + examples/purgecss/src/index.css | 38 +++++++- examples/purgecss/src/index.html | 22 ++--- examples/purgecss/src/index.js | 14 +++ examples/purgecss/tsconfig.json | 5 +- .../@roots/bud-postcss/src/extension/index.ts | 5 + .../bud-postcss/src/extension/options.ts | 1 + sources/@roots/bud-purgecss/package.json | 12 +-- sources/@roots/bud-purgecss/src/api.ts | 91 ------------------- sources/@roots/bud-purgecss/src/extension.ts | 20 ---- .../bud-purgecss/src/extension/index.ts | 43 +++++++++ .../@roots/bud-purgecss/src/facade/index.ts | 31 +++++++ sources/@roots/bud-purgecss/src/index.ts | 21 ++++- .../bud-purgecss/test/extension.test.ts | 10 +- sources/@roots/bud-purgecss/tsconfig.json | 4 +- tests/integration/purgecss.test.ts | 21 ++++- 17 files changed, 193 insertions(+), 161 deletions(-) delete mode 100644 examples/purgecss/bud.config.js create mode 100644 examples/purgecss/bud.config.ts create mode 100644 examples/purgecss/src/index.js delete mode 100644 sources/@roots/bud-purgecss/src/api.ts delete mode 100644 sources/@roots/bud-purgecss/src/extension.ts create mode 100644 sources/@roots/bud-purgecss/src/extension/index.ts create mode 100644 sources/@roots/bud-purgecss/src/facade/index.ts diff --git a/examples/purgecss/bud.config.js b/examples/purgecss/bud.config.js deleted file mode 100644 index b0e2cb0311..0000000000 --- a/examples/purgecss/bud.config.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @param {import('@roots/bud').Bud} bud - */ -export default async bud => { - bud.html({template: bud.path('src/index.html')}) - - bud.purgecss({ - content: [bud.path('src/*.html')], - css: [bud.path('src/**/*.css')], - }) -} diff --git a/examples/purgecss/bud.config.ts b/examples/purgecss/bud.config.ts new file mode 100644 index 0000000000..3eeea7efa9 --- /dev/null +++ b/examples/purgecss/bud.config.ts @@ -0,0 +1,5 @@ +import {bud} from '@roots/bud' + +bud.html({ + template: bud.path('src/index.html'), +}) diff --git a/examples/purgecss/src/index.css b/examples/purgecss/src/index.css index b3400ebfb6..f0de66a29a 100644 --- a/examples/purgecss/src/index.css +++ b/examples/purgecss/src/index.css @@ -1,11 +1,47 @@ +/** + * This element is present in `index.html` and can be found in the final CSS file. + */ h1 { color: black; } +/** + * This element is present in `index.html` and can be found in the final CSS file. + */ h2 { color: red; } -h3.exclude { +/** + * This element is not found in any source file and will not be found in the final CSS file. + */ +h3 { color: yellow; } + +/** + * This element is dynamically inserted into the DOM in `index.js` and + * can be found in the final CSS file. + */ +.include { + color: green; +} + +/** + * This is a test of postcss syntax. There is no `.li` element within a `div` in any source file, + * but there is a `.li` element within a `section`. This will not be found in the final CSS file. + */ +div { + .li { + color: purple; + } +} + +/** + * This is a test of comment hinting. There is a dynamically inserted element in `index.js` + * which matches this selector. However, the class name is constructed by joining multiple + * strings together. We use a comment to make sure that this rule is preserved. + */ +.comment-test { + color: orange; +} diff --git a/examples/purgecss/src/index.html b/examples/purgecss/src/index.html index d438240415..2147320b00 100644 --- a/examples/purgecss/src/index.html +++ b/examples/purgecss/src/index.html @@ -1,20 +1,18 @@ - + - - - %APP_TITLE% - - + + PurgeCSS Test -

PostCSS

-

PurgeCss test

- +

This element has a matching css selector

+

This element has a matching css selector

+
+ +
diff --git a/examples/purgecss/src/index.js b/examples/purgecss/src/index.js new file mode 100644 index 0000000000..048f5b7362 --- /dev/null +++ b/examples/purgecss/src/index.js @@ -0,0 +1,14 @@ +import '@src/index.css' + +/** + * This dynamically inserted element is not present in `./index.html` but the matching + * CSS selector will be included in the final bundle because it matches. + */ +document.querySelector(`h2`)?.insertAdjacementHTML(`afterend`, `

Paragraph

`) + +/** + * This dynamically inserted element's classname is constructed from multiple strings + * so we'll include a comment to ensure it's not purged. + */ +const classname = [`comment`, `test`].join(`-`) // comment-test +document.querySelector(`h2`)?.insertAdjacentHTML(`afterend`, `
Paragraph
`) diff --git a/examples/purgecss/tsconfig.json b/examples/purgecss/tsconfig.json index e3b83fea04..c4fc2b4951 100644 --- a/examples/purgecss/tsconfig.json +++ b/examples/purgecss/tsconfig.json @@ -9,7 +9,6 @@ "webpack/module", ] }, - "files": ["bud.config.js"], - "include": ["src"], - "exclude": ["node_modules"] + "files": ["bud.config.ts"], + "include": ["src"] } diff --git a/sources/@roots/bud-postcss/src/extension/index.ts b/sources/@roots/bud-postcss/src/extension/index.ts index 644cd45953..7209336d69 100644 --- a/sources/@roots/bud-postcss/src/extension/index.ts +++ b/sources/@roots/bud-postcss/src/extension/index.ts @@ -66,6 +66,11 @@ class BudPostCss extends BudPostCssOptionsApi { return plugin[0] } + @bind + public hasPlugin(name: string): boolean { + return this.normalizePluginName(name) in this.plugins + } + @bind protected normalizePluginName(name: string): string { if (name.startsWith(`postcss-`)) name = name.replace(`postcss-`, ``) diff --git a/sources/@roots/bud-postcss/src/extension/options.ts b/sources/@roots/bud-postcss/src/extension/options.ts index 4c4712bb70..ed500c6226 100644 --- a/sources/@roots/bud-postcss/src/extension/options.ts +++ b/sources/@roots/bud-postcss/src/extension/options.ts @@ -39,6 +39,7 @@ type BudPostCssPublicInterface = StrictPublicExtensionApi< getPlugin(name: string): PluginReference getPluginOptions(name: string): Record getPluginPath(name: string): string + hasPlugin(name: string): boolean setConfig(config: boolean): BudPostCssPublicInterface setPlugin(name: string, plugin?: PluginInput): BudPostCssPublicInterface setPluginOptions( diff --git a/sources/@roots/bud-purgecss/package.json b/sources/@roots/bud-purgecss/package.json index a0c61d10e9..d3f748b3fd 100644 --- a/sources/@roots/bud-purgecss/package.json +++ b/sources/@roots/bud-purgecss/package.json @@ -51,33 +51,31 @@ "type": "module", "exports": { ".": "./lib/index.js", - "./api": "./lib/api.js", - "./extension": "./lib/extension.js" + "./facade": "./lib/facade/index.js", + "./extension": "./lib/extension/index.js" }, "typesVersions": { "*": { ".": [ "./lib/index.d.ts" ], - "api": [ - "./lib/api.d.ts" + "facade": [ + "./lib/facade/index.d.ts" ], "extension": [ - "./lib/extension.d.ts" + "./lib/extension/index.d.ts" ] } }, "types": "./lib/index.d.ts", "module": "./lib/index.js", "devDependencies": { - "@roots/bud": "workspace:*", "@roots/bud-postcss": "workspace:*", "@skypack/package-check": "0.2.2", "@types/node": "18.17.9" }, "dependencies": { "@fullhuman/postcss-purgecss": "5.0.0", - "@roots/bud": "workspace:*", "@roots/bud-framework": "workspace:*", "postcss": "8.4.28", "tslib": "2.6.2" diff --git a/sources/@roots/bud-purgecss/src/api.ts b/sources/@roots/bud-purgecss/src/api.ts deleted file mode 100644 index a0fea6d7af..0000000000 --- a/sources/@roots/bud-purgecss/src/api.ts +++ /dev/null @@ -1,91 +0,0 @@ -import type {Bud} from '@roots/bud-framework' - -/** - * Purge unused CSS from compiled stylesheets - * - * @remarks - * For more information, see [the PurgeCSS API](https://purgecss.com/configuration.html) - * - * @example - * ```js - * app.purgecss({ - * content: [app.path('resources/views/**')], - * allow: require('purgecss-with-wordpress').whitelist, - * allowPatterns: require('purgecss-with-wordpress').whitelistPatterns, - * }) - * ``` - */ -export interface purge { - (this: Bud, userOptions: Options): Bud -} - -/** - * PurgeCSS options - * - * @see https://purgecss.com/plugins/postcss.html#options - */ -export interface Options { - blocklist?: Array - content?: Array< - | { - extension: string - raw: string - } - | string - > - contentFunction?: (sourceFile: string) => Array< - | { - extension: string - raw: string - } - | string - > - defaultExtractor?: ExtractorFunction - extractors?: Array - fontFace?: boolean - keyframes?: boolean - output?: string - rejected?: boolean - safelist?: - | { - deep?: RegExp[] - greedy?: RegExp[] - keyframes?: Array - standard?: Array - variables?: Array - } - | Array - stdin?: boolean - stdout?: boolean - variables?: boolean -} - -export type ExtractorFunction = (content: T) => string[] - -export interface Extractors { - extensions: string[] - extractor: ExtractorFunction -} - -/** - * Purge unused CSS from compiled stylesheets - * - * @remarks - * For more information, see [the PurgeCSS API](https://purgecss.com/configuration.html) - * - * @example - * ```js - * app.purgecss({ - * content: [app.path('resources/views/**')], - * allow: require('purgecss-with-wordpress').whitelist, - * allowPatterns: require('purgecss-with-wordpress').whitelistPatterns, - * }) - * ``` - */ -export const purgecss: purge = function (userOptions) { - this.postcss - .setPlugin(`purgecss`, [`@fullhuman/postcss-purgecss`, userOptions]) - .use(plugins => [...plugins, `purgecss`]) - - return this -} diff --git a/sources/@roots/bud-purgecss/src/extension.ts b/sources/@roots/bud-purgecss/src/extension.ts deleted file mode 100644 index cab3877818..0000000000 --- a/sources/@roots/bud-purgecss/src/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type {Bud} from '@roots/bud-framework' - -import {Extension} from '@roots/bud-framework/extension' -import {dependsOn, label} from '@roots/bud-framework/extension/decorators' - -import {purgecss} from './api.js' - -/** - * ## purgecss configuration - */ -@label(`@roots/bud-purgecss`) -@dependsOn([`@roots/bud-postcss`]) -export default class BudPurgeCSS extends Extension { - /** - * {@link Extension.register} - */ - public override async register(bud: Bud) { - bud.bindFacade(`purgecss`, purgecss) - } -} diff --git a/sources/@roots/bud-purgecss/src/extension/index.ts b/sources/@roots/bud-purgecss/src/extension/index.ts new file mode 100644 index 0000000000..6127daafb0 --- /dev/null +++ b/sources/@roots/bud-purgecss/src/extension/index.ts @@ -0,0 +1,43 @@ +import type {UserDefinedOptions as Options} from '@fullhuman/postcss-purgecss' +import type {Bud} from '@roots/bud-framework' + +import {DynamicOption, Extension} from '@roots/bud-framework/extension' +import { + dependsOn, + label, + options, +} from '@roots/bud-framework/extension/decorators' +import {purgecss} from '@roots/bud-purgecss/facade' + +/** + * PurgeCSS configuration + * + * {@link Extension} + */ +@label(`@roots/bud-purgecss`) +@dependsOn([`@roots/bud-postcss`]) +@options({ + content: DynamicOption.make((bud: Bud) => [ + bud.path(`@src/*.{js,jsx,ts,tsx,vue,html,php,pug,rb}`), + bud.path(`@src/**/*.{js,jsx,ts,tsx,vue,html,php,pug,rb}`), + ]), +}) +export default class BudPurgeCSS extends Extension { + /** + * {@link Extension.register} + */ + public override async register(bud: Bud) { + bud.bindFacade(`purgecss`, purgecss) + } + + /** + * {@link Extension.buildBefore} + */ + public override async buildBefore(bud: Bud) { + // Return early if purgecss is already setup + if (bud.postcss.hasPlugin(`purgecss`)) return + + // Set up plugin with default options + bud.purgecss(this.getOptions()) + } +} diff --git a/sources/@roots/bud-purgecss/src/facade/index.ts b/sources/@roots/bud-purgecss/src/facade/index.ts new file mode 100644 index 0000000000..2e3b4196cf --- /dev/null +++ b/sources/@roots/bud-purgecss/src/facade/index.ts @@ -0,0 +1,31 @@ +import type {UserDefinedOptions} from '@fullhuman/postcss-purgecss' +import type {Bud} from '@roots/bud-framework' + +type Options = ((options?: UserDefinedOptions) => UserDefinedOptions) | UserDefinedOptions + +export interface purgecss { + (this: Bud, options: Options): Bud +} + +/** + * Purge unused CSS from compiled stylesheets + * + * @remarks + * For more information, see [the PurgeCSS API](https://purgecss.com/configuration.html) + * + * @example + * ```js + * app.purgecss({ + * content: [app.path('resources/views/**')], + * allow: require('purgecss-with-wordpress').whitelist, + * allowPatterns: require('purgecss-with-wordpress').whitelistPatterns, + * }) + * ``` + */ +export const purgecss: purgecss = function (options) { + this.postcss + .setPlugin(`purgecss`, [`@fullhuman/postcss-purgecss`, options]) + .use(plugins => [...plugins, `purgecss`]) + + return this +} diff --git a/sources/@roots/bud-purgecss/src/index.ts b/sources/@roots/bud-purgecss/src/index.ts index 2c4978ff42..7c2fd7dfd3 100644 --- a/sources/@roots/bud-purgecss/src/index.ts +++ b/sources/@roots/bud-purgecss/src/index.ts @@ -8,13 +8,28 @@ * @see https://github.com/roots/bud */ -import type {purgecss} from './api.js' +import type {purgecss} from '@roots/bud-purgecss/facade' -import BudPurgeCSS from './extension.js' +import BudPurgeCSS from '@roots/bud-purgecss/extension' declare module '@roots/bud-framework' { interface Bud { - purgecss: typeof purgecss + /** + * Purge unused CSS from compiled stylesheets + * + * @remarks + * For more information, see [the PurgeCSS API](https://purgecss.com/configuration.html) + * + * @example + * ```js + * app.purgecss({ + * content: [app.path('resources/views/**')], + * allow: require('purgecss-with-wordpress').whitelist, + * allowPatterns: require('purgecss-with-wordpress').whitelistPatterns, + * }) + * ``` + */ + purgecss: purgecss } interface Modules { diff --git a/sources/@roots/bud-purgecss/test/extension.test.ts b/sources/@roots/bud-purgecss/test/extension.test.ts index 161d0daf71..533b81a4de 100644 --- a/sources/@roots/bud-purgecss/test/extension.test.ts +++ b/sources/@roots/bud-purgecss/test/extension.test.ts @@ -1,12 +1,9 @@ -import '../src/index.js' - import {Bud, factory} from '@repo/test-kit' import postcss from '@roots/bud-postcss' +import BudPurgeCSS from '@roots/bud-purgecss' +import {purgecss} from '@roots/bud-purgecss/facade' import {beforeEach, describe, expect, it} from 'vitest' -import {purgecss} from '../src/api.js' -import BudPurgeCSS from '../src/extension.js' - describe( `@roots/bud-purgecss`, () => { @@ -17,15 +14,14 @@ describe( bud = await factory() await bud.build.make() await bud.extensions.add(postcss) - // @ts-ignore Extension = new BudPurgeCSS(bud) }) it(`should be constructable`, () => { expect(Extension).toEqual( expect.objectContaining({ - label: `@roots/bud-purgecss`, dependsOn: expect.any(Set), + label: `@roots/bud-purgecss`, register: expect.any(Function), }), ) diff --git a/sources/@roots/bud-purgecss/tsconfig.json b/sources/@roots/bud-purgecss/tsconfig.json index 01a1e333ef..82ef054b44 100644 --- a/sources/@roots/bud-purgecss/tsconfig.json +++ b/sources/@roots/bud-purgecss/tsconfig.json @@ -3,10 +3,10 @@ "compilerOptions": { "rootDir": "src", "outDir": "lib", - "types": ["@roots/bud-framework", "@roots/bud-postcss"] + "types": ["@roots/bud-framework", "@roots/bud-postcss", "node"] }, "include": ["src"], - "exclude": ["**/*.test.ts"], + "exclude": ["test"], "references": [ {"path": "./../bud-framework/tsconfig.json"}, {"path": "./../bud-api/tsconfig.json"}, diff --git a/tests/integration/purgecss.test.ts b/tests/integration/purgecss.test.ts index 8da04e9d66..b3c000ed18 100644 --- a/tests/integration/purgecss.test.ts +++ b/tests/integration/purgecss.test.ts @@ -1,4 +1,5 @@ import setup from '@repo/test-kit/setup' +import {testIsCompiledCss, testIsMinimized} from '@repo/test-kit/tests' import {describe, expect, it} from 'vitest' describe(`examples/purgecss`, () => { @@ -7,9 +8,21 @@ describe(`examples/purgecss`, () => { await test.install() await test.build() - expect(test.assets[`main.css`].length).toBeGreaterThan(10) - expect(test.assets[`main.css`].includes(`@import`)).toBeFalsy() - expect(test.assets[`main.css`].includes(`h2`)).toBeTruthy() - expect(test.assets[`main.css`]).not.toMatch(/\.*h3.*/) + const css = test.assets[`main.css`] + + testIsCompiledCss(css) + testIsMinimized(css) + + // matched in src/index.html + expect(test.assets[`main.css`]).toMatch(/h1{.*}/) + expect(test.assets[`main.css`]).toMatch(/h2{.*}/) + + // matched in src/index.js + expect(test.assets[`main.css`]).toMatch(/\.include{.*}/) + expect(test.assets[`main.css`]).toMatch(/\.comment-test{.*}/) + + // not matched in source + expect(test.assets[`main.css`]).not.toMatch(/h3{.*}/) + expect(test.assets[`main.css`]).not.toMatch(/div \.bar{.*}/) }) }) From a102b928437f872a6920b3621f5cb3143f29c7d9 Mon Sep 17 00:00:00 2001 From: Kelly Mears Date: Sun, 10 Sep 2023 04:12:56 -0400 Subject: [PATCH 2/4] --- yarn.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 5ba105d0e4..5fca4c3466 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8293,7 +8293,6 @@ __metadata: resolution: "@roots/bud-purgecss@workspace:sources/@roots/bud-purgecss" dependencies: "@fullhuman/postcss-purgecss": 5.0.0 - "@roots/bud": "workspace:*" "@roots/bud-framework": "workspace:*" "@roots/bud-postcss": "workspace:*" "@skypack/package-check": 0.2.2 From f589a51e9d7cdd92a4511176d4cf7407810a065f Mon Sep 17 00:00:00 2001 From: Kelly Mears Date: Mon, 11 Sep 2023 04:05:40 -0400 Subject: [PATCH 3/4] --- .../@roots/bud-purgecss/src/extension/base.ts | 75 +++++++++++++++++++ .../bud-purgecss/src/extension/index.ts | 39 ++++++++-- .../bud-purgecss/src/extension/model.ts | 9 +++ sources/@roots/bud-purgecss/src/index.ts | 15 ++++ 4 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 sources/@roots/bud-purgecss/src/extension/base.ts create mode 100644 sources/@roots/bud-purgecss/src/extension/model.ts diff --git a/sources/@roots/bud-purgecss/src/extension/base.ts b/sources/@roots/bud-purgecss/src/extension/base.ts new file mode 100644 index 0000000000..8ebf39dbdc --- /dev/null +++ b/sources/@roots/bud-purgecss/src/extension/base.ts @@ -0,0 +1,75 @@ +import type { UserDefinedOptions as Options } from '@fullhuman/postcss-purgecss' + +import {Extension} from '@roots/bud-framework/extension' + +import type { BudPurgeCSSPublicInterface } from './model.js' + +export default class BudPurgeCSSPublicAPI extends Extension { + public declare blocklist: BudPurgeCSSPublicInterface[`blocklist`] + public declare getBlocklist: BudPurgeCSSPublicInterface[`getBlocklist`] + public declare setBlocklist: BudPurgeCSSPublicInterface[`setBlocklist`] + + public declare content: BudPurgeCSSPublicInterface[`content`] + public declare getContent: BudPurgeCSSPublicInterface[`getContent`] + public declare setContent: BudPurgeCSSPublicInterface[`setContent`] + + public declare contentFunction: BudPurgeCSSPublicInterface[`contentFunction`] + public declare getContentFunction: BudPurgeCSSPublicInterface[`getContentFunction`] + public declare setContentFunction: BudPurgeCSSPublicInterface[`setContentFunction`] + + public declare dynamicAttributes: BudPurgeCSSPublicInterface[`dynamicAttributes`] + public declare getDynamicAttributes: BudPurgeCSSPublicInterface[`getDynamicAttributes`] + public declare setDynamicAttributes: BudPurgeCSSPublicInterface[`setDynamicAttributes`] + + public declare defaultExtractor: BudPurgeCSSPublicInterface[`defaultExtractor`] + public declare getDefaultExtractor: BudPurgeCSSPublicInterface[`getDefaultExtractor`] + public declare setDefaultExtractor: BudPurgeCSSPublicInterface[`setDefaultExtractor`] + + public declare extractors: BudPurgeCSSPublicInterface[`extractors`] + public declare getExtractors: BudPurgeCSSPublicInterface[`getExtractors`] + public declare setExtractors: BudPurgeCSSPublicInterface[`setExtractors`] + + public declare fontFace: BudPurgeCSSPublicInterface[`fontFace`] + public declare getFontFace: BudPurgeCSSPublicInterface[`getFontFace`] + public declare setFontFace: BudPurgeCSSPublicInterface[`setFontFace`] + + public declare keyframes: BudPurgeCSSPublicInterface[`keyframes`] + public declare getKeyframes: BudPurgeCSSPublicInterface[`getKeyframes`] + public declare setKeyframes: BudPurgeCSSPublicInterface[`setKeyframes`] + + public declare output: BudPurgeCSSPublicInterface[`output`] + public declare getOutput: BudPurgeCSSPublicInterface[`getOutput`] + public declare setOutput: BudPurgeCSSPublicInterface[`setOutput`] + + public declare rejected: BudPurgeCSSPublicInterface[`rejected`] + public declare getRejected: BudPurgeCSSPublicInterface[`getRejected`] + public declare setRejected: BudPurgeCSSPublicInterface[`setRejected`] + + public declare rejectedCss: BudPurgeCSSPublicInterface[`rejectedCss`] + public declare getRejectedCss: BudPurgeCSSPublicInterface[`getRejectedCss`] + public declare setRejectedCss: BudPurgeCSSPublicInterface[`setRejectedCss`] + + public declare safelist: BudPurgeCSSPublicInterface[`safelist`] + public declare getSafelist: BudPurgeCSSPublicInterface[`getSafelist`] + public declare setSafelist: BudPurgeCSSPublicInterface[`setSafelist`] + + public declare skippedContentGlobs: BudPurgeCSSPublicInterface[`skippedContentGlobs`] + public declare getSkippedContentGlobs: BudPurgeCSSPublicInterface[`getSkippedContentGlobs`] + public declare setSkippedContentGlobs: BudPurgeCSSPublicInterface[`setSkippedContentGlobs`] + + public declare sourceMap: BudPurgeCSSPublicInterface[`sourceMap`] + public declare getSourceMap: BudPurgeCSSPublicInterface[`getSourceMap`] + public declare setSourceMap: BudPurgeCSSPublicInterface[`setSourceMap`] + + public declare stdin: BudPurgeCSSPublicInterface[`stdin`] + public declare getStdin: BudPurgeCSSPublicInterface[`getStdin`] + public declare setStdin: BudPurgeCSSPublicInterface[`setStdin`] + + public declare stdout: BudPurgeCSSPublicInterface[`stdout`] + public declare getStdout: BudPurgeCSSPublicInterface[`getStdout`] + public declare setStdout: BudPurgeCSSPublicInterface[`setStdout`] + + public declare variables: BudPurgeCSSPublicInterface[`variables`] + public declare getVariables: BudPurgeCSSPublicInterface[`getVariables`] + public declare setVariables: BudPurgeCSSPublicInterface[`setVariables`] +} diff --git a/sources/@roots/bud-purgecss/src/extension/index.ts b/sources/@roots/bud-purgecss/src/extension/index.ts index 6127daafb0..996df18aa4 100644 --- a/sources/@roots/bud-purgecss/src/extension/index.ts +++ b/sources/@roots/bud-purgecss/src/extension/index.ts @@ -4,11 +4,14 @@ import type {Bud} from '@roots/bud-framework' import {DynamicOption, Extension} from '@roots/bud-framework/extension' import { dependsOn, + expose, label, options, } from '@roots/bud-framework/extension/decorators' import {purgecss} from '@roots/bud-purgecss/facade' +import BudPurgeCSSPublicAPI from './base.js' + /** * PurgeCSS configuration * @@ -16,13 +19,30 @@ import {purgecss} from '@roots/bud-purgecss/facade' */ @label(`@roots/bud-purgecss`) @dependsOn([`@roots/bud-postcss`]) +@expose(`purge`) @options({ + blocklist: undefined, content: DynamicOption.make((bud: Bud) => [ - bud.path(`@src/*.{js,jsx,ts,tsx,vue,html,php,pug,rb}`), - bud.path(`@src/**/*.{js,jsx,ts,tsx,vue,html,php,pug,rb}`), + bud.path(`@src/*.{html,js,jsx,php,pug,rb,ts,tsx,vue}`), + bud.path(`@src/**/*.{html,js,jsx,php,pug,rb,ts,tsx,vue}`), ]), + contentFunction: undefined, + defaultExtractor: undefined, + dynamicAttributes: undefined, + extractors: undefined, + fontFace: undefined, + keyframes: undefined, + output: undefined, + rejected: undefined, + rejectedCss: undefined, + safelist: undefined, + skippedContentGlobs: undefined, + sourceMap: undefined, + stdin: undefined, + stdout: undefined, + variables: undefined, }) -export default class BudPurgeCSS extends Extension { +export default class BudPurgeCSS extends BudPurgeCSSPublicAPI { /** * {@link Extension.register} */ @@ -34,10 +54,17 @@ export default class BudPurgeCSS extends Extension { * {@link Extension.buildBefore} */ public override async buildBefore(bud: Bud) { - // Return early if purgecss is already setup + /** + * Return early if purgecss is already setup + * Which can happen if the user has called the deprecated {@link Bud.purgecss} method + */ if (bud.postcss.hasPlugin(`purgecss`)) return - // Set up plugin with default options - bud.purgecss(this.getOptions()) + // Add purgecss to postcss plugins + bud.postcss + .setPlugin(`purgecss`, [`@fullhuman/postcss-purgecss`, this.options]) + .use(plugins => [...plugins, `purgecss`]) } } + +export {BudPurgeCSSPublicAPI} diff --git a/sources/@roots/bud-purgecss/src/extension/model.ts b/sources/@roots/bud-purgecss/src/extension/model.ts new file mode 100644 index 0000000000..d01d419c13 --- /dev/null +++ b/sources/@roots/bud-purgecss/src/extension/model.ts @@ -0,0 +1,9 @@ +import type { UserDefinedOptions as Options } from '@fullhuman/postcss-purgecss' + +import {type StrictPublicExtensionApi} from '@roots/bud-framework/extension' + +export interface BudPurgeCSSPublicInterface + extends StrictPublicExtensionApi< + BudPurgeCSSPublicInterface, + Options + > {} diff --git a/sources/@roots/bud-purgecss/src/index.ts b/sources/@roots/bud-purgecss/src/index.ts index 7c2fd7dfd3..0b361bbaa1 100644 --- a/sources/@roots/bud-purgecss/src/index.ts +++ b/sources/@roots/bud-purgecss/src/index.ts @@ -12,6 +12,8 @@ import type {purgecss} from '@roots/bud-purgecss/facade' import BudPurgeCSS from '@roots/bud-purgecss/extension' +import type { BudPurgeCSSPublicInterface } from './extension/model.js' + declare module '@roots/bud-framework' { interface Bud { /** @@ -29,6 +31,19 @@ declare module '@roots/bud-framework' { * }) * ``` */ + purge: BudPurgeCSSPublicInterface + + /** + * Purge unused CSS from compiled stylesheets + * + * @deprecated + * Use `bud.purge` instead. + * + * @example + * ```js + * bud.purge.set('content', [bud.path('resources/views/**')]) + * ``` + */ purgecss: purgecss } From 4df5fb275e0e08ffec3a00f15e482eadbe55d039 Mon Sep 17 00:00:00 2001 From: Kelly Mears Date: Tue, 12 Sep 2023 02:55:37 -0400 Subject: [PATCH 4/4] --- sources/@roots/bud-purgecss/src/extension/index.ts | 4 +++- sources/@roots/bud-purgecss/src/index.ts | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/sources/@roots/bud-purgecss/src/extension/index.ts b/sources/@roots/bud-purgecss/src/extension/index.ts index 996df18aa4..d8bc282895 100644 --- a/sources/@roots/bud-purgecss/src/extension/index.ts +++ b/sources/@roots/bud-purgecss/src/extension/index.ts @@ -7,6 +7,7 @@ import { expose, label, options, + production, } from '@roots/bud-framework/extension/decorators' import {purgecss} from '@roots/bud-purgecss/facade' @@ -42,6 +43,7 @@ import BudPurgeCSSPublicAPI from './base.js' stdout: undefined, variables: undefined, }) +@production export default class BudPurgeCSS extends BudPurgeCSSPublicAPI { /** * {@link Extension.register} @@ -67,4 +69,4 @@ export default class BudPurgeCSS extends BudPurgeCSSPublicAPI { } } -export {BudPurgeCSSPublicAPI} +export type {BudPurgeCSSPublicAPI} diff --git a/sources/@roots/bud-purgecss/src/index.ts b/sources/@roots/bud-purgecss/src/index.ts index 0b361bbaa1..c34179cf23 100644 --- a/sources/@roots/bud-purgecss/src/index.ts +++ b/sources/@roots/bud-purgecss/src/index.ts @@ -26,8 +26,7 @@ declare module '@roots/bud-framework' { * ```js * app.purgecss({ * content: [app.path('resources/views/**')], - * allow: require('purgecss-with-wordpress').whitelist, - * allowPatterns: require('purgecss-with-wordpress').whitelistPatterns, + * safestlist: require('purgecss-with-wordpress').safelist, * }) * ``` */ @@ -37,11 +36,13 @@ declare module '@roots/bud-framework' { * Purge unused CSS from compiled stylesheets * * @deprecated - * Use `bud.purge` instead. + * Use {@link Bud.purge} instead. * * @example * ```js - * bud.purge.set('content', [bud.path('resources/views/**')]) + * bud.purge + * .setContent([bud.path('resources/views/**')]) + * .setSafelist((await import('purgecss-with-wordpress')).safelist) * ``` */ purgecss: purgecss