diff --git a/integrations/tailwindcss-cli/tests/cli.test.js b/integrations/tailwindcss-cli/tests/cli.test.js index e23b6c36d..7c8200225 100644 --- a/integrations/tailwindcss-cli/tests/cli.test.js +++ b/integrations/tailwindcss-cli/tests/cli.test.js @@ -96,6 +96,24 @@ describe('Build command', () => { expect(withoutMinify.length).toBeGreaterThan(withMinify.length) }) + test('--minify applies Lightning 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(`.text-teal{color:#40bfbf}`) + }) + test('--no-autoprefixer', async () => { await writeInputFile('index.html', html`
`) diff --git a/package.json b/package.json index 5b449cc86..59f147669 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 .", @@ -47,13 +47,13 @@ "@swc/jest": "^0.2.22", "@swc/register": "^0.1.10", "autoprefixer": "^10.4.8", - "cssnano": "^5.1.13", "esbuild": "^0.15.7", "eslint": "^8.23.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-prettier": "^4.2.1", "jest": "^28.1.3", "jest-diff": "^28.1.3", + "lightningcss": "^1.11.2", "prettier": "^2.7.1", "prettier-plugin-tailwindcss": "^0.1.13", "rimraf": "^3.0.0", diff --git a/src/cli-peer-dependencies.js b/src/cli-peer-dependencies.js index 6b9f986aa..4c9c6c339 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 lazyLightningCss() { + return require('lightningcss') } diff --git a/src/cli.js b/src/cli.js index c9d6ab7c0..657321bb7 100644 --- a/src/cli.js +++ b/src/cli.js @@ -1,6 +1,11 @@ #!/usr/bin/env node -import { lazyPostcss, lazyPostcssImport, lazyCssnano, lazyAutoprefixer } from '../peers/index.js' +import { + lazyPostcss, + lazyPostcssImport, + lazyLightningCss, + lazyAutoprefixer, +} from '../peers/index.js' import chokidar from 'chokidar' import path from 'path' @@ -359,6 +364,67 @@ if (args['--help']) { run() +/// --- + +/** @type {import('lightningcss')} */ +let lightningCss + +/** @returns {import('lightningcss')} */ +function loadLightningCss() { + if (lightningCss) { + return lightningCss + } + + // Try to load a local version first + try { + return (lightningCss = require('lightningcss')) + } catch {} + + return (lightningCss = lazyLightningCss()) +} + +/** + * + * @param {boolean} shouldMinify + * @param {import('postcss').Result} result + * @returns {import('postcss').Result} + */ +async function minifyCss(shouldMinify, result) { + if (!shouldMinify) { + return result + } + + let css = loadLightningCss() + 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() { @@ -633,17 +699,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() @@ -654,6 +709,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) @@ -735,17 +791,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) { @@ -792,6 +837,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') {