From db92f78b455a4241df66c6bc6ed6efc599e2348f Mon Sep 17 00:00:00 2001 From: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Date: Fri, 5 Jul 2024 12:41:38 -0400 Subject: [PATCH 1/2] Avoid over-extracting utilities from candidates with decimal values Prevent candidates like `px-1.5` from generating both the `px-1.5` class and the `px-1` class. --- src/lib/defaultExtractor.js | 28 +++++++++++++++++++++++++--- tests/default-extractor.test.js | 13 +++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 27e30fb9a621..fdcd8dd5d214 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -1,4 +1,5 @@ import * as regex from './regex' +import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly' export function defaultExtractor(context) { let patterns = Array.from(buildRegExps(context)) @@ -16,6 +17,30 @@ export function defaultExtractor(context) { } } + // Extract any subclasses from languages like Slim and Pug, eg: + // div.flex.px-5.underline + for (let result of results.slice()) { + let segments = splitAtTopLevelOnly(result, '.') + + for (let idx = 0; idx < segments.length; idx++) { + let segment = segments[idx] + if (idx >= segments.length - 1) { + results.push(segment) + continue + } + + // If the next segment is a number, discard both, for example seeing + // `px-1` and `5` means the real candidate was `px-1.5` which is already + // captured. + let next = parseInt(segments[idx + 1]) + if (isNaN(next)) { + results.push(segment) + } else { + idx++ + } + } + } + return results } } @@ -127,9 +152,6 @@ function* buildRegExps(context) { utility, ]) } - - // 5. Inner matches - yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g } // We want to capture any "special" characters diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index e4b40e1ce8e3..d99069197d60 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -476,6 +476,19 @@ test('classes in slim templates', async () => { expect(extractions).toContain('text-gray-500') }) +test("classes with fractional numeric values don't also generate the whole number utility", async () => { + const extractions = defaultExtractor(` +
Hello world!
+ `) + + expect(extractions).toContain('px-1.5') + expect(extractions).toContain('py-2.75') + expect(extractions).not.toContain('px-1') + expect(extractions).not.toContain('5') + expect(extractions).not.toContain('py-2') + expect(extractions).not.toContain('75') +}) + test('multi-word + arbitrary values + quotes', async () => { const extractions = defaultExtractor(` grid-cols-['repeat(2)'] From 1f63a4e6ac65e3e626f9e4efeff301108db8d5ea Mon Sep 17 00:00:00 2001 From: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Date: Fri, 5 Jul 2024 12:47:32 -0400 Subject: [PATCH 2/2] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a452d7bff6f..66cbea645812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Disable automatic `var()` injection for anchor properties ([#13826](https://github.com/tailwindlabs/tailwindcss/pull/13826)) - Use no value instead of `blur(0px)` for `backdrop-blur-none` and `blur-none` utilities ([#13830](https://github.com/tailwindlabs/tailwindcss/pull/13830)) - Add `.mts` and `.cts` config file detection ([#13940](https://github.com/tailwindlabs/tailwindcss/pull/13940)) +- Don't generate utilities like `px-1` unnecessarily when using utilities like `px-1.5` ([#13959](https://github.com/tailwindlabs/tailwindcss/pull/13959)) ## [3.4.4] - 2024-06-05