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 <malfait.robin@gmail.com>
This commit is contained in:
Philipp Spiess 2024-11-19 15:53:02 +01:00 committed by GitHub
parent 38c9a881ac
commit b3d1cbb72f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 81 additions and 0 deletions

View File

@ -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

View File

@ -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`
<div class="underline"></div>
`,
'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./,
)
},
)

View File

@ -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:^"
}
}

View File

@ -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

View File

@ -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<string | null> {
try {
let packageJson = localResolve(`${pkg}/package.json`, { paths: [base] })
let { version } = JSON.parse(await fs.readFile(packageJson, 'utf8'))
return version
} catch {
return null
}
}