mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
content rules from the JS config that are also covered by the automatic source detection should not be migrated to CSS (#14714)
This PR changes the migration of `content` rules in the JS config to CSS codemods.
When a `content` rule is processed which matches files that are _also matched by the automatic content discovery in v4_, we do not need to emit CSS for that rule.
Take, for example this v3 configuration file:
```ts
import { type Config } from 'tailwindcss'
module.exports = {
content: [
'./src/**/*.{html,js}',
'./node_modules/my-external-lib/**/*.{html}'
],
} satisfies Config
```
Provided the base directories match up, the first rule will also be covered by the automatic content discovery in v4 and thus we only need to convert the second rule to CSS:
```css
@import "tailwindcss";
@source '../node_modules/my-external-lib/**/*.{html}';
```
This commit is contained in:
parent
3da49f9837
commit
5c1bfd3a91
@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- _Upgrade (experimental)_: Migrate `plugins` with options to CSS ([#14700](https://github.com/tailwindlabs/tailwindcss/pull/14700))
|
||||
|
||||
### Changed
|
||||
|
||||
- _Upgrade (experimental)_: Don't create `@source` rules for `content` paths that are already covered by automatic source detection ([#14714](https://github.com/tailwindlabs/tailwindcss/pull/14714))
|
||||
|
||||
## [4.0.0-alpha.28] - 2024-10-17
|
||||
|
||||
### Added
|
||||
|
||||
@ -40,8 +40,6 @@ test(
|
||||
|
||||
--- ./src/input.css ---
|
||||
@import 'tailwindcss';
|
||||
|
||||
@source './**/*.{html,js}';
|
||||
"
|
||||
`)
|
||||
|
||||
@ -100,8 +98,6 @@ test(
|
||||
--- ./src/input.css ---
|
||||
@import 'tailwindcss' prefix(tw);
|
||||
|
||||
@source './**/*.{html,js}';
|
||||
|
||||
.btn {
|
||||
@apply tw:rounded-md! tw:px-2 tw:py-1 tw:bg-blue-500 tw:text-white;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { expect } from 'vitest'
|
||||
import { css, json, test, ts } from '../utils'
|
||||
import { css, html, json, test, ts } from '../utils'
|
||||
|
||||
test(
|
||||
`upgrade JS config files with flat theme values, darkMode, and content fields`,
|
||||
@ -18,7 +18,7 @@ test(
|
||||
|
||||
module.exports = {
|
||||
darkMode: 'selector',
|
||||
content: ['./src/**/*.{html,js}', './my-app/**/*.{html,js}'],
|
||||
content: ['./src/**/*.{html,js}', './node_modules/my-external-lib/**/*.{html}'],
|
||||
theme: {
|
||||
boxShadow: {
|
||||
sm: '0 2px 6px rgb(15 23 42 / 0.08)',
|
||||
@ -72,6 +72,11 @@ test(
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
`,
|
||||
'node_modules/my-external-lib/src/template.html': html`
|
||||
<div class="text-red-500">
|
||||
Hello world!
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
},
|
||||
async ({ exec, fs }) => {
|
||||
@ -82,8 +87,7 @@ test(
|
||||
--- src/input.css ---
|
||||
@import 'tailwindcss';
|
||||
|
||||
@source './**/*.{html,js}';
|
||||
@source '../my-app/**/*.{html,js}';
|
||||
@source '../node_modules/my-external-lib/**/*.{html}';
|
||||
|
||||
@variant dark (&:where(.dark, .dark *));
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Scanner } from '@tailwindcss/oxide'
|
||||
import fs from 'node:fs/promises'
|
||||
import { dirname } from 'path'
|
||||
import type { Config } from 'tailwindcss'
|
||||
import { type Config } from 'tailwindcss'
|
||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { loadModule } from '../../@tailwindcss-node/src/compile'
|
||||
@ -54,7 +55,7 @@ export async function migrateJsConfig(
|
||||
}
|
||||
|
||||
if ('content' in unresolvedConfig) {
|
||||
sources = migrateContent(unresolvedConfig as any, base)
|
||||
sources = await migrateContent(unresolvedConfig as any, base)
|
||||
}
|
||||
|
||||
if ('theme' in unresolvedConfig) {
|
||||
@ -158,16 +159,31 @@ function createSectionKey(key: string[]): string {
|
||||
return sectionSegments.join('-')
|
||||
}
|
||||
|
||||
function migrateContent(
|
||||
async function migrateContent(
|
||||
unresolvedConfig: Config & { content: any },
|
||||
base: string,
|
||||
): { base: string; pattern: string }[] {
|
||||
): Promise<{ base: string; pattern: string }[]> {
|
||||
let autoContentFiles = autodetectedSourceFiles(base)
|
||||
|
||||
let sources = []
|
||||
for (let content of unresolvedConfig.content) {
|
||||
if (typeof content !== 'string') {
|
||||
throw new Error('Unsupported content value: ' + content)
|
||||
}
|
||||
sources.push({ base, pattern: content })
|
||||
|
||||
let sourceFiles = patternSourceFiles({ base, pattern: content })
|
||||
|
||||
let autoContentContainsAllSourceFiles = true
|
||||
for (let sourceFile of sourceFiles) {
|
||||
if (!autoContentFiles.includes(sourceFile)) {
|
||||
autoContentContainsAllSourceFiles = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!autoContentContainsAllSourceFiles) {
|
||||
sources.push({ base, pattern: content })
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
@ -253,3 +269,15 @@ function keyframesToCss(keyframes: Record<string, unknown>): string {
|
||||
let ast: AstNode[] = keyframesToRules({ theme: { keyframes } })
|
||||
return toCss(ast).trim() + '\n'
|
||||
}
|
||||
|
||||
function autodetectedSourceFiles(base: string) {
|
||||
let scanner = new Scanner({ detectSources: { base } })
|
||||
scanner.scan()
|
||||
return scanner.files
|
||||
}
|
||||
|
||||
function patternSourceFiles(source: { base: string; pattern: string }): string[] {
|
||||
let scanner = new Scanner({ sources: [source] })
|
||||
scanner.scan()
|
||||
return scanner.files
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user