mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Improve @tailwindcss/upgrade and pnpm workspaces support (#18065)
This PR fixes an issue where an error such as: <img width="1702" alt="image" src="https://github.com/user-attachments/assets/4e6f75c7-3182-4497-939e-96cff08c55ae" /> Will be thrown during the upgrade process. This can happen when you are using `pnpm` and your CSS file includes a `@import "tailwindcss";`. In this scenario, `tailwindcss` will be loaded from a shared `.pnpm` folder outside of the current working directory. In this case, we are also not interested in migrating _that_ file, but we also don't want the upgrade process to just crash. I didn't see an option to ignore errors like this, so wrapped it in a try/catch instead. It also fixes another issue where if you are using a pnpm workspace and run the upgrade tool from the root, then it throws you an error that you cannot add dependencies to the workspace root unless `-w` or `--workspace-root` flags are passed. For this, we disable the check entirely using the `--ignore-workspace-root-check` flag. If we always used the `--workspace-root` flag, then the dependencies would always be added to the root, regardless of where you are running the script from which is not what we want. ## Test plan Before: <img width="1816" alt="image" src="https://github.com/user-attachments/assets/78246876-3eb6-4539-a557-d3d366f1b3a3" /> After: <img width="1816" alt="image" src="https://github.com/user-attachments/assets/a65e4421-d7c5-4d83-b35d-934708543e25" /> Before: <img width="1816" alt="image" src="https://github.com/user-attachments/assets/53772661-2c4a-4212-84d9-a556a0ad320f" /> After: <img width="1816" alt="image" src="https://github.com/user-attachments/assets/5bfaf20e-34b8-44fd-9b59-e72d36738879" />
This commit is contained in:
parent
c7d368b3c4
commit
71fb9cdf59
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
|
||||
- Upgrade: Do not migrate declarations that look like candidates in `<style>` blocks ([#18057](https://github.com/tailwindlabs/tailwindcss/pull/18057))
|
||||
- Upgrade: Improve `pnpm` workspaces support ([#18065](https://github.com/tailwindlabs/tailwindcss/pull/18065))
|
||||
|
||||
## [4.1.7] - 2025-05-15
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import path from 'node:path'
|
||||
import { isRepoDirty } from '../../packages/@tailwindcss-upgrade/src/utils/git'
|
||||
import { candidate, css, html, js, json, test, ts } from '../utils'
|
||||
import { candidate, css, html, js, json, test, ts, yaml } from '../utils'
|
||||
|
||||
test(
|
||||
'error when no CSS file with @tailwind is used',
|
||||
@ -2967,6 +2968,155 @@ test(
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'upgrades can run in a pnpm workspace',
|
||||
{
|
||||
fs: {
|
||||
'package.json': json`{}`,
|
||||
'pnpm-workspace.yaml': yaml`
|
||||
#
|
||||
packages:
|
||||
- project-a
|
||||
`,
|
||||
'project-a/package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/upgrade": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'project-a/src/index.html': html`
|
||||
<!-- Migrating 'ring', 'rounded' and 'outline-none' are unsafe in v4 -> v4 migrations -->
|
||||
<div class="ring rounded outline"></div>
|
||||
|
||||
<!-- Variant order is also unsafe to change in v4 projects -->
|
||||
<div class="file:hover:flex *:hover:flex"></div>
|
||||
<div class="hover:file:flex hover:*:flex"></div>
|
||||
|
||||
<!-- These are safe to migrate: -->
|
||||
<div
|
||||
class="!flex bg-red-500/[var(--my-opacity)] [@media(pointer:fine)]:flex bg-right-bottom object-left-top"
|
||||
></div>
|
||||
`,
|
||||
'project-a/src/input.css': css`
|
||||
@import 'tailwindcss';
|
||||
|
||||
.foo {
|
||||
@apply !bg-[var(--my-color)];
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ root, exec, fs, expect }) => {
|
||||
let stdout = await exec('npx @tailwindcss/upgrade', {
|
||||
cwd: path.join(root, 'project-a'),
|
||||
})
|
||||
|
||||
expect(/Path .*? is not in cwd/.test(stdout)).toBe(false)
|
||||
|
||||
expect(await fs.dumpFiles('./project-a/src/**/*.{css,html}')).toMatchInlineSnapshot(`
|
||||
"
|
||||
--- ./project-a/src/index.html ---
|
||||
<!-- Migrating 'ring', 'rounded' and 'outline-none' are unsafe in v4 -> v4 migrations -->
|
||||
<div class="ring rounded outline"></div>
|
||||
|
||||
<!-- Variant order is also unsafe to change in v4 projects -->
|
||||
<div class="file:hover:flex *:hover:flex"></div>
|
||||
<div class="hover:file:flex hover:*:flex"></div>
|
||||
|
||||
<!-- These are safe to migrate: -->
|
||||
<div
|
||||
class="flex! bg-red-500/(--my-opacity) pointer-fine:flex bg-bottom-right object-top-left"
|
||||
></div>
|
||||
|
||||
--- ./project-a/src/input.css ---
|
||||
@import 'tailwindcss';
|
||||
|
||||
.foo {
|
||||
@apply bg-(--my-color)!;
|
||||
}
|
||||
"
|
||||
`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'upgrades can run in a pnpm workspace root',
|
||||
{
|
||||
fs: {
|
||||
'pnpm-workspace.yaml': yaml`
|
||||
#
|
||||
packages:
|
||||
- .
|
||||
`,
|
||||
'package.json': json`
|
||||
{
|
||||
"dependencies": {
|
||||
"tailwindcss": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/upgrade": "workspace:^"
|
||||
}
|
||||
}
|
||||
`,
|
||||
'src/index.html': html`
|
||||
<!-- Migrating 'ring', 'rounded' and 'outline-none' are unsafe in v4 -> v4 migrations -->
|
||||
<div class="ring rounded outline"></div>
|
||||
|
||||
<!-- Variant order is also unsafe to change in v4 projects -->
|
||||
<div class="file:hover:flex *:hover:flex"></div>
|
||||
<div class="hover:file:flex hover:*:flex"></div>
|
||||
|
||||
<!-- These are safe to migrate: -->
|
||||
<div
|
||||
class="!flex bg-red-500/[var(--my-opacity)] [@media(pointer:fine)]:flex bg-right-bottom object-left-top"
|
||||
></div>
|
||||
`,
|
||||
'src/input.css': css`
|
||||
@import 'tailwindcss';
|
||||
|
||||
.foo {
|
||||
@apply !bg-[var(--my-color)];
|
||||
}
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ exec, fs, expect }) => {
|
||||
let stdout = await exec('npx @tailwindcss/upgrade')
|
||||
|
||||
expect(stdout).not.toContain(
|
||||
'Running this command will add the dependency to the workspace root',
|
||||
)
|
||||
|
||||
expect(await fs.dumpFiles('./src/**/*.{css,html}')).toMatchInlineSnapshot(`
|
||||
"
|
||||
--- ./src/index.html ---
|
||||
<!-- Migrating 'ring', 'rounded' and 'outline-none' are unsafe in v4 -> v4 migrations -->
|
||||
<div class="ring rounded outline"></div>
|
||||
|
||||
<!-- Variant order is also unsafe to change in v4 projects -->
|
||||
<div class="file:hover:flex *:hover:flex"></div>
|
||||
<div class="hover:file:flex hover:*:flex"></div>
|
||||
|
||||
<!-- These are safe to migrate: -->
|
||||
<div
|
||||
class="flex! bg-red-500/(--my-opacity) pointer-fine:flex bg-bottom-right object-top-left"
|
||||
></div>
|
||||
|
||||
--- ./src/input.css ---
|
||||
@import 'tailwindcss';
|
||||
|
||||
.foo {
|
||||
@apply bg-(--my-color)!;
|
||||
}
|
||||
"
|
||||
`)
|
||||
},
|
||||
)
|
||||
|
||||
test(
|
||||
'upgrade <style> blocks carefully',
|
||||
{
|
||||
@ -2980,21 +3130,21 @@ test(
|
||||
}
|
||||
`,
|
||||
'src/index.vue': html`
|
||||
<template
|
||||
<template>
|
||||
<div class="!flex"></div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@reference "./input.css";
|
||||
@reference "./input.css";
|
||||
|
||||
.foo {
|
||||
@apply !bg-red-500;
|
||||
}
|
||||
.foo {
|
||||
@apply !bg-red-500;
|
||||
}
|
||||
|
||||
.bar {
|
||||
/* Do not upgrade the key: */
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.bar {
|
||||
/* Do not upgrade the key: */
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
`,
|
||||
'src/input.css': css`
|
||||
@ -3016,21 +3166,21 @@ test(
|
||||
expect(await fs.dumpFiles('./src/**/*.{css,vue}')).toMatchInlineSnapshot(`
|
||||
"
|
||||
--- ./src/index.vue ---
|
||||
<template
|
||||
<template>
|
||||
<div class="flex!"></div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@reference "./input.css";
|
||||
@reference "./input.css";
|
||||
|
||||
.foo {
|
||||
@apply !bg-red-500;
|
||||
}
|
||||
.foo {
|
||||
@apply !bg-red-500;
|
||||
}
|
||||
|
||||
.bar {
|
||||
/* Do not upgrade the key: */
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.bar {
|
||||
/* Do not upgrade the key: */
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
--- ./src/input.css ---
|
||||
|
||||
@ -12,7 +12,14 @@ export async function analyze(stylesheets: Stylesheet[]) {
|
||||
let processingQueue: (() => Promise<Result>)[] = []
|
||||
let stylesheetsByFile = new DefaultMap<string, Stylesheet | null>((file) => {
|
||||
// We don't want to process ignored files (like node_modules)
|
||||
if (isIgnored(file)) {
|
||||
try {
|
||||
if (isIgnored(file)) {
|
||||
return null
|
||||
}
|
||||
} catch {
|
||||
// If the file is not part of the current working directory (which can
|
||||
// happen if you import `tailwindcss` and it's loading a shared file from
|
||||
// pnpm) then this will throw.
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,13 @@ export function pkg(base: string) {
|
||||
args.push(SAVE_DEV[packageManager] || SAVE_DEV.default)
|
||||
}
|
||||
|
||||
// Allow running the `pnpm` command in the workspace root without
|
||||
// erroring. Can't just use `--workspace-root` because that will force
|
||||
// install dependencies in the workspace root.
|
||||
if (packageManager === 'pnpm') {
|
||||
args.push('--ignore-workspace-root-check')
|
||||
}
|
||||
|
||||
let command = `${packageManager} add ${args.join(' ')}`
|
||||
try {
|
||||
return await exec(command, { cwd: base })
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user