-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Migrate simple PostCSS setup #14612
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Migrate simple PostCSS setup #14612
Changes from 7 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
3f38b8b
WIP: add test
philipp-spiess 16686c2
Migrate simple PostCSS setup
philipp-spiess 3d556df
Add change log
philipp-spiess 21030c0
Add bun support
philipp-spiess 9706229
Update snapshot
philipp-spiess 7494dd8
Update change log
philipp-spiess 6ddab3f
Fix typescript issue
philipp-spiess e2f08fa
Merge remote-tracking branch 'origin/next' into feat/migrate-simple-p…
philipp-spiess acdb351
Handle postcss-import and tailwindcss/nesting removal
philipp-spiess 6069577
Handle package.json PostCSS config
philipp-spiess 4a532c7
Merge remote-tracking branch 'origin/next' into feat/migrate-simple-p…
philipp-spiess e5b2666
Update Changelog
philipp-spiess bbb0a8e
Add support for JSON based config files
philipp-spiess ffd7417
Fix test
philipp-spiess File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| import fs from 'node:fs/promises' | ||
| import path from 'node:path' | ||
| import { pkg } from './utils/packages' | ||
| import { info, success, warn } from './utils/renderer' | ||
|
|
||
| // Migrates simple PostCSS setups. This is to cover non-dynamic config files | ||
| // similar to the ones we have all over our docs: | ||
| // | ||
| // ```js | ||
| // module.exports = { | ||
| // plugins: { | ||
| // tailwindcss: {}, | ||
| // autoprefixer: {}, | ||
| // } | ||
| // } | ||
| export async function migratePostCSSConfig(base: string) { | ||
| let configPath = await detectConfigPath(base) | ||
| if (configPath === null) { | ||
| // TODO: We can look for an eventual config inside package.json | ||
| return | ||
| } | ||
|
|
||
| info(`Attempt to upgrade the PostCSS config in file: ${configPath}`) | ||
|
|
||
| let isSimpleConfig = await isSimplePostCSSConfig(base, configPath) | ||
| if (!isSimpleConfig) { | ||
| warn(`The PostCSS config contains dynamic JavaScript and can not be automatically migrated.`) | ||
| return | ||
| } | ||
|
|
||
| let didAddPostcssClient = false | ||
| let didRemoveAutoprefixer = false | ||
|
|
||
| let fullPath = path.resolve(base, configPath) | ||
| let content = await fs.readFile(fullPath, 'utf-8') | ||
| let lines = content.split('\n') | ||
| let newLines: string[] = [] | ||
| for (let line of lines) { | ||
| if (line.includes('tailwindcss:')) { | ||
| didAddPostcssClient = true | ||
| newLines.push(line.replace('tailwindcss:', `'@tailwindcss/postcss':`)) | ||
philipp-spiess marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } else if (line.includes('autoprefixer:')) { | ||
| didRemoveAutoprefixer = true | ||
| } else { | ||
| newLines.push(line) | ||
| } | ||
philipp-spiess marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| await fs.writeFile(fullPath, newLines.join('\n')) | ||
|
|
||
| if (didAddPostcssClient) { | ||
| try { | ||
| await pkg('add -D @tailwindcss/postcss@next', base) | ||
| } catch {} | ||
| } | ||
| if (didRemoveAutoprefixer) { | ||
| try { | ||
| await pkg('remove autoprefixer', base) | ||
| } catch {} | ||
| } | ||
|
|
||
| success(`PostCSS config in file ${configPath} has been upgraded.`) | ||
| } | ||
|
|
||
| const CONFIG_FILE_LOCATIONS = [ | ||
| '.postcssrc.js', | ||
| '.postcssrc.mjs', | ||
| '.postcssrc.cjs', | ||
| '.postcssrc.ts', | ||
| '.postcssrc.mts', | ||
| '.postcssrc.cts', | ||
| 'postcss.config.js', | ||
| 'postcss.config.mjs', | ||
| 'postcss.config.cjs', | ||
| 'postcss.config.ts', | ||
| 'postcss.config.mts', | ||
| 'postcss.config.cts', | ||
philipp-spiess marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ] | ||
| async function detectConfigPath(base: string): Promise<null | string> { | ||
| for (let file of CONFIG_FILE_LOCATIONS) { | ||
| let fullPath = path.resolve(base, file) | ||
| try { | ||
| await fs.access(fullPath) | ||
| return file | ||
| } catch {} | ||
| } | ||
| return null | ||
| } | ||
|
|
||
| async function isSimplePostCSSConfig(base: string, configPath: string): Promise<boolean> { | ||
| let fullPath = path.resolve(base, configPath) | ||
| let content = await fs.readFile(fullPath, 'utf-8') | ||
| return ( | ||
| content.includes('tailwindcss:') && !(content.includes('require') || content.includes('import')) | ||
philipp-spiess marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
philipp-spiess marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import { execSync } from 'node:child_process' | ||
| import fs from 'node:fs/promises' | ||
| import { dirname, resolve } from 'node:path' | ||
| import { warn } from './renderer' | ||
|
|
||
| let didWarnAboutPackageManager = false | ||
|
|
||
| export async function pkg(command: string, base: string): Promise<Buffer | void> { | ||
| let packageManager = await detectPackageManager(base) | ||
| if (!packageManager) { | ||
| if (!didWarnAboutPackageManager) { | ||
| didWarnAboutPackageManager = true | ||
| warn('Could not detect a package manager. Please manually update `tailwindcss` to v4.') | ||
| } | ||
| return | ||
| } | ||
| return execSync(`${packageManager} ${command}`, { | ||
| cwd: base, | ||
| }) | ||
philipp-spiess marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| async function detectPackageManager(base: string): Promise<null | string> { | ||
| do { | ||
| // 1. Check package.json for a `packageManager` field | ||
| let packageJsonPath = resolve(base, 'package.json') | ||
| try { | ||
| let packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8') | ||
| let packageJson = JSON.parse(packageJsonContent) | ||
| if (packageJson.packageManager) { | ||
| if (packageJson.packageManager.includes('bun')) { | ||
| return 'bun' | ||
| } | ||
| if (packageJson.packageManager.includes('yarn')) { | ||
| return 'yarn' | ||
| } | ||
philipp-spiess marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (packageJson.packageManager.includes('pnpm')) { | ||
| return 'pnpm' | ||
| } | ||
| if (packageJson.packageManager.includes('npm')) { | ||
| return 'npm' | ||
| } | ||
| } | ||
| } catch {} | ||
|
|
||
| // 2. Check for common lockfiles | ||
philipp-spiess marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| try { | ||
| await fs.access(resolve(base, 'bun.lockb')) | ||
| return 'bun' | ||
| } catch {} | ||
| try { | ||
| await fs.access(resolve(base, 'bun.lock')) | ||
| return 'bun' | ||
| } catch {} | ||
| try { | ||
| await fs.access(resolve(base, 'pnpm-lock.yaml')) | ||
| return 'pnpm' | ||
| } catch {} | ||
|
|
||
| try { | ||
| await fs.access(resolve(base, 'yarn.lock')) | ||
| return 'yarn' | ||
| } catch {} | ||
|
|
||
| try { | ||
| await fs.access(resolve(base, 'package-lock.json')) | ||
| return 'npm' | ||
| } catch {} | ||
|
|
||
| // 3. If no lockfile is found, we might be in a monorepo | ||
| base = dirname(base) | ||
| } while (true) | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.