Skip to content

Commit

Permalink
Merge branch 'next' into fix/v4-always-emit-add-utilities-keyframes
Browse files Browse the repository at this point in the history
  • Loading branch information
thecrypticace authored Oct 22, 2024
2 parents bb1a981 + c7b190f commit 35d2bb2
Show file tree
Hide file tree
Showing 25 changed files with 212 additions and 90 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ 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))
- _Upgrade (experimental)_: Allow JS configuration files with `corePlugins` options to be migrated to CSS ([#14742](https://github.com/tailwindlabs/tailwindcss/pull/14742))
- _Upgrade (experimental)_: Migrate `@variants` and `@responsive` directives ([#14748](https://github.com/tailwindlabs/tailwindcss/pull/14748))
- _Upgrade (experimental)_: Migrate `@screen` directive ([#14749](https://github.com/tailwindlabs/tailwindcss/pull/14749))

### Fixed

Expand All @@ -19,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ensure changes to the input CSS file result in a full rebuild ([#14744](https://github.com/tailwindlabs/tailwindcss/pull/14744))
- Add `postcss` as a dependency of `@tailwindcss/postcss` ([#14750](https://github.com/tailwindlabs/tailwindcss/pull/14750))
- Always emit keyframes registered in `addUtilities` ([#14747](https://github.com/tailwindlabs/tailwindcss/pull/14747))
- Ensure loading stylesheets via the `?raw` and `?url` static asset query works when using the Vite plugin ([#14716](https://github.com/tailwindlabs/tailwindcss/pull/14716))
- _Upgrade (experimental)_: Migrate `flex-grow` to `grow` and `flex-shrink` to `shrink` ([#14721](https://github.com/tailwindlabs/tailwindcss/pull/14721))
- _Upgrade (experimental)_: Minify arbitrary values when printing candidates ([#14720](https://github.com/tailwindlabs/tailwindcss/pull/14720))
- _Upgrade (experimental)_: Ensure legacy theme values ending in `1` (like `theme(spacing.1)`) are correctly migrated to custom properties ([#14724](https://github.com/tailwindlabs/tailwindcss/pull/14724))
Expand Down
10 changes: 10 additions & 0 deletions integrations/upgrade/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ test(
@tailwind base;
@tailwind components;
@tailwind utilities;
@variants hover, focus {
.foo {
color: red;
}
}
`,
},
},
Expand All @@ -40,6 +46,10 @@ test(
--- ./src/input.css ---
@import 'tailwindcss';
@utility foo {
color: red;
}
"
`)

Expand Down
61 changes: 61 additions & 0 deletions integrations/vite/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,3 +504,64 @@ test(
})
},
)

test(
`does not interfere with ?raw and ?url static asset handling`,
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"vite": "^5.3.5"
}
}
`,
'vite.config.ts': ts`
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
build: { cssMinify: false },
plugins: [tailwindcss()],
})
`,
'index.html': html`
<head>
<script type="module" src="./src/index.js"></script>
</head>
`,
'src/index.js': js`
import url from './index.css?url'
import raw from './index.css?raw'
`,
'src/index.css': css`@import 'tailwindcss';`,
},
},
async ({ spawn, getFreePort }) => {
let port = await getFreePort()
await spawn(`pnpm vite dev --port ${port}`)

await retryAssertion(async () => {
// We have to load the .js file first so that the static assets are
// resolved
await fetch(`http://localhost:${port}/src/index.js`).then((r) => r.text())

let [raw, url] = await Promise.all([
fetch(`http://localhost:${port}/src/index.css?raw`).then((r) => r.text()),
fetch(`http://localhost:${port}/src/index.css?url`).then((r) => r.text()),
])

expect(firstLine(raw)).toBe(`export default "@import 'tailwindcss';"`)
expect(firstLine(url)).toBe(`export default "/src/index.css"`)
})
},
)

function firstLine(str: string) {
return str.split('\n')[0]
}
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = `
}
input:where(:not([type="button"], [type="reset"], [type="submit"])), select, textarea {
border: 1px solid;
border-width: 1px;
}
button, input:where([type="button"], [type="reset"], [type="submit"]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ it('should migrate a built-in breakpoint', async () => {
`)
})

it('should migrate `@screen` with a built-in breakpoint', async () => {
expect(
await migrate(css`
@screen md {
.foo {
color: red;
}
}
`),
).toMatchInlineSnapshot(`
"@media (width >= theme(--breakpoint-md)) {
.foo {
color: red;
}
}"
`)
})

it('should migrate a custom min-width screen (string)', async () => {
expect(
await migrate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ export function migrateMediaScreen({
return value ? buildMediaQuery(value) : null
})

// First migrate `@screen md` to `@media screen(md)`
root.walkAtRules('screen', (node) => {
node.name = 'media'
node.params = `screen(${node.params})`
})

// Then migrate the `screen(…)` function
root.walkAtRules((rule) => {
if (rule.name !== 'media') return

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,19 @@ it('should drop `@tailwind variants;`', async () => {
`),
).toEqual('')
})

it('should replace `@responsive` with its children', async () => {
expect(
await migrate(css`
@responsive {
.foo {
color: red;
}
}
`),
).toMatchInlineSnapshot(`
".foo {
color: red;
}"
`)
})
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ export function migrateTailwindDirectives(options: { newPrefix: string | null })
) {
node.remove()
}

// Replace Tailwind CSS v2 directives that still worked in v3.
else if (node.name === 'responsive') {
if (node.nodes) {
for (let child of node.nodes) {
child.raws.tailwind_pretty = true
}
node.replaceWith(node.nodes)
} else {
node.remove()
}
}
})

// Insert default import if all directives are present
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import dedent from 'dedent'
import postcss from 'postcss'
import { expect, it } from 'vitest'
import { formatNodes } from './format-nodes'
import { migrateVariantsDirective } from './migrate-variants-directive'

const css = dedent

function migrate(input: string) {
return postcss()
.use(migrateVariantsDirective())
.use(formatNodes())
.process(input, { from: expect.getState().testPath })
.then((result) => result.css)
}

it('should replace `@variants` with `@layer utilities`', async () => {
expect(
await migrate(css`
@variants hover, focus {
.foo {
color: red;
}
}
`),
).toMatchInlineSnapshot(`
"@layer utilities {
.foo {
color: red;
}
}"
`)
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { type Plugin, type Root } from 'postcss'

export function migrateVariantsDirective(): Plugin {
function migrate(root: Root) {
root.walkAtRules('variants', (node) => {
// Migrate `@variants` to `@utility` because `@variants` make the classes
// an actual utility.
// ```css
// @variants hover {
// .foo {}
// }
// ```
//
// Means that you can do this in your HTML:
// ```html
// <div class="focus:foo"></div>
// ```
//
// Notice the `focus:`, even though we _only_ configured the `hover`
// variant.
//
// This means that we can convert it to an `@layer utilities` rule. Later,
// this will get converted to an `@utility` rule.
if (node.name === 'variants') {
node.name = 'layer'
node.params = 'utilities'
}
})
}

return {
postcssPlugin: '@tailwindcss/upgrade/migrate-variants-directive',
OnceExit: migrate,
}
}
2 changes: 2 additions & 0 deletions packages/@tailwindcss-upgrade/src/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { migrateMediaScreen } from './codemods/migrate-media-screen'
import { migrateMissingLayers } from './codemods/migrate-missing-layers'
import { migrateTailwindDirectives } from './codemods/migrate-tailwind-directives'
import { migrateThemeToVar } from './codemods/migrate-theme-to-var'
import { migrateVariantsDirective } from './codemods/migrate-variants-directive'
import type { JSConfigMigration } from './migrate-js-config'
import { Stylesheet, type StylesheetConnection, type StylesheetId } from './stylesheet'
import { resolveCssId } from './utils/resolve'
Expand Down Expand Up @@ -38,6 +39,7 @@ export async function migrateContents(
.use(migrateAtApply(options))
.use(migrateThemeToVar(options))
.use(migrateMediaScreen(options))
.use(migrateVariantsDirective())
.use(migrateAtLayerUtilities(stylesheet))
.use(migrateMissingLayers())
.use(migrateTailwindDirectives(options))
Expand Down
11 changes: 8 additions & 3 deletions packages/@tailwindcss-vite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { Features, transform } from 'lightningcss'
import path from 'path'
import type { Plugin, ResolvedConfig, Rollup, Update, ViteDevServer } from 'vite'

const SPECIAL_QUERY_RE = /[?&](raw|url)\b/

export default function tailwindcss(): Plugin[] {
let servers: ViteDevServer[] = []
let config: ResolvedConfig | null = null
Expand Down Expand Up @@ -261,9 +263,12 @@ function getExtension(id: string) {
function isPotentialCssRootFile(id: string) {
let extension = getExtension(id)
let isCssFile =
extension === 'css' ||
(extension === 'vue' && id.includes('&lang.css')) ||
(extension === 'astro' && id.includes('&lang.css'))
(extension === 'css' ||
(extension === 'vue' && id.includes('&lang.css')) ||
(extension === 'astro' && id.includes('&lang.css'))) &&
// Don't intercept special static asset resources
!SPECIAL_QUERY_RE.test(id)

return isCssFile
}

Expand Down
2 changes: 1 addition & 1 deletion packages/tailwindcss/preflight.css
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ textarea,
input:where(:not([type='button'], [type='reset'], [type='submit'])),
select,
textarea {
border: 1px solid;
border-width: 1px;
}

/*
Expand Down
3 changes: 1 addition & 2 deletions playgrounds/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"@types/react": "^18.3.9",
"@types/react-dom": "^18.3.1",
"bun": "^1.1.29",
"vite": "catalog:",
"vite-plugin-handlebars": "^2.0.0"
"vite": "catalog:"
}
}
1 change: 0 additions & 1 deletion playgrounds/vite/src/animate.js

This file was deleted.

4 changes: 0 additions & 4 deletions playgrounds/vite/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { Foo } from './foo'

export function App() {
return (
<div className="m-3 p-3 border">
<h1 className="text-blue-500">Hello World</h1>
<button className="hocus:underline">Click me</button>
<Foo />
</div>
)
}
7 changes: 0 additions & 7 deletions playgrounds/vite/src/bar.tsx

This file was deleted.

10 changes: 0 additions & 10 deletions playgrounds/vite/src/foo.tsx

This file was deleted.

1 change: 0 additions & 1 deletion playgrounds/vite/src/forms.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
@import 'tailwindcss';
@plugin "./plugin.js";
1 change: 0 additions & 1 deletion playgrounds/vite/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>≈ Playground</title>
<link rel="stylesheet" href="./app.css" />
</head>
<body class="h-full">
<div id="app"></div>
Expand Down
2 changes: 2 additions & 0 deletions playgrounds/vite/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react'
import ReactDOM from 'react-dom/client'
import { App } from './app'

import './index.css'

ReactDOM.createRoot(document.getElementById('app')!).render(
<React.StrictMode>
<App />
Expand Down
4 changes: 0 additions & 4 deletions playgrounds/vite/src/plugin.js

This file was deleted.

1 change: 0 additions & 1 deletion playgrounds/vite/src/typography.js

This file was deleted.

Loading

0 comments on commit 35d2bb2

Please sign in to comment.