From b3d1cbb72ff7d223f6160745b889f71b3cae489d Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 19 Nov 2024 15:53:02 +0100 Subject: [PATCH] Upgrade: Error when project is already using Tailwind CSS v4 (#15015) In some local testing we ran the `@tailwindcss/upgrade` command twice in a row. It would be great to get some feedback that this is not working, so this PR now checks if it can resolve the installed version of `tailwindcss` and if it can, it requires it to be < 4 (you can bypass this check with `--force`). --------- Co-authored-by: Robin Malfait --- CHANGELOG.md | 1 + integrations/upgrade/index.test.ts | 35 +++++++++++++++++++ integrations/upgrade/js-config.test.ts | 16 +++++++++ packages/@tailwindcss-upgrade/src/index.ts | 11 ++++++ .../src/utils/package-version.ts | 18 ++++++++++ 5 files changed, 81 insertions(+) create mode 100644 packages/@tailwindcss-upgrade/src/utils/package-version.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index dc3bfae0a..eb5d70dd6 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 - Allow `addUtilities()` and `addComponents()` to work with child combinators and other complex selectors ([#15029](https://github.com/tailwindlabs/tailwindcss/pull/15029)) - _Upgrade (experimental)_: Migrate `[&>*]` to the `*` variant ([#15022](https://github.com/tailwindlabs/tailwindcss/pull/15022)) - _Upgrade (experimental)_: Migrate `[&_*]` to the `**` variant ([#15022](https://github.com/tailwindlabs/tailwindcss/pull/15022)) +- _Upgrade (experimental)_: Warn when trying to migrating a project that is not on Tailwind CSS v3 ([#15015](https://github.com/tailwindlabs/tailwindcss/pull/15015)) ### Fixed diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index 32fcd1b83..1e39992b9 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -954,6 +954,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -2463,3 +2464,37 @@ test( `) }, ) + +test( + 'requires Tailwind v3 before attempting an upgrade', + { + fs: { + 'package.json': json` + { + "dependencies": { + "tailwindcss": "workspace:^", + "@tailwindcss/upgrade": "workspace:^" + } + } + `, + 'tailwind.config.ts': js` export default {} `, + 'src/index.html': html` +
+ `, + 'src/index.css': css` + @tailwind base; + @tailwind components; + @tailwind utilities; + `, + }, + }, + async ({ exec }) => { + let output = await exec('npx @tailwindcss/upgrade', {}, { ignoreStdErr: true }).catch((e) => + e.toString(), + ) + + expect(output).toMatch( + /Tailwind CSS v.* found. The migration tool can only be run on v3 projects./, + ) + }, +) diff --git a/integrations/upgrade/js-config.test.ts b/integrations/upgrade/js-config.test.ts index 6cd862cfd..85c0150dc 100644 --- a/integrations/upgrade/js-config.test.ts +++ b/integrations/upgrade/js-config.test.ts @@ -9,6 +9,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -297,6 +298,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/typography": "^0.5.15", "@tailwindcss/upgrade": "workspace:^" } @@ -404,6 +406,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -485,6 +488,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -572,6 +576,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -640,6 +645,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -718,6 +724,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -838,6 +845,7 @@ test( 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -915,6 +923,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -973,6 +982,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -1034,6 +1044,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -1077,6 +1088,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -1136,6 +1148,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -1219,6 +1232,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -1330,6 +1344,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } @@ -1443,6 +1458,7 @@ describe('border compatibility', () => { 'package.json': json` { "dependencies": { + "tailwindcss": "^3", "@tailwindcss/upgrade": "workspace:^" } } diff --git a/packages/@tailwindcss-upgrade/src/index.ts b/packages/@tailwindcss-upgrade/src/index.ts index 15d11b733..945b48ab4 100644 --- a/packages/@tailwindcss-upgrade/src/index.ts +++ b/packages/@tailwindcss-upgrade/src/index.ts @@ -22,6 +22,7 @@ import { prepareConfig } from './template/prepare-config' import { args, type Arg } from './utils/args' import { isRepoDirty } from './utils/git' import { hoistStaticGlobParts } from './utils/hoist-static-glob-parts' +import { getPackageVersion } from './utils/package-version' import { pkg } from './utils/packages' import { eprintln, error, header, highlight, info, relative, success } from './utils/renderer' @@ -50,6 +51,7 @@ async function run() { let cleanup: (() => void)[] = [] if (!flags['--force']) { + // Require a clean git directory if (isRepoDirty()) { error('Git directory is not clean. Please stash or commit your changes before migrating.') info( @@ -59,6 +61,15 @@ async function run() { } } + // Require an installed `tailwindcss` version < 4 + let tailwindVersion = await getPackageVersion('tailwindcss', base) + if (tailwindVersion && Number(tailwindVersion.split('.')[0]) !== 3) { + error( + `Tailwind CSS v${tailwindVersion} found. The migration tool can only be run on v3 projects.`, + ) + process.exit(1) + } + { // Stylesheet migrations diff --git a/packages/@tailwindcss-upgrade/src/utils/package-version.ts b/packages/@tailwindcss-upgrade/src/utils/package-version.ts new file mode 100644 index 000000000..b41ad6fb0 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/utils/package-version.ts @@ -0,0 +1,18 @@ +import fs from 'node:fs/promises' +import { createRequire } from 'node:module' + +const localResolve = createRequire(import.meta.url).resolve + +/** + * Resolves the version string of an npm dependency installed in the based + * directory. + */ +export async function getPackageVersion(pkg: string, base: string): Promise { + try { + let packageJson = localResolve(`${pkg}/package.json`, { paths: [base] }) + let { version } = JSON.parse(await fs.readFile(packageJson, 'utf8')) + return version + } catch { + return null + } +}