diff --git a/CHANGELOG.md b/CHANGELOG.md index a2039b711..0e338fdc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add standalone CLI build for 64-bit Windows on ARM (`node16-win-arm64`) ([#10001](https://github.com/tailwindlabs/tailwindcss/pull/10001)) - Add `delay-0` and `duration-0` by default ([#10294](https://github.com/tailwindlabs/tailwindcss/pull/10294)) - Add logical properties support for inline direction ([#10166](https://github.com/tailwindlabs/tailwindcss/pull/10166)) +- Use `Lightning CSS` in the PostCSS Plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) ### Fixed diff --git a/integrations/postcss-cli/tests/integration.test.js b/integrations/postcss-cli/tests/integration.test.js index 929be5c50..964c57b82 100644 --- a/integrations/postcss-cli/tests/integration.test.js +++ b/integrations/postcss-cli/tests/integration.test.js @@ -222,11 +222,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/rollup-sass/tests/integration.test.js b/integrations/rollup-sass/tests/integration.test.js index 0c15ecedc..cdf9a11fb 100644 --- a/integrations/rollup-sass/tests/integration.test.js +++ b/integrations/rollup-sass/tests/integration.test.js @@ -220,11 +220,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } @@ -307,11 +305,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/rollup/tests/integration.test.js b/integrations/rollup/tests/integration.test.js index 65f813ff5..63a28bcb5 100644 --- a/integrations/rollup/tests/integration.test.js +++ b/integrations/rollup/tests/integration.test.js @@ -220,11 +220,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/tailwindcss-cli/tests/integration.test.js b/integrations/tailwindcss-cli/tests/integration.test.js index ddba060bc..42e35a895 100644 --- a/integrations/tailwindcss-cli/tests/integration.test.js +++ b/integrations/tailwindcss-cli/tests/integration.test.js @@ -472,10 +472,7 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } .font-bold { font-weight: 700; diff --git a/integrations/vite/tests/integration.test.js b/integrations/vite/tests/integration.test.js index 43a3052d8..b2d08bc27 100644 --- a/integrations/vite/tests/integration.test.js +++ b/integrations/vite/tests/integration.test.js @@ -263,11 +263,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/webpack-4/tests/integration.test.js b/integrations/webpack-4/tests/integration.test.js index 68b43b9a0..63ab3cbbf 100644 --- a/integrations/webpack-4/tests/integration.test.js +++ b/integrations/webpack-4/tests/integration.test.js @@ -227,11 +227,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/webpack-5/tests/integration.test.js b/integrations/webpack-5/tests/integration.test.js index 3eafb767a..95f3d5f5f 100644 --- a/integrations/webpack-5/tests/integration.test.js +++ b/integrations/webpack-5/tests/integration.test.js @@ -227,11 +227,9 @@ describe('watcher', () => { css` .btn { border-radius: 0.25rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/jest/customMatchers.js b/jest/customMatchers.js index 385faf7bd..1ea532f0c 100644 --- a/jest/customMatchers.js +++ b/jest/customMatchers.js @@ -1,85 +1,127 @@ const prettier = require('prettier') const { diff } = require('jest-diff') +const lightningcss = require('lightningcss') -function format(input) { +function formatPrettier(input) { return prettier.format(input, { parser: 'css', printWidth: 100, }) } +function format(input) { + try { + return lightningcss + .transform({ + filename: 'input.css', + code: Buffer.from(input), + minify: false, + targets: { chrome: 106 << 16 }, + drafts: { + nesting: true, + customMedia: true, + }, + }) + .code.toString('utf8') + } catch (err) { + try { + // Lightning CSS is pretty strict, so it will fail for `@media screen(md) {}` for example, + // in that case we can fallback to prettier since it doesn't really care. However if an + // actual syntax error is made, then we still want to show the proper error. + return formatPrettier(input.replace(/\n/g, '')) + } catch { + let lines = err.source.split('\n') + let e = new Error( + [ + 'Error formatting using Lightning CSS:', + '', + ...[ + '```css', + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + '```', + ], + ].join('\n') + ) + if (Error.captureStackTrace) { + Error.captureStackTrace(e, toMatchFormattedCss) + } + throw e + } + } +} + +function toMatchFormattedCss(received = '', argument = '') { + let options = { + comment: 'formatCSS(received) === formatCSS(argument)', + isNot: this.isNot, + promise: this.promise, + } + + let formattedReceived = format(received) + let formattedArgument = format(argument) + + let pass = formattedReceived === formattedArgument + + let message = pass + ? () => { + return ( + this.utils.matcherHint('toMatchFormattedCss', undefined, undefined, options) + + '\n\n' + + `Expected: not ${this.utils.printExpected(formattedReceived)}\n` + + `Received: ${this.utils.printReceived(formattedArgument)}` + ) + } + : () => { + let actual = formatPrettier(formattedReceived) + let expected = formatPrettier(formattedArgument) + + let diffString = diff(expected, actual, { + expand: this.expand, + }) + + return ( + this.utils.matcherHint('toMatchFormattedCss', undefined, undefined, options) + + '\n\n' + + (diffString && diffString.includes('- Expect') + ? `Difference:\n\n${diffString}` + : `Expected: ${this.utils.printExpected(expected)}\n` + + `Received: ${this.utils.printReceived(actual)}`) + ) + } + + return { actual: received, message, pass } +} + expect.extend({ // Compare two CSS strings with all whitespace removed // This is probably naive but it's fast and works well enough. - toMatchCss(received, argument) { - function stripped(str) { - return str.replace(/\s/g, '').replace(/;/g, '') - } - - const options = { - comment: 'stripped(received) === stripped(argument)', - isNot: this.isNot, - promise: this.promise, - } - - const pass = stripped(received) === stripped(argument) - - const message = pass - ? () => { - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - `Expected: not ${this.utils.printExpected(format(received))}\n` + - `Received: ${this.utils.printReceived(format(argument))}` - ) - } - : () => { - const actual = format(received) - const expected = format(argument) - - const diffString = diff(expected, actual, { - expand: this.expand, - }) - - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - (diffString && diffString.includes('- Expect') - ? `Difference:\n\n${diffString}` - : `Expected: ${this.utils.printExpected(expected)}\n` + - `Received: ${this.utils.printReceived(actual)}`) - ) - } - - return { actual: received, message, pass } - }, + toMatchCss: toMatchFormattedCss, + toMatchFormattedCss: toMatchFormattedCss, toIncludeCss(received, argument) { - function stripped(str) { - return str.replace('/* prettier-ignore */', '').replace(/\s/g, '').replace(/;/g, '') - } - - const options = { + let options = { comment: 'stripped(received).includes(stripped(argument))', isNot: this.isNot, promise: this.promise, } - const pass = stripped(received).includes(stripped(argument)) + let pass = format(received).includes(format(argument)) - const message = pass + let message = pass ? () => { return ( this.utils.matcherHint('toIncludeCss', undefined, undefined, options) + '\n\n' + - `Expected: not ${this.utils.printExpected(format(received))}\n` + - `Received: ${this.utils.printReceived(format(argument))}` + `Expected: not ${this.utils.printExpected(formatPrettier(received))}\n` + + `Received: ${this.utils.printReceived(formatPrettier(argument))}` ) } : () => { - const actual = format(received) - const expected = format(argument) + let actual = formatPrettier(received) + let expected = formatPrettier(argument) - const diffString = diff(expected, actual, { + let diffString = diff(expected, actual, { expand: this.expand, }) @@ -96,55 +138,3 @@ expect.extend({ return { actual: received, message, pass } }, }) - -expect.extend({ - // Compare two CSS strings with all whitespace removed - // This is probably naive but it's fast and works well enough. - toMatchFormattedCss(received = '', argument = '') { - function format(input) { - return prettier.format(input.replace(/\n/g, ''), { - parser: 'css', - printWidth: 100, - }) - } - const options = { - comment: 'stripped(received) === stripped(argument)', - isNot: this.isNot, - promise: this.promise, - } - - let formattedReceived = format(received) - let formattedArgument = format(argument) - - const pass = formattedReceived === formattedArgument - - const message = pass - ? () => { - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - `Expected: not ${this.utils.printExpected(formattedReceived)}\n` + - `Received: ${this.utils.printReceived(formattedArgument)}` - ) - } - : () => { - const actual = formattedReceived - const expected = formattedArgument - - const diffString = diff(expected, actual, { - expand: this.expand, - }) - - return ( - this.utils.matcherHint('toMatchCss', undefined, undefined, options) + - '\n\n' + - (diffString && diffString.includes('- Expect') - ? `Difference:\n\n${diffString}` - : `Expected: ${this.utils.printExpected(expected)}\n` + - `Received: ${this.utils.printReceived(actual)}`) - ) - } - - return { actual: received, message, pass } - }, -}) diff --git a/package-lock.json b/package-lock.json index 2bd976cbf..1bec10384 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "lightningcss": "^1.17.1", + "lightningcss": "^1.18.0", "lilconfig": "^2.0.6", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -25284,7 +25284,7 @@ "is-glob": "^4.0.3", "jest": "^28.1.3", "jest-diff": "^28.1.3", - "lightningcss": "^1.17.1", + "lightningcss": "^1.18.0", "lilconfig": "^2.0.6", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", diff --git a/package-lock.stable.json b/package-lock.stable.json index ff0e0dcf5..6c40c1957 100644 --- a/package-lock.stable.json +++ b/package-lock.stable.json @@ -44,6 +44,7 @@ "@swc/jest": "0.2.24", "@swc/register": "0.1.10", "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", "concurrently": "^7.5.0", "cssnano": "^5.1.14", "esbuild": "^0.16.10", @@ -52,6 +53,7 @@ "eslint-plugin-prettier": "^4.2.1", "jest": "^28.1.3", "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", "prettier": "^2.8.1", "rimraf": "^3.0.0", "source-map-js": "^1.0.2", @@ -3518,6 +3520,18 @@ "version": "1.0.0", "license": "MIT" }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "dev": true, @@ -5876,6 +5890,192 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", + "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "dev": true, + "dependencies": { + "detect-libc": "^1.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.18.0", + "lightningcss-darwin-x64": "1.18.0", + "lightningcss-linux-arm-gnueabihf": "1.18.0", + "lightningcss-linux-arm64-gnu": "1.18.0", + "lightningcss-linux-arm64-musl": "1.18.0", + "lightningcss-linux-x64-gnu": "1.18.0", + "lightningcss-linux-x64-musl": "1.18.0", + "lightningcss-win32-x64-msvc": "1.18.0" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", + "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", + "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", + "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", + "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", + "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", + "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", + "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lilconfig": { "version": "2.0.6", "license": "MIT", @@ -10238,6 +10438,12 @@ "defined": { "version": "1.0.0" }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true + }, "detect-newline": { "version": "3.1.0", "dev": true @@ -11842,6 +12048,79 @@ } } }, + "lightningcss": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", + "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3", + "lightningcss-darwin-arm64": "1.18.0", + "lightningcss-darwin-x64": "1.18.0", + "lightningcss-linux-arm-gnueabihf": "1.18.0", + "lightningcss-linux-arm64-gnu": "1.18.0", + "lightningcss-linux-arm64-musl": "1.18.0", + "lightningcss-linux-x64-gnu": "1.18.0", + "lightningcss-linux-x64-musl": "1.18.0", + "lightningcss-win32-x64-msvc": "1.18.0" + } + }, + "lightningcss-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "dev": true, + "optional": true + }, + "lightningcss-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", + "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm-gnueabihf": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", + "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", + "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "dev": true, + "optional": true + }, + "lightningcss-linux-arm64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", + "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "dev": true, + "optional": true + }, + "lightningcss-linux-x64-gnu": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", + "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "dev": true, + "optional": true + }, + "lightningcss-linux-x64-musl": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", + "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "dev": true, + "optional": true + }, + "lightningcss-win32-x64-msvc": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", + "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "dev": true, + "optional": true + }, "lilconfig": { "version": "2.0.6" }, diff --git a/package.json b/package.json index 14a5d5977..0a4cd90e1 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "lightningcss": "^1.17.1", + "lightningcss": "^1.18.0", "lilconfig": "^2.0.6", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", diff --git a/package.stable.json b/package.stable.json index 15eefa949..7161e4c54 100644 --- a/package.stable.json +++ b/package.stable.json @@ -52,6 +52,7 @@ "@swc/jest": "0.2.24", "@swc/register": "0.1.10", "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", "concurrently": "^7.5.0", "cssnano": "^5.1.14", "esbuild": "^0.16.10", @@ -60,6 +61,7 @@ "eslint-plugin-prettier": "^4.2.1", "jest": "^28.1.3", "jest-diff": "^28.1.3", + "lightningcss": "^1.18.0", "prettier": "^2.8.1", "rimraf": "^3.0.0", "source-map-js": "^1.0.2", @@ -84,7 +86,7 @@ "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.21", + "postcss": "^8.0.9", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", @@ -104,6 +106,9 @@ "/standalone-cli/", "\\.test\\.skip\\.js$" ], + "transformIgnorePatterns": [ + "node_modules/(?!lightningcss)" + ], "transform": { "\\.js$": "@swc/jest", "\\.ts$": "@swc/jest" diff --git a/src/plugin.js b/src/plugin.js index 7dc41c317..4fa8ce757 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -34,6 +34,66 @@ module.exports = function tailwindcss(configOrPath) { processTailwindFeatures(context)(root, result) }, + env.OXIDE && + function lightningCssPlugin(_root, result) { + let postcss = require('postcss') + let lightningcss = require('lightningcss') + let browserslist = require('browserslist') + + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: + typeof process !== 'undefined' && process.env.JEST_WORKER_ID + ? { chrome: 106 << 16 } + : lightningcss.browserslistToTargets( + browserslist(require('../package.json').browserslist) + ), + + drafts: { + nesting: true, + customMedia: true, + }, + }) + + result.map = Object.assign(result.map ?? {}, { + toJSON() { + return transformed.map.toJSON() + }, + toString() { + return transformed.map.toString() + }, + }) + + result.root = postcss.parse(transformed.code.toString('utf8')) + } catch (err) { + if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { + let lines = err.source.split('\n') + err = new Error( + [ + 'Error formatting using Lightning CSS:', + '', + ...[ + '```css', + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + '```', + ], + ].join('\n') + ) + } + + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin) + } + throw err + } + }, env.DEBUG && function (root) { console.timeEnd('JIT TOTAL') diff --git a/tests/arbitrary-values.oxide.test.css b/tests/arbitrary-values.oxide.test.css index 34bb93bc6..326149b90 100644 --- a/tests/arbitrary-values.oxide.test.css +++ b/tests/arbitrary-values.oxide.test.css @@ -182,20 +182,16 @@ width: var(--width, calc(100% + 1rem)); } .w-\[\{\{\}\}\] { - width: { - { - } - } + width: {{} }; } .w-\[\{\}\] { - width: { - } + width: {}; } .min-w-\[3\.23rem\] { min-width: 3.23rem; } .min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] { - min-width: calc(1 - ((12 - 3) * 0.5)); + min-width: -3.5px; } .min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] { min-width: calc(1 - (var(--something) * 0.5)); @@ -420,7 +416,7 @@ scroll-padding-top: var(--scroll-padding); } .list-\[\'\\1f44d\'\] { - list-style-type: '\1F44D'; + list-style-type: '\1f44d'; } .list-\[var\(--value\)\] { list-style-type: var(--value); @@ -685,13 +681,7 @@ .bg-\[image\:var\(--value\)\2c var\(--value\)\] { background-image: var(--value), var(--value); } -.bg-\[linear-gradient\(\#eee\2c - \#fff\)\2c - conic-gradient\(red\2c - orange\2c - yellow\2c - green\2c - blue\)\] { +.bg-\[linear-gradient\(\#eee\,\#fff\)\,conic-gradient\(red\,orange\,yellow\,green\,blue\)\] { background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, yellow, green, blue); } .bg-\[linear-gradient\(\#eee\2c \#fff\)\] { diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index 3098a954a..e446fcab3 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -182,14 +182,10 @@ width: var(--width, calc(100% + 1rem)); } .w-\[\{\{\}\}\] { - width: { - { - } - } + width: {{} }; } .w-\[\{\}\] { - width: { - } + width: {}; } .min-w-\[3\.23rem\] { min-width: 3.23rem; @@ -420,7 +416,7 @@ scroll-padding-top: var(--scroll-padding); } .list-\[\'\\1f44d\'\] { - list-style-type: '\1F44D'; + list-style-type: '\1f44d'; } .list-\[var\(--value\)\] { list-style-type: var(--value); @@ -685,13 +681,7 @@ .bg-\[image\:var\(--value\)\2c var\(--value\)\] { background-image: var(--value), var(--value); } -.bg-\[linear-gradient\(\#eee\2c - \#fff\)\2c - conic-gradient\(red\2c - orange\2c - yellow\2c - green\2c - blue\)\] { +.bg-\[linear-gradient\(\#eee\,\#fff\)\,conic-gradient\(red\,orange\,yellow\,green\,blue\)\] { background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, yellow, green, blue); } .bg-\[linear-gradient\(\#eee\2c \#fff\)\] { diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html index 56a9d3ae6..047dae8ca 100644 --- a/tests/arbitrary-values.test.html +++ b/tests/arbitrary-values.test.html @@ -123,7 +123,7 @@
- + diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index af29b4927..1b7c08290 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -644,15 +644,15 @@ crosscheck(({ stable, oxide }) => {