From 1482c7512a0291dd122bf78bbd100f6ffc3fa1ad Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 10 Nov 2022 12:33:42 -0500 Subject: [PATCH 1/6] Fix watching of files on Linux when renames are involved (#9796) * Fix watching files on Linux * Update changelog --- CHANGELOG.md | 4 +++- src/cli/build/watching.js | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27c08731a119..a2caf67580ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Fix watching of files on Linux when renames are involved ([#9796](https://github.com/tailwindlabs/tailwindcss/pull/9796)) ## [3.2.3] - 2022-11-09 diff --git a/src/cli/build/watching.js b/src/cli/build/watching.js index c5204b610e54..ffbfd1ac096a 100644 --- a/src/cli/build/watching.js +++ b/src/cli/build/watching.js @@ -97,14 +97,15 @@ export function createWatcher(args, { state, rebuild }) { * * @param {*} file * @param {(() => Promise) | null} content + * @param {boolean} skipPendingCheck * @returns {Promise} */ - function recordChangedFile(file, content = null) { + function recordChangedFile(file, content = null, skipPendingCheck = false) { file = path.resolve(file) // Applications like Vim/Neovim fire both rename and change events in succession for atomic writes // In that case rebuild has already been queued by rename, so can be skipped in change - if (pendingRebuilds.has(file)) { + if (pendingRebuilds.has(file) && !skipPendingCheck) { return Promise.resolve() } @@ -198,8 +199,10 @@ export function createWatcher(args, { state, rebuild }) { } // This will push the rebuild onto the chain + // We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux + // This is because the order of events and timing is different on Linux // @ts-ignore: TypeScript isn't picking up that content is a string here - await recordChangedFile(filePath, () => content) + await recordChangedFile(filePath, () => content, true) } catch { // If reading the file fails, it's was probably a deleted temporary file // So we can ignore it and no rebuild is needed From 4ccc0fa12ad31dfee285465dda937b76afa6cb49 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 11 Nov 2022 10:14:14 -0500 Subject: [PATCH 2/6] Make sure errors are always displayed when watching for changes (#9810) * Make sure errors are always displayed when watching for changes * Update changelog --- CHANGELOG.md | 1 + src/cli/build/plugin.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2caf67580ad..cb7712480e0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix watching of files on Linux when renames are involved ([#9796](https://github.com/tailwindlabs/tailwindcss/pull/9796)) +- Make sure errors are always displayed when watching for changes ([#9810](https://github.com/tailwindlabs/tailwindcss/pull/9810)) ## [3.2.3] - 2022-11-09 diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index 8d21516ef3ff..6b61c723eeff 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -364,6 +364,23 @@ export async function createProcessor(args, cliConfigPath) { console.error() console.error('Done in', (end - start) / BigInt(1e6) + 'ms.') }) + .then( + () => {}, + (err) => { + // TODO: If an initial build fails we can't easily pick up any PostCSS dependencies + // that were collected before the error occurred + // The result is not stored on the error so we have to store it externally + // and pull the messages off of it here somehow + + // This results in a less than ideal DX because the watcher will not pick up + // changes to imported CSS if one of them caused an error during the initial build + // If you fix it and then save the main CSS file so there's no error + // The watcher will start watching the imported CSS files and will be + // resilient to future errors. + + console.error(err) + } + ) } /** From 602101d030aa1d0e9ccc5fd401097e324cc50dd0 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 11 Nov 2022 11:47:20 -0500 Subject: [PATCH 3/6] Allow users to block generation of certain utilities (#9812) * Add blocklist tests * Build initial implementation of blocklist * wip * wip * wip * Update changelog --- CHANGELOG.md | 4 ++ src/lib/setupContextUtils.js | 3 +- src/util/normalizeConfig.js | 18 ++++++ tests/blocklist.test.js | 116 +++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 tests/blocklist.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index cb7712480e0e..83a777060587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Allow users to block generation of certain utilities ([#9812](https://github.com/tailwindlabs/tailwindcss/pull/9812)) + ### Fixed - Fix watching of files on Linux when renames are involved ([#9796](https://github.com/tailwindlabs/tailwindcss/pull/9796)) diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index a5f8d3fdfb67..7b815ffbeaa0 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -1165,7 +1165,8 @@ export function createContext(tailwindConfig, changedContent = [], root = postcs candidateRuleCache: new Map(), classCache: new Map(), applyClassCache: new Map(), - notClassCache: new Set(), + // Seed the not class cache with the blocklist (which is only strings) + notClassCache: new Set(tailwindConfig.blocklist ?? []), postCssNodeCache: new Map(), candidateRuleMap: new Map(), tailwindConfig, diff --git a/src/util/normalizeConfig.js b/src/util/normalizeConfig.js index baee48394d56..95f63a39eeee 100644 --- a/src/util/normalizeConfig.js +++ b/src/util/normalizeConfig.js @@ -150,6 +150,24 @@ export function normalizeConfig(config) { return [] })() + // Normalize the `blocklist` + config.blocklist = (() => { + let { blocklist } = config + + if (Array.isArray(blocklist)) { + if (blocklist.every((item) => typeof item === 'string')) { + return blocklist + } + + log.warn('blocklist-invalid', [ + 'The `blocklist` option must be an array of strings.', + 'https://tailwindcss.com/docs/content-configuration#discarding-classes', + ]) + } + + return [] + })() + // Normalize prefix option if (typeof config.prefix === 'function') { log.warn('prefix-function', [ diff --git a/tests/blocklist.test.js b/tests/blocklist.test.js new file mode 100644 index 000000000000..9fc319a9c908 --- /dev/null +++ b/tests/blocklist.test.js @@ -0,0 +1,116 @@ +import { run, html, css } from './util/run' + +let warn + +beforeEach(() => { + warn = jest.spyOn(require('../src/util/log').default, 'warn') +}) + +afterEach(() => warn.mockClear()) + +it('can block classes matched literally', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + blocklist: ['font', 'uppercase', 'hover:text-sm', 'bg-red-500/50', 'my-custom-class'], + } + + let input = css` + @tailwind utilities; + .my-custom-class { + color: red; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchCss(css` + .font-bold { + font-weight: 700; + } + .my-custom-class { + color: red; + } + @media (min-width: 640px) { + .sm\:hover\:text-sm:hover { + font-size: 0.875rem; + line-height: 1.25rem; + } + } + `) + }) +}) + +it('can block classes inside @layer', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + blocklist: ['my-custom-class'], + } + + let input = css` + @tailwind utilities; + @layer utilities { + .my-custom-class { + color: red; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchCss(css` + .font-bold { + font-weight: 700; + } + `) + }) +}) + +it('blocklists do NOT support regexes', async () => { + let config = { + content: [{ raw: html`
` }], + blocklist: [/^bg-\[[^]+\]$/], + } + + let result = await run('@tailwind utilities', config) + + expect(result.css).toMatchCss(css` + .bg-\[\#f00d1e\] { + --tw-bg-opacity: 1; + background-color: rgb(240 13 30 / var(--tw-bg-opacity)); + } + .font-bold { + font-weight: 700; + } + `) + + expect(warn).toHaveBeenCalledTimes(1) + expect(warn.mock.calls.map((x) => x[0])).toEqual(['blocklist-invalid']) +}) + +it('can block classes generated by the safelist', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [{ pattern: /^bg-red-(400|500)$/ }], + blocklist: ['bg-red-500'], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .bg-red-400 { + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + } + .font-bold { + font-weight: 700; + } + `) + }) +}) From 22d45dd2dd4e16c02eccb520b087d5de4d54b06f Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Fri, 11 Nov 2022 12:14:29 -0500 Subject: [PATCH 4/6] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83a777060587..e1447afc3558 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Allow users to block generation of certain utilities ([#9812](https://github.com/tailwindlabs/tailwindcss/pull/9812)) +- Add `blocklist` option to prevent generating unwanted CSS ([#9812](https://github.com/tailwindlabs/tailwindcss/pull/9812)) ### Fixed From 13eb1e28fbabe40a662c7364b3a18fc9f45778fd Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 11 Nov 2022 12:14:46 -0500 Subject: [PATCH 5/6] update changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1447afc3558..320e52d8e7e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Nothing yet! + +## [3.2.4] - 2022-11-11 + ### Added - Add `blocklist` option to prevent generating unwanted CSS ([#9812](https://github.com/tailwindlabs/tailwindcss/pull/9812)) @@ -2117,7 +2121,8 @@ No release notes - Everything! -[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.3...HEAD +[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.4...HEAD +[3.2.4]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.3...v3.2.4 [3.2.3]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.2...v3.2.3 [3.2.2]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.1...v3.2.2 [3.2.1]: https://github.com/tailwindlabs/tailwindcss/compare/v3.2.0...v3.2.1 From f2f1ee9b5585d11945587f688a4c533c5287aaf7 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 11 Nov 2022 12:14:46 -0500 Subject: [PATCH 6/6] 3.2.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2bd24e4909e4..71ae8c2e1c83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "tailwindcss", - "version": "3.2.3", + "version": "3.2.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "tailwindcss", - "version": "3.2.3", + "version": "3.2.4", "license": "MIT", "dependencies": { "arg": "^5.0.2", diff --git a/package.json b/package.json index 737cdfbce574..0d36d64df136 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tailwindcss", - "version": "3.2.3", + "version": "3.2.4", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "main": "lib/index.js",