Skip to content

Commit 52000a3

Browse files
PostCSS: Improve error recovery (#17754)
Closes #17295 This commit addresses an issue where the PostCSS plugin would get stuck in an error state when processing files with e.g. invalid @apply directives. This change prevents the PostCSS plugin from getting stuck in an error states particularly when the error happened inside an `@import`ed CSS files (as these were not registered as dependencies correctly before). ## Error overlays Some frameworks (e.g. Angular 19 or Next.js) handle errors inside PostCSS transforms to render a nice error overlay. This works well and gives immediate feedback that something went wrong. However, even when dependencies are registered before an error is thrown, these frameworks _will not consider changes to these dependencies anymore_ when an error occurs, as you can see in this Next.js example: https://github.com/user-attachments/assets/985c9dd7-daf8-4628-b4ad-6543ef220954 To avoid conditions where errors are not recoverable, this PR makes it so that these overlays will no longer show up in the app and only be logged to the output console. This will need follow-up upstream work before we can revisit this. ## Test plan - Tested with the repro in #17295. The error can now be recovered from. - Tested with a Next.js app where the issue in the screencast above is now no longer happening. - Added an integration test for errors in `@import`-ed files - Added a unit test for the changed `@apply` behavior.
1 parent 231cddd commit 52000a3

File tree

6 files changed

+272
-164
lines changed

6 files changed

+272
-164
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- Hide default shadow suggestions when missing theme keys ([#17743](https://github.com/tailwindlabs/tailwindcss/pull/17743))
1919
- Replace `_` with `.` in theme suggestions for `@utility` if surrounded by digits ([#17743](https://github.com/tailwindlabs/tailwindcss/pull/17743))
2020
- Upgrade: Bump all Tailwind CSS related dependencies during upgrade ([#17763](https://github.com/tailwindlabs/tailwindcss/pull/17763))
21+
- PostCSS: Ensure that errors in stylesheet dependencies are recoverable ([#17754](https://github.com/tailwindlabs/tailwindcss/pull/17754))
2122

2223
## [4.1.4] - 2025-04-14
2324

integrations/postcss/index.test.ts

+88
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,91 @@ test(
635635
await fs.expectFileToContain('project-a/dist/out.css', [candidate`content-['c/src/index.js']`])
636636
},
637637
)
638+
639+
test(
640+
'rebuild error recovery',
641+
{
642+
fs: {
643+
'package.json': json`
644+
{
645+
"devDependencies": {
646+
"postcss": "^8",
647+
"postcss-cli": "^10",
648+
"tailwindcss": "workspace:^",
649+
"@tailwindcss/postcss": "workspace:^"
650+
}
651+
}
652+
`,
653+
'postcss.config.js': js`
654+
module.exports = {
655+
plugins: {
656+
'@tailwindcss/postcss': {},
657+
},
658+
}
659+
`,
660+
'src/index.html': html`
661+
<div class="underline"></div>
662+
`,
663+
'src/index.css': css` @import './tailwind.css'; `,
664+
'src/tailwind.css': css`
665+
@reference 'tailwindcss/does-not-exist';
666+
@import 'tailwindcss/utilities';
667+
`,
668+
},
669+
},
670+
async ({ fs, expect, spawn }) => {
671+
let process = await spawn('pnpm postcss src/index.css --output dist/out.css --watch --verbose')
672+
673+
await process.onStderr((message) =>
674+
message.includes('Package path ./does-not-exist is not exported from package'),
675+
)
676+
677+
expect(await fs.dumpFiles('dist/*.css')).toMatchInlineSnapshot(`
678+
"
679+
--- dist/out.css ---
680+
<EMPTY>
681+
"
682+
`)
683+
684+
await process.onStderr((message) => message.includes('Waiting for file changes...'))
685+
686+
// Fix the CSS file
687+
await fs.write(
688+
'src/tailwind.css',
689+
css`
690+
@reference 'tailwindcss/theme';
691+
@import 'tailwindcss/utilities';
692+
`,
693+
)
694+
await process.onStderr((message) => message.includes('Finished src/index.css'))
695+
696+
expect(await fs.dumpFiles('dist/*.css')).toMatchInlineSnapshot(`
697+
"
698+
--- dist/out.css ---
699+
.underline {
700+
text-decoration-line: underline;
701+
}
702+
"
703+
`)
704+
705+
// Now break the CSS file again
706+
await fs.write(
707+
'src/tailwind.css',
708+
css`
709+
@reference 'tailwindcss/does-not-exist';
710+
@import 'tailwindcss/utilities';
711+
`,
712+
)
713+
await process.onStderr((message) =>
714+
message.includes('Package path ./does-not-exist is not exported from package'),
715+
)
716+
await process.onStderr((message) => message.includes('Finished src/index.css'))
717+
718+
expect(await fs.dumpFiles('dist/*.css')).toMatchInlineSnapshot(`
719+
"
720+
--- dist/out.css ---
721+
<EMPTY>
722+
"
723+
`)
724+
},
725+
)

0 commit comments

Comments
 (0)