From 8745304788aa89309930e348452960ab41f64068 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 10 Sep 2024 11:45:47 +0200 Subject: [PATCH 1/9] Throw a useful error when `tailwindcss` is used as a PostCSS plugin --- .../postcss/core-as-postcss-plugin.test.ts | 69 +++++++++++++++++++ integrations/utils.ts | 14 +++- packages/tailwindcss/src/index.cts | 8 +++ packages/tailwindcss/src/index.ts | 6 ++ packages/tailwindcss/tsup.config.ts | 10 +-- 5 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 integrations/postcss/core-as-postcss-plugin.test.ts create mode 100644 packages/tailwindcss/src/index.cts diff --git a/integrations/postcss/core-as-postcss-plugin.test.ts b/integrations/postcss/core-as-postcss-plugin.test.ts new file mode 100644 index 000000000000..5cd3824beaba --- /dev/null +++ b/integrations/postcss/core-as-postcss-plugin.test.ts @@ -0,0 +1,69 @@ +import { afterEach, beforeEach } from 'node:test' +import { expect, vi } from 'vitest' +import { css, js, json, test } from '../utils' + +const variantConfig = { + string: { + 'postcss.config.js': js` + module.exports = { + plugins: { + tailwindcss: {}, + }, + } + `, + }, + ESM: { + 'postcss.config.mjs': js` + import tailwindcss from 'tailwindcss' + export default { + plugins: [tailwindcss()], + } + `, + }, + CJS: { + 'postcss.config.cjs': js` + let tailwindcss = require('tailwindcss') + module.exports = { + plugins: [tailwindcss()], + } + `, + }, +} + +let originalConsoleError: typeof console.error +beforeEach(() => { + originalConsoleError = console.error + console.error = vi.fn() +}) +afterEach(() => { + console.error = originalConsoleError +}) + +for (let variant of ['string', 'ESM', 'CJS']) { + test( + `can not use \`tailwindcss\` as a postcss module (${variant})`, + { + fs: { + ...variantConfig[variant], + 'package.json': json` + { + "dependencies": { + "postcss": "^8", + "postcss-cli": "^10", + "tailwindcss": "workspace:^" + } + } + `, + 'src/index.css': css`@import 'tailwindcss';`, + }, + }, + async ({ exec }) => { + expect( + exec('pnpm postcss src/index.css --output dist/out.css', undefined, { ignoreStdErr: true }), + ).rejects + .toThrowError(`It looks like you're trying to use the \`tailwindcss\` package as a PostCSS plugin. This is no longer possible since Tailwind CSS v4. + +If you want to continue to use Tailwind CSS with PostCSS, please install \`@tailwindcss/postcss\` and change your PostCSS config file.`) + }, + ) +} diff --git a/integrations/utils.ts b/integrations/utils.ts index e5f550c0531c..7530321d09fa 100644 --- a/integrations/utils.ts +++ b/integrations/utils.ts @@ -23,6 +23,10 @@ interface ChildProcessOptions { cwd?: string } +interface ExecOptions { + ignoreStdErr?: boolean +} + interface TestConfig { fs: { [filePath: string]: string @@ -30,7 +34,7 @@ interface TestConfig { } interface TestContext { root: string - exec(command: string, options?: ChildProcessOptions): Promise + exec(command: string, options?: ChildProcessOptions, execOptions?: ExecOptions): Promise spawn(command: string, options?: ChildProcessOptions): Promise getFreePort(): Promise fs: { @@ -84,7 +88,11 @@ export function test( let context = { root, - async exec(command: string, childProcessOptions: ChildProcessOptions = {}) { + async exec( + command: string, + childProcessOptions: ChildProcessOptions = {}, + execOptions: ExecOptions = {}, + ) { let cwd = childProcessOptions.cwd ?? root if (debug && cwd !== root) { let relative = path.relative(root, cwd) @@ -101,7 +109,7 @@ export function test( }, (error, stdout, stderr) => { if (error) { - console.error(stderr) + if (execOptions.ignoreStdErr !== true) console.error(stderr) reject(error) } else { resolve(stdout.toString()) diff --git a/packages/tailwindcss/src/index.cts b/packages/tailwindcss/src/index.cts new file mode 100644 index 000000000000..84e2750f1ba8 --- /dev/null +++ b/packages/tailwindcss/src/index.cts @@ -0,0 +1,8 @@ +import tailwindcss from './index.ts' + +// This file exists so that `plugin.ts` can be written one time but be +// compatible with both CJS and ESM. Without it we get a `.default` export when +// using `require` in CJS. + +// @ts-ignore +export = tailwindcss diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index f8514ab7136c..a6f97cce8b1c 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -507,3 +507,9 @@ function getVersion() { return version } } + +export default function postcssPluginWarning() { + throw new Error(`It looks like you're trying to use the \`tailwindcss\` package as a PostCSS plugin. This is no longer possible since Tailwind CSS v4. + +If you want to continue to use Tailwind CSS with PostCSS, please install \`@tailwindcss/postcss\` and change your PostCSS config file.`) +} diff --git a/packages/tailwindcss/tsup.config.ts b/packages/tailwindcss/tsup.config.ts index 25803da45289..1a8e238873b8 100644 --- a/packages/tailwindcss/tsup.config.ts +++ b/packages/tailwindcss/tsup.config.ts @@ -1,19 +1,12 @@ import { defineConfig } from 'tsup' export default defineConfig([ - { - format: ['esm', 'cjs'], - minify: true, - dts: true, - entry: { - lib: 'src/index.ts', - }, - }, { format: ['esm'], minify: true, dts: true, entry: { + lib: 'src/index.ts', plugin: 'src/plugin.ts', colors: 'src/compat/colors.ts', 'default-theme': 'src/compat/default-theme.ts', @@ -25,6 +18,7 @@ export default defineConfig([ dts: true, entry: { plugin: 'src/plugin.cts', + lib: 'src/index.cts', colors: 'src/compat/colors.cts', 'default-theme': 'src/compat/default-theme.cts', }, From 8c487d4cce6b3378b1d712701ffc607331ffb9d2 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 10 Sep 2024 11:52:13 +0200 Subject: [PATCH 2/9] Add change log --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 490f1ff4266b..0fc23b3c619e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Properly resolve `theme('someKey.DEFAULT')` when all `--some-key-*` keys have a suffix ([#14354](https://github.com/tailwindlabs/tailwindcss/pull/14354)) - Make sure tuple theme values in JS configs take precedence over `@theme default` values ([#14359](https://github.com/tailwindlabs/tailwindcss/pull/14359)) +### Changed + +- Improve the error message when the `tailwindcss` package is used as a PostCSS plugin ([#14378](https://github.com/tailwindlabs/tailwindcss/pull/14378)) + ## [4.0.0-alpha.23] - 2024-09-05 ### Added From 1e46f208c65d939fefe132f47b5c1caf419307b0 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 10 Sep 2024 11:53:02 +0200 Subject: [PATCH 3/9] Remove leftover console.error reset --- .../postcss/core-as-postcss-plugin.test.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/integrations/postcss/core-as-postcss-plugin.test.ts b/integrations/postcss/core-as-postcss-plugin.test.ts index 5cd3824beaba..5dbb24a1ab68 100644 --- a/integrations/postcss/core-as-postcss-plugin.test.ts +++ b/integrations/postcss/core-as-postcss-plugin.test.ts @@ -1,5 +1,4 @@ -import { afterEach, beforeEach } from 'node:test' -import { expect, vi } from 'vitest' +import { expect } from 'vitest' import { css, js, json, test } from '../utils' const variantConfig = { @@ -30,16 +29,7 @@ const variantConfig = { }, } -let originalConsoleError: typeof console.error -beforeEach(() => { - originalConsoleError = console.error - console.error = vi.fn() -}) -afterEach(() => { - console.error = originalConsoleError -}) - -for (let variant of ['string', 'ESM', 'CJS']) { +for (let variant of Object.keys(variantConfig)) { test( `can not use \`tailwindcss\` as a postcss module (${variant})`, { From 56a841f594c13ad2d8fbd16a5e498abe704c6fcc Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 10 Sep 2024 11:54:59 +0200 Subject: [PATCH 4/9] Unify wording in `*.cts` files --- packages/tailwindcss/src/compat/colors.cts | 4 ++++ packages/tailwindcss/src/compat/default-theme.cts | 4 ++++ packages/tailwindcss/src/index.cts | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/tailwindcss/src/compat/colors.cts b/packages/tailwindcss/src/compat/colors.cts index b903bf39beed..92cd2f66bb85 100644 --- a/packages/tailwindcss/src/compat/colors.cts +++ b/packages/tailwindcss/src/compat/colors.cts @@ -1,4 +1,8 @@ import colors from './colors.ts' +// This file exists so that `colors.ts` can be written one time but be +// compatible with both CJS and ESM. Without it we get a `.default` export when +// using `require` in CJS. + // @ts-ignore export = colors diff --git a/packages/tailwindcss/src/compat/default-theme.cts b/packages/tailwindcss/src/compat/default-theme.cts index 235d60252a5d..aab00f35743a 100644 --- a/packages/tailwindcss/src/compat/default-theme.cts +++ b/packages/tailwindcss/src/compat/default-theme.cts @@ -1,4 +1,8 @@ import defaultTheme from './default-theme.ts' +// This file exists so that `default-theme.ts` can be written one time but be +// compatible with both CJS and ESM. Without it we get a `.default` export when +// using `require` in CJS. + // @ts-ignore export = defaultTheme diff --git a/packages/tailwindcss/src/index.cts b/packages/tailwindcss/src/index.cts index 84e2750f1ba8..fc8c7de8b123 100644 --- a/packages/tailwindcss/src/index.cts +++ b/packages/tailwindcss/src/index.cts @@ -1,6 +1,6 @@ import tailwindcss from './index.ts' -// This file exists so that `plugin.ts` can be written one time but be +// This file exists so that `index.ts` can be written one time but be // compatible with both CJS and ESM. Without it we get a `.default` export when // using `require` in CJS. From e6e44c840c2597ddd1849d8b408f36de44e78539 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Wed, 11 Sep 2024 11:03:06 +0200 Subject: [PATCH 5/9] Export everything, not just the default export --- packages/tailwindcss/src/index.cts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tailwindcss/src/index.cts b/packages/tailwindcss/src/index.cts index fc8c7de8b123..53dbbc89df17 100644 --- a/packages/tailwindcss/src/index.cts +++ b/packages/tailwindcss/src/index.cts @@ -1,4 +1,4 @@ -import tailwindcss from './index.ts' +import * as tailwindcss from './index.ts' // This file exists so that `index.ts` can be written one time but be // compatible with both CJS and ESM. Without it we get a `.default` export when From 71eca3bb26da938516039b214b89536ac65abc0d Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Wed, 11 Sep 2024 11:14:54 +0200 Subject: [PATCH 6/9] Patch the default export fn to contain the rest of the API --- packages/tailwindcss/src/index.cts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/tailwindcss/src/index.cts b/packages/tailwindcss/src/index.cts index 53dbbc89df17..fc4b691f943c 100644 --- a/packages/tailwindcss/src/index.cts +++ b/packages/tailwindcss/src/index.cts @@ -1,8 +1,14 @@ -import * as tailwindcss from './index.ts' +import postcssPlugin, * as tailwindcss from './index.ts' // This file exists so that `index.ts` can be written one time but be // compatible with both CJS and ESM. Without it we get a `.default` export when // using `require` in CJS. +for (let key in tailwindcss) { + if (key === 'default') continue + // @ts-ignore + postcssPlugin[key] = tailwindcss[key] +} + // @ts-ignore -export = tailwindcss +export = postcssPlugin From c543d1d31fb13d5d1be8ba218182aa885bb8d2ee Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Wed, 11 Sep 2024 16:37:38 +0200 Subject: [PATCH 7/9] Update packages/tailwindcss/src/index.ts Co-authored-by: Adam Wathan --- packages/tailwindcss/src/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index a6f97cce8b1c..e1c5ca12951d 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -509,7 +509,5 @@ function getVersion() { } export default function postcssPluginWarning() { - throw new Error(`It looks like you're trying to use the \`tailwindcss\` package as a PostCSS plugin. This is no longer possible since Tailwind CSS v4. - -If you want to continue to use Tailwind CSS with PostCSS, please install \`@tailwindcss/postcss\` and change your PostCSS config file.`) + throw new Error(`It looks like you're trying to use \`tailwindcss\` directly as a PostCSS plugin. The PostCSS plugin has moved to a separate package, so to continue using Tailwind CSS with PostCSS you'll need to install \`@tailwindcss/postcss\` and update your PostCSS configuration.`) } From 8108134c70404ffab4653703c1e10035ff730df2 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Wed, 11 Sep 2024 16:46:22 +0200 Subject: [PATCH 8/9] Update tests to match the new wording --- integrations/postcss/core-as-postcss-plugin.test.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/integrations/postcss/core-as-postcss-plugin.test.ts b/integrations/postcss/core-as-postcss-plugin.test.ts index 5dbb24a1ab68..85779e7b26f8 100644 --- a/integrations/postcss/core-as-postcss-plugin.test.ts +++ b/integrations/postcss/core-as-postcss-plugin.test.ts @@ -50,10 +50,9 @@ for (let variant of Object.keys(variantConfig)) { async ({ exec }) => { expect( exec('pnpm postcss src/index.css --output dist/out.css', undefined, { ignoreStdErr: true }), - ).rejects - .toThrowError(`It looks like you're trying to use the \`tailwindcss\` package as a PostCSS plugin. This is no longer possible since Tailwind CSS v4. - -If you want to continue to use Tailwind CSS with PostCSS, please install \`@tailwindcss/postcss\` and change your PostCSS config file.`) + ).rejects.toThrowError( + `It looks like you're trying to use \`tailwindcss\` directly as a PostCSS plugin. The PostCSS plugin has moved to a separate package, so to continue using Tailwind CSS with PostCSS you'll need to install \`@tailwindcss/postcss\` and update your PostCSS configuration.`, + ) }, ) } From 568af8fc404389e2cb586146085426a1bb975391 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Wed, 11 Sep 2024 16:50:53 +0200 Subject: [PATCH 9/9] Make it pretty --- packages/tailwindcss/src/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index e1c5ca12951d..e1bb90ca0943 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -509,5 +509,7 @@ function getVersion() { } export default function postcssPluginWarning() { - throw new Error(`It looks like you're trying to use \`tailwindcss\` directly as a PostCSS plugin. The PostCSS plugin has moved to a separate package, so to continue using Tailwind CSS with PostCSS you'll need to install \`@tailwindcss/postcss\` and update your PostCSS configuration.`) + throw new Error( + `It looks like you're trying to use \`tailwindcss\` directly as a PostCSS plugin. The PostCSS plugin has moved to a separate package, so to continue using Tailwind CSS with PostCSS you'll need to install \`@tailwindcss/postcss\` and update your PostCSS configuration.`, + ) }