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 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..85779e7b26f8 --- /dev/null +++ b/integrations/postcss/core-as-postcss-plugin.test.ts @@ -0,0 +1,58 @@ +import { expect } 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()], + } + `, + }, +} + +for (let variant of Object.keys(variantConfig)) { + 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 \`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.`, + ) + }, + ) +} 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/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 new file mode 100644 index 000000000000..fc4b691f943c --- /dev/null +++ b/packages/tailwindcss/src/index.cts @@ -0,0 +1,14 @@ +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 = postcssPlugin diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index f8514ab7136c..e1bb90ca0943 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 \`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.`, + ) +} 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', },