Postcss: Run plugin in Once hook (#15273)

Closes #15138

This PR changes the postcss client to run in the `Once` hook instead of
`OnceExit`. This makes sure the postcss order in v4 matches that of v3.

Conceptually this also makes more sense, since we expect tailwindcss to
be run as one of the first plugins in the pipeline (where `OnceExit`
would run it almost at the end).

To make sure it's still possible to use `postcss-import` before and have
it resolve to the right paths, we also needed to change the
`postcss-fix-relative-paths` plugin to run in the `Once` order
(`postcss-import` also uses `Once` order so the order).

## Test Plan

This issue had many ways in which it can manifest. I added a unit test
to ensure the plugin order works but here's a concrete example when
using the postcss plugin in Vite.

### Before

Image `url()`s were not properly handled since the postcss plugin to
transform these was run before Tailwind CSS could generate the class for
it:

<img width="2532" alt="Screenshot 2024-12-02 at 14 55 42"
src="https://github.com/user-attachments/assets/2f23b409-1576-441d-9ffe-6f24ad6e7436">

### After

<img width="2529" alt="Screenshot 2024-12-02 at 14 53 52"
src="https://github.com/user-attachments/assets/b754c3d8-1af1-4aeb-87da-0bfc3ffecdb7">

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
This commit is contained in:
Philipp Spiess 2024-12-03 10:28:51 +01:00 • committed by GitHub
parent 93b922dcb6
commit 545401469d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 64 additions and 6 deletions

View file

@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ensure absolute `url()`s inside imported CSS files are not rebased when using `@tailwindcss/vite`
- Fix issues with dev servers using Svelte 5 with the Vite plugin ([#15274](https://github.com/tailwindlabs/tailwindcss/issues/15274))
- Fix resolution of imported CSS files in Vite SSR builds ([#15279](https://github.com/tailwindlabs/tailwindcss/issues/15279))
- Ensure other plugins can run after `@tailwindcss/postcss` ([#15273](https://github.com/tailwindlabs/tailwindcss/pull/15273))
- Rebase `url()` inside imported CSS files when using Vite with the `@tailwindcss/postcss` extension ([#15273](https://github.com/tailwindlabs/tailwindcss/pull/15273))
### Added

View file

@ -2,7 +2,6 @@ import dedent from 'dedent'
import { unlink, writeFile } from 'node:fs/promises'
import postcss from 'postcss'
import { afterEach, beforeEach, describe, expect, test } from 'vitest'
// @ts-ignore
import tailwindcss from './index'
// We give this file path to PostCSS for processing.
@ -248,3 +247,62 @@ test('bail early when Tailwind is not used', async () => {
}"
`)
})
test('runs `Once` plugins in the right order', async () => {
let before = ''
let after = ''
let processor = postcss([
{
postcssPlugin: 'before',
Once(root) {
before = root.toString()
},
},
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
{
postcssPlugin: 'after',
Once(root) {
after = root.toString()
},
},
])
let result = await processor.process(
css`
@theme {
--color-red-500: red;
}
.custom-css {
color: theme(--color-red-500);
}
`,
{ from: inputCssFilePath() },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
":root {
--color-red-500: red;
}
.custom-css {
color: red;
}"
`)
expect(before).toMatchInlineSnapshot(`
"@theme {
--color-red-500: red;
}
.custom-css {
color: theme(--color-red-500);
}"
`)
expect(after).toMatchInlineSnapshot(`
":root {
--color-red-500: red;
}
.custom-css {
color: red;
}"
`)
})

View file

@ -55,7 +55,7 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
{
postcssPlugin: 'tailwindcss',
async OnceExit(root, { result }) {
async Once(root, { result }) {
env.DEBUG && console.time('[@tailwindcss/postcss] Total time in @tailwindcss/postcss')
let inputFile = result.opts.from ?? ''
let context = getContextFromCache(inputFile, opts)

View file

@ -67,10 +67,8 @@ export default function fixRelativePathsPlugin(): Plugin {
return {
postcssPlugin: 'tailwindcss-postcss-fix-relative-paths',
AtRule: {
source: fixRelativePath,
plugin: fixRelativePath,
config: fixRelativePath,
Once(root) {
root.walkAtRules(/source|plugin|config/, fixRelativePath)
},
}
}