Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
content rules from the JS config that are also covered by the autom…
…atic source detection should not be migrated to CSS
  • Loading branch information
philipp-spiess committed Oct 18, 2024
commit 8e3c3e68715773b16a285e9e429c009ceccb21cb
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)_: `content` rules from the JS configuration that are also covered by the automatic source detection are no longer migrated to CSS ([#14714](https://github.com/tailwindlabs/tailwindcss/pull/14714))

## [4.0.0-alpha.28] - 2024-10-17

### Added
Expand Down
4 changes: 0 additions & 4 deletions integrations/upgrade/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ test(

--- ./src/input.css ---
@import 'tailwindcss';

@source './**/*.{html,js}';
"
`)

Expand Down Expand Up @@ -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;
}
Expand Down
12 changes: 8 additions & 4 deletions integrations/upgrade/js-config.test.ts
Original file line number Diff line number Diff line change
@@ -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`,
Expand All @@ -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)',
Expand Down Expand Up @@ -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 }) => {
Expand All @@ -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 *));

Expand Down
44 changes: 38 additions & 6 deletions packages/@tailwindcss-upgrade/src/migrate-js-config.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -15,7 +16,7 @@ import type { ThemeConfig } from '../../tailwindcss/src/compat/config/types'
import { darkModePlugin } from '../../tailwindcss/src/compat/dark-mode'
import type { DesignSystem } from '../../tailwindcss/src/design-system'
import { findStaticPlugins, type StaticPluginOptions } from './utils/extract-static-plugins'
import { info } from './utils/renderer'
import { info, warn } from './utils/renderer'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -158,16 +159,35 @@ 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 = listAutoContentFiles(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 = listSourceContentFiles({ base, pattern: content })

let autoContentContainsAllSourceFiles = true
for (let sourceFile of sourceFiles) {
if (!autoContentFiles.includes(sourceFile)) {
autoContentContainsAllSourceFiles = false
break
}
}

if (autoContentContainsAllSourceFiles) {
warn(
'The `content` configuration `${content}` is already included in the automatic content file discovery and will not be migrated.',
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually seeing this I think I'd rather just not log anything, it almost reads like the upgrade couldn't be completed and I'm not sure how to say it more clearly without it being too verbose.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamwathan Yeah I think this makes sense.

} else {
sources.push({ base, pattern: content })
}
}
return sources
}
Expand Down Expand Up @@ -253,3 +273,15 @@ function keyframesToCss(keyframes: Record<string, unknown>): string {
let ast: AstNode[] = keyframesToRules({ theme: { keyframes } })
return toCss(ast).trim() + '\n'
}

function listAutoContentFiles(base: string) {
let scanner = new Scanner({ detectSources: { base } })
scanner.scan()
return scanner.files
}

function listSourceContentFiles(source: { base: string; pattern: string }): string[] {
let scanner = new Scanner({ sources: [source] })
scanner.scan()
return scanner.files
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we avoid the word "content" for code that's just looking at the modern stuff?

Are these names clear enough?

Suggested change
function listAutoContentFiles(base: string) {
let scanner = new Scanner({ detectSources: { base } })
scanner.scan()
return scanner.files
}
function listSourceContentFiles(source: { base: string; pattern: string }): string[] {
let scanner = new Scanner({ sources: [source] })
scanner.scan()
return scanner.files
}
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
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I went with content in the first iteration since we are looking at the content array and this is the content field migration, but yeah in terms of v4, the term content does not really exists.