From df535b22a3eafa3984cfe2da9cf53d30ca9e9870 Mon Sep 17 00:00:00 2001 From: Sami Date: Tue, 10 Mar 2026 15:41:35 +0100 Subject: [PATCH] fix(upgrade): use v3 config content patterns when no @source is set, skip writes when content is unchanged When migrating from v3 to v4, the CSS entrypoint has no @source directive yet, leaving compiler.root as null. The fallback to '**/*' caused the tool to scan every file in the project (PHP migrations, config files, etc.) and unconditionally write them all back to disk. - Use the v3 JS config's content patterns (config.sources) as the scan scope when compiler.root is null, falling back to '**/*' only when no config sources are available - Move config lookup before the sources IIFE to avoid a TDZ error - Skip fs.writeFile when the migrated content is identical to the original --- .../src/codemods/template/migrate.ts | 8 ++++---- packages/@tailwindcss-upgrade/src/index.ts | 12 +++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate.ts b/packages/@tailwindcss-upgrade/src/codemods/template/migrate.ts index 2b39094d45ba..03cc0042cd06 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/template/migrate.ts @@ -123,8 +123,8 @@ export async function migrate(designSystem: DesignSystem, userConfig: Config | n let fullPath = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file) let contents = await fs.readFile(fullPath, 'utf-8') - await fs.writeFile( - fullPath, - await migrateContents(designSystem, userConfig, contents, extname(file)), - ) + let migrated = await migrateContents(designSystem, userConfig, contents, extname(file)) + if (migrated !== contents) { + await fs.writeFile(fullPath, migrated) + } } diff --git a/packages/@tailwindcss-upgrade/src/index.ts b/packages/@tailwindcss-upgrade/src/index.ts index 2cfbab371f5f..5868ca6d6d0b 100644 --- a/packages/@tailwindcss-upgrade/src/index.ts +++ b/packages/@tailwindcss-upgrade/src/index.ts @@ -293,6 +293,8 @@ async function run() { let designSystem = await sheet.designSystem() if (!designSystem) continue + let config = configBySheet.get(sheet) + // Figure out the source files to migrate let sources = (() => { // Disable auto source detection @@ -300,16 +302,20 @@ async function run() { return [] } - // No root specified, use the base directory + // No root specified — during a v3→v4 migration the CSS entrypoint won't + // have an @source directive yet. Use the content patterns from the v3 JS + // config if available, rather than falling back to '**/*' which would + // scan every file in the project (including migrations, vendor files, etc.). if (compiler.root === null) { + if (config?.sources && config.sources.length > 0) { + return config.sources + } return [{ base, pattern: '**/*', negated: false }] } // Use the specified root return [{ ...compiler.root, negated: false }] })().concat(compiler.sources) - - let config = configBySheet.get(sheet) let scanner = new Scanner({ sources }) let filesToMigrate = [] for (let file of scanner.files) {