From 0971ee1cff1aed169ec87c885008f682f2263c64 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 1 Sep 2022 12:06:43 -0400 Subject: [PATCH 1/4] Allow negating utilities using min/max/clamp --- src/util/negateValue.js | 12 ++++++++++-- tests/negative-prefix.test.js | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/util/negateValue.js b/src/util/negateValue.js index 105915e03..8dfbfa358 100644 --- a/src/util/negateValue.js +++ b/src/util/negateValue.js @@ -10,7 +10,15 @@ export default function (value) { return value.replace(/^[+-]?/, (sign) => (sign === '-' ? '' : '-')) } - if (value.includes('var(') || value.includes('calc(')) { - return `calc(${value} * -1)` + // What functions we support negating numeric values for + // var() isn't inherently a numeric function but we support it anyway + // The trigonometric functions are omitted because you'll need to use calc(…) with them _anyway_ + // to produce generally useful results and that will be covered already + let numericFunctions = ['var', 'calc', 'min', 'max', 'clamp'] + + for (const fn of numericFunctions) { + if (value.includes(`${fn}(`)) { + return `calc(${value} * -1)` + } } } diff --git a/tests/negative-prefix.test.js b/tests/negative-prefix.test.js index 0b232d073..a37c55ab9 100644 --- a/tests/negative-prefix.test.js +++ b/tests/negative-prefix.test.js @@ -146,6 +146,42 @@ test('a value that includes a calc', () => { }) }) +test('a value that includes min/max/clamp functions', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 'min': 'min(100vmin, 3rem)', + 'max': 'max(100vmax, 3rem)', + 'clamp': 'clamp(1rem, 100vh, 3rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .mt-min { + margin-top: min(100vmin, 3rem); + } + .-mt-min { + margin-top: calc(min(100vmin, 3rem) * -1); + } + .mt-max { + margin-top: max(100vmax, 3rem); + } + .-mt-max { + margin-top: calc(max(100vmax, 3rem) * -1); + } + .mt-clamp { + margin-top: clamp(1rem, 100vh, 3rem); + } + .-mt-clamp { + margin-top: calc(clamp(1rem, 100vh, 3rem) * -1); + } + `) + }) +}) + test('a keyword value', () => { let config = { content: [{ raw: html`
` }], From 97f93639f476eed1372027a760bcbc9825f53d84 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 2 Sep 2022 09:34:57 -0400 Subject: [PATCH 2/4] Add prototype using `@parcel/css` for minification --- package.json | 4 +- src/cli-peer-dependencies.js | 4 +- src/cli.js | 85 ++++++++++++++++++++++++++---------- 3 files changed, 66 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 0efcb12f0..2d1039285 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "scripts": { "preswcify": "npm run generate && rimraf lib", "swcify": "swc src --out-dir lib --copy-files", - "postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js", + "postswcify": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", "rebuild-fixtures": "npm run swcify && node -r @swc/register scripts/rebuildFixtures.js", "prepublishOnly": "npm install --force && npm run swcify", "style": "eslint .", @@ -42,12 +42,12 @@ "*.js" ], "devDependencies": { + "@parcel/css": "^1.11.2", "@swc/cli": "^0.1.57", "@swc/core": "^1.2.244", "@swc/jest": "^0.2.22", "@swc/register": "^0.1.10", "autoprefixer": "^10.4.8", - "cssnano": "^5.1.13", "esbuild": "^0.14.54", "eslint": "^8.21.0", "eslint-config-prettier": "^8.5.0", diff --git a/src/cli-peer-dependencies.js b/src/cli-peer-dependencies.js index 6b9f986aa..5324ec572 100644 --- a/src/cli-peer-dependencies.js +++ b/src/cli-peer-dependencies.js @@ -10,6 +10,6 @@ export function lazyAutoprefixer() { return require('autoprefixer') } -export function lazyCssnano() { - return require('cssnano') +export function lazyParcelCss() { + return require('@parcel/css') } diff --git a/src/cli.js b/src/cli.js index 52c3d08f6..bf3328b21 100644 --- a/src/cli.js +++ b/src/cli.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { lazyPostcss, lazyPostcssImport, lazyCssnano, lazyAutoprefixer } from '../peers/index.js' +import { lazyPostcss, lazyPostcssImport, lazyParcelCss, lazyAutoprefixer } from '../peers/index.js' import chokidar from 'chokidar' import path from 'path' @@ -353,6 +353,65 @@ if (args['--help']) { run() +/// --- + +/** @type {import('@parcel/css')} */ +let parcelCss + +/** @returns {import('@parcel/css')} */ +function loadParcelCss() { + if (parcelCss) { + return parcelCss + } + + // Try to load a local version first + try { + return parcelCss = require('@parcel/css') + } catch {} + + return parcelCss = lazyParcelCss() +} + +/** + * + * @param {boolean} shouldMinify + * @param {import('postcss').Result} result + * @returns {import('postcss').Result} + */ +async function minifyCss(shouldMinify, result) { + if (! shouldMinify) { + return result + } + + let css = loadParcelCss() + let transformed + + try { + transformed = css.transform({ + filename: result.opts.from || 'input.css', + code: Buffer.from(result.css, 'utf-8'), + minify: true, + sourceMap: true, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + }) + } catch (err) { + console.error("Unable to minify CSS. Using unminified version instead.") + console.error(err) + + return result + } + + return Object.assign(result, { + css: transformed.code.toString('utf8'), + map: result.map ? Object.assign(result.map, { + toString() { + return transformed.map.toString() + } + }) : result.map, + }) +} + // --- function init() { @@ -626,17 +685,6 @@ async function build() { return lazyAutoprefixer() })(), - args['--minify'] && - (() => { - let options = { preset: ['default', { cssDeclarationSorter: false }] } - - // Try to load a local `cssnano` version first - try { - return require('cssnano') - } catch {} - - return lazyCssnano()(options) - })(), ].filter(Boolean) let postcss = loadPostcss() @@ -647,6 +695,7 @@ async function build() { return Promise.resolve() .then(() => (output ? fs.promises.mkdir(path.dirname(output), { recursive: true }) : null)) .then(() => processor.process(css, { ...postcssOptions, from: input, to: output })) + .then((result) => minifyCss(!!args['--minify'], result)) .then((result) => { if (!output) { return process.stdout.write(result.css) @@ -728,17 +777,6 @@ async function build() { return lazyAutoprefixer() })(), - args['--minify'] && - (() => { - let options = { preset: ['default', { cssDeclarationSorter: false }] } - - // Try to load a local `cssnano` version first - try { - return require('cssnano') - } catch {} - - return lazyCssnano()(options) - })(), ].filter(Boolean) async function rebuild(config) { @@ -785,6 +823,7 @@ async function build() { output ? fs.promises.mkdir(path.dirname(output), { recursive: true }) : null ) .then(() => processor.process(css, { from: input, to: output })) + .then((result) => minifyCss(!!args['--minify'], result)) .then(async (result) => { for (let message of result.messages) { if (message.type === 'dependency') { From 494d5c970907f9ae0a5262d12e318222425f9746 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 11 Jul 2022 12:44:18 -0400 Subject: [PATCH 3/4] Update lockfile --- .../tailwindcss-cli/package-lock.json | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/integrations/tailwindcss-cli/package-lock.json b/integrations/tailwindcss-cli/package-lock.json index e36028945..1bfff83a7 100644 --- a/integrations/tailwindcss-cli/package-lock.json +++ b/integrations/tailwindcss-cli/package-lock.json @@ -12,13 +12,13 @@ } }, "../..": { - "version": "3.0.24", + "version": "3.1.5", "license": "MIT", "dependencies": { - "arg": "^5.0.1", + "arg": "^5.0.2", "chokidar": "^3.5.3", "color-name": "^1.1.4", - "detective": "^5.2.0", + "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.2.11", @@ -36,26 +36,26 @@ "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", - "resolve": "^1.22.0" + "resolve": "^1.22.1" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" }, "devDependencies": { + "@parcel/css": "^1.11.2", "@swc/cli": "^0.1.57", - "@swc/core": "^1.2.160", + "@swc/core": "^1.2.196", "@swc/jest": "^0.2.21", "@swc/register": "^0.1.10", "autoprefixer": "^10.4.7", - "cssnano": "^5.1.9", - "esbuild": "^0.14.39", - "eslint": "^8.15.0", + "esbuild": "^0.14.48", + "eslint": "^8.18.0", "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.0.0", - "jest": "^28.0.3", - "jest-diff": "^28.1.0", - "prettier": "^2.6.2", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.1.2", + "jest-diff": "^28.1.1", + "prettier": "^2.7.1", "prettier-plugin-tailwindcss": "^0.1.11", "rimraf": "^3.0.0", "source-map-js": "^1.0.2" @@ -76,27 +76,27 @@ "tailwindcss": { "version": "file:../..", "requires": { + "@parcel/css": "^1.11.2", "@swc/cli": "^0.1.57", - "@swc/core": "^1.2.160", + "@swc/core": "^1.2.196", "@swc/jest": "^0.2.21", "@swc/register": "^0.1.10", - "arg": "^5.0.1", + "arg": "^5.0.2", "autoprefixer": "^10.4.7", "chokidar": "^3.5.3", "color-name": "^1.1.4", - "cssnano": "^5.1.9", - "detective": "^5.2.0", + "detective": "^5.2.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "esbuild": "^0.14.39", - "eslint": "^8.15.0", + "esbuild": "^0.14.48", + "eslint": "^8.18.0", "eslint-config-prettier": "^8.5.0", - "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-prettier": "^4.2.1", "fast-glob": "^3.2.11", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jest": "^28.0.3", - "jest-diff": "^28.1.0", + "jest": "^28.1.2", + "jest-diff": "^28.1.1", "lilconfig": "^2.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", @@ -108,10 +108,10 @@ "postcss-nested": "5.0.6", "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", - "prettier": "^2.6.2", + "prettier": "^2.7.1", "prettier-plugin-tailwindcss": "^0.1.11", "quick-lru": "^5.1.1", - "resolve": "^1.22.0", + "resolve": "^1.22.1", "rimraf": "^3.0.0", "source-map-js": "^1.0.2" } From 440954a163d59a0b5d701849b0933131a060ec87 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 11 Jul 2022 12:52:12 -0400 Subject: [PATCH 4/4] Add test --- integrations/tailwindcss-cli/tests/cli.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/integrations/tailwindcss-cli/tests/cli.test.js b/integrations/tailwindcss-cli/tests/cli.test.js index 9ebcd3012..a3e277ae5 100644 --- a/integrations/tailwindcss-cli/tests/cli.test.js +++ b/integrations/tailwindcss-cli/tests/cli.test.js @@ -96,6 +96,21 @@ describe('Build command', () => { expect(withoutMinify.length).toBeGreaterThan(withMinify.length) }) + test('--minify applies @parcel/css optimizations', async () => { + await writeInputFile('index.html', html`
`) + await writeInputFile('index.css', css` + .text-teal { + color: hsl(calc(360deg / 2) 50% 50%); + } + `) + + await $(`${EXECUTABLE} --input ./src/index.css --output ./dist/main.css --minify`) + + let withMinify = await readOutputFile('main.css') + + expect(withMinify).toEqual(css`.text-teal{color:#40bfbf}`) + }) + test('--no-autoprefixer', async () => { await writeInputFile('index.html', html`
`)