Skip candidates with invalid theme() calls (#14437)
Right now when we encounter a candidates with invalid `theme()` calls we
throw an error which stops the build entirely. This is not ideal
because, especially in the case of `node_modules`, if one file in one
package has an error it will stop the build for an entire project and
tracking this down can be quite difficult.
Now, after this PR, any candidates that use `theme(…)` with non-existent
theme keys (e.g. `rounded-[theme(--radius-does-not-exist)]`) will be
skipped instead of breaking the build.
Before:
```html
<div class="underline rounded-[theme(--radius-does-not-exist)]"></div>
```
```css
/* No CSS was generated because an error was thrown */
/* Error: Invalid theme key: --radius-does-not-exist */
```
After:
```html
<div class="underline rounded-[theme(--radius-does-not-exist)]"></div>
```
```css
.underline {
text-decoration-line: underline;
}
```
---------
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This commit is contained in:
parent
23cee5c6e0
commit
cb5b7b405a
4 changed files with 54 additions and 6 deletions
|
|
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Support `borderRadius.*` as an alias for `--radius-*` when using dot notation inside the `theme()` function ([#14436](https://github.com/tailwindlabs/tailwindcss/pull/14436))
|
||||
- Ensure individual variants from groups are always sorted earlier than stacked variants from the same groups ([#14431](https://github.com/tailwindlabs/tailwindcss/pull/14431))
|
||||
- Allow `anchor-size(…)` in arbitrary values ([#14394](https://github.com/tailwindlabs/tailwindcss/pull/14394))
|
||||
- Skip candidates with invalid `theme()` calls ([#14437](https://github.com/tailwindlabs/tailwindcss/pull/14437))
|
||||
|
||||
## [4.0.0-alpha.24] - 2024-09-11
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { decl, rule, walk, WalkAction, type AstNode, type Rule } from './ast'
|
||||
import { type Candidate, type Variant } from './candidate'
|
||||
import { substituteFunctions } from './css-functions'
|
||||
import { type DesignSystem } from './design-system'
|
||||
import GLOBAL_PROPERTY_ORDER from './property-order'
|
||||
import { asColor, type Utility } from './utilities'
|
||||
|
|
@ -40,6 +41,22 @@ export function compileCandidates(
|
|||
let rules = designSystem.compileAstNodes(candidate)
|
||||
if (rules.length === 0) continue
|
||||
|
||||
// Arbitrary values (`text-[theme(--color-red-500)]`) and arbitrary
|
||||
// properties (`[--my-var:theme(--color-red-500)]`) can contain function
|
||||
// calls so we need evaluate any functions we find there that weren't in
|
||||
// the source CSS.
|
||||
try {
|
||||
substituteFunctions(
|
||||
rules.map(({ node }) => node),
|
||||
designSystem.resolveThemeValue,
|
||||
)
|
||||
} catch (err) {
|
||||
// If substitution fails then the candidate likely contains a call to
|
||||
// `theme()` that is invalid which may be because of incorrect usage,
|
||||
// invalid arguments, or a theme key that does not exist.
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
|
||||
for (let { node, propertySort } of rules) {
|
||||
|
|
|
|||
|
|
@ -606,6 +606,42 @@ describe('theme function', () => {
|
|||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test("values that don't exist don't produce candidates", async () => {
|
||||
// This guarantees that valid candidates still make it through when some are invalid
|
||||
expect(
|
||||
await compileCss(
|
||||
css`
|
||||
@tailwind utilities;
|
||||
@theme reference {
|
||||
--radius-sm: 2rem;
|
||||
}
|
||||
`,
|
||||
[
|
||||
'rounded-[theme(--radius-sm)]',
|
||||
'rounded-[theme(i.do.not.exist)]',
|
||||
'rounded-[theme(--i-do-not-exist)]',
|
||||
],
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
".rounded-\\[theme\\(--radius-sm\\)\\] {
|
||||
border-radius: 2rem;
|
||||
}"
|
||||
`)
|
||||
|
||||
// This guarantees no output for the following candidates
|
||||
expect(
|
||||
await compileCss(
|
||||
css`
|
||||
@tailwind utilities;
|
||||
@theme reference {
|
||||
--radius-sm: 2rem;
|
||||
}
|
||||
`,
|
||||
['rounded-[theme(i.do.not.exist)]', 'rounded-[theme(--i-do-not-exist)]'],
|
||||
),
|
||||
).toEqual('')
|
||||
})
|
||||
})
|
||||
|
||||
describe('in @media queries', () => {
|
||||
|
|
|
|||
|
|
@ -385,12 +385,6 @@ export async function compile(
|
|||
return compiledCss
|
||||
}
|
||||
|
||||
// Arbitrary values (`text-[theme(--color-red-500)]`) and arbitrary
|
||||
// properties (`[--my-var:theme(--color-red-500)]`) can contain function
|
||||
// calls so we need evaluate any functions we find there that weren't in
|
||||
// the source CSS.
|
||||
substituteFunctions(newNodes, designSystem.resolveThemeValue)
|
||||
|
||||
previousAstNodeCount = newNodes.length
|
||||
|
||||
tailwindUtilitiesNode.nodes = newNodes
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue