Commit graph

5485 commits

Author SHA1 Message Date
Philipp Spiess
2ef87ab7fb
Release v4.0.0-alpha.24 (#14395) 2024-09-12 16:10:56 +02:00
Philipp Spiess
0eff7e7c57 Increase CI timeouts for Windows intergarion tests 2024-09-12 15:41:07 +02:00
Philipp Spiess
52f2993069
Pin rust toolchain to work around Windows regression (#14406)
This PR works around a current regression in the Rust toolchain that
caused our Windows workers to start failing with:

```
    Finished `test` profile [unoptimized + debuginfo] target(s) in 32.63s
     Running unittests src\lib.rs (target\debug\deps\tailwind_oxide-ce6a5d43a3798437.exe)
Load Node-API [napi_get_last_error_info] from host runtime failed: GetProcAddress failed
fatal runtime error: thread::set_current should only be called once per thread
Load Node-API [napi_get_uv_event_loop] from host runtime failed: GetProcAddress failed
Load Node-API [napi_fatal_exception] from host runtime failed: GetProcAddress failed
Load Node-API [napi_create_threadsafe_function] from host runtime failed: GetProcAddress failed
error: test failed, to rerun pass `-p tailwind-oxide --lib`
```

The workaround is to pin the rust toolchain version so that the
regression isn't applied when we build on Windows in test mode.
2024-09-12 14:07:43 +02:00
Philipp Spiess
7244f276c8
Don't assert on mangled CSS names (#14397)
This PR fixes an issue with the regex rule I oh-so-carefully constructed
that would fail the regex when the _randomness_ part contains a `t`
😶‍🌫️.
2024-09-11 17:37:36 +02:00
Philipp Spiess
63390c97b2
Throw a useful error when tailwindcss is used as a PostCSS plugin (#14378)
While upgrading a project to Tailwind CSS v4, I forgot to remove the
`tailwindcss` import from the PostCSS config. As a result of this, I was
greeted with the following message:

```
node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[Failed to load PostCSS config: Failed to load PostCSS config (searchPath: /Users/philipp/dev/project): [TypeError] Invalid PostCSS Plugin found at: plugins[0]

(@/Users/philipp/dev/project/postcss.config.js)
TypeError: Invalid PostCSS Plugin found at: plugins[0]
```

I don't think this was particularly helpful, so I’m proposing we add a
default function export to the `tailwindcss` package so when it's used
inside PostCSS, we can control the error message. So I changed it to
something along these lines:

```
It looks like you're trying to use the \`tailwindcss\` package as a PostCSS plugin. This is no longer possible since Tailwind CSS v4.

If you want to continue to use Tailwind CSS with PostCSS, please install \`@tailwindcss/postcss\` and change your PostCSS config file.
    at w (/Users/philipp/dev/project/node_modules/tailwindcss/node_modules/tailwindcss/dist/lib.js:1:21233)
    at Object.<anonymous> (/Users/philipp/dev/project/node_modules/tailwindcss/postcss.config.cjs:3:13)
    at Module._compile (node:internal/modules/cjs/loader:1358:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)
    at Module.load (node:internal/modules/cjs/loader:1208:32)
    at Module._load (node:internal/modules/cjs/loader:1024:12)
    at cjsLoader (node:internal/modules/esm/translators:348:17)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:297:7)
    at ModuleJob.run (node:internal/modules/esm/module_job:222:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:316:24)
```

This is also a good place to link to the migration guides once we have
them 🙂

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-11 17:02:24 +02:00
Philipp Spiess
d2b5731811
Intellisense: Add example bare values to border completions (#14370)
Closes
https://github.com/tailwindlabs/tailwindcss-intellisense/issues/1048

This PR adds a few bare value examples for border width completions. The
examples are taken from [our
docs](https://tailwindcss.com/docs/border-width).
2024-09-11 16:59:18 +02:00
Philipp Spiess
1e0dfbc6d0
Add matchVariant API (#14371)
This PR adds support for the `matchVariant` plugin API. I've copied over
all [V3
tests](f07dbff2a7/tests/match-variants.test.js)
and made sure they still pass.

## Sorted order of stacked arbitrary variants

The only difference in behavior is regarding the sort order of stacked
arbitrary variants: Sorting in this case now works by the latest defined
`matchVariant` taking precedence.

So, if you define a plugin like this:

```ts
matchVariant('testmin', (value) => `@media (min-width: ${value})`, {
  sort(a, z) {
    return parseInt(a.value) - parseInt(z.value)
  },
})

matchVariant('testmax', (value) => `@media (max-width: ${value})`, {
  sort(a, z) {
    return parseInt(z.value) - parseInt(a.value)
  },
})
```

The resulting CSS is first sorted by the `testmax` values descending and
then the `testmin` values ascending, so these candidates:

```txt
testmin-[150px]:testmax-[400px]:order-2
testmin-[100px]:testmax-[350px]:order-3
testmin-[100px]:testmax-[300px]:order-4
testmin-[100px]:testmax-[400px]:order-1
```

Will resolve to the order outlined by the `order-` utility.

## At-rules and placeholders support

Since we added support for at-rules and placeholders in the
`matchVariant` syntax like this:

```ts
matchVariant(
  'potato',
  (flavor) => `@media (potato: ${flavor}) { @supports (font:bold) { &:large-potato } }`,
)
```

We also added support for the same syntax to the `addVariant` API:

```ts
addVariant(
  'potato',
  '@media (max-width: 400px) { @supports (font:bold) { &:large-potato } }',
)
```

The only change necessary in core was to call functional variants for
when the variant value is set to `null`. This allows functional variants
to define the un-parameterized implementation like `potato:underline` as
opposed to `potato[big]:underline`.

---------

Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-09-11 16:45:07 +02:00
Adam Wathan
8b0fff6edd
Extract more backwards compatibility logic to compatibility layer (#14365)
I noticed a lot more backwards compatibility concerns had started
leaking into core, especially around the `theme` function, so did a bit
of work to try and pull that stuff out and into the compatibility layer.

Now the core version of `theme` only handles CSS variables (like
`--color-red-500`) and has no knowledge of the dot notation or how to
upgrade it. Instead, we unconditionally override that function in the
compatibility layer with a light version that _does_ know how to do the
dot notation upgrade, and override that again with the very heavy/slow
version that handles JS config objects only if plugins/JS configs are
actually used.

I've also renamed `registerPlugins` to `applyCompatibilityHooks` because
the name was definitely a bit out of date given how much work it's doing
now, and now call it unconditionally from core, leaving that function to
do any conditional optimizations itself internally.

Next steps I think would be to split up `plugin-api.ts` a bit and maybe
make `applyCompatibilityHooks` its own file, and move both of those
files into the `compat` folder so everything is truly isolated there.

My goal with this stuff is that if/when we ever decide to drop backwards
compatibility with these features in the future (maybe v5), that all we
have to do is delete the one line of code that calls
`applyCompatibilityHooks` in `index.ts`, and delete the `compat` folder
and we're done. I could be convinced that this isn't a worthwhile goal
if we feel it's making the codebase needlessly complex, so open to that
discussion as well.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-09-11 16:17:02 +02:00
Jordan Pittman
8c6c291869
Make config resolution lazy (#14362)
The internal `registerPlugins()` API is used to enable backwards
compatibility with v3 plugins and configs and it is called on every
build even when no v3 plugins or configs are used. This function has a
non-trivial cost in that case — around 5ms.

So this PR does a few things:

## Implements a simpler, faster `theme(…)` function

We now have a much simpler `theme(…)` function that can be used when
backwards compatibility is not necessary. It still supports many of the
same features:
- The modern, v4 style CSS variable syntax `theme(--color-red-500)`
- The legacy, v3 path style `theme(colors.red.500)`
- And the v3-style alpha modifier `theme(colors.red.500 / 50%)`
- Path upgrades so things like `theme(accentColor.red.500)` pulls from
`--color-red-500` when no `--accent-color-red-500` theme key exists

When you do have plugins or configs the more advanced `theme(…)`
function is swapped in for more complete backwards compatibility.

## `registerPlugins` registers globs

Before `registerPlugins` passed the `ResolvedConfig` out so we could
register globs in `compile()`. Since that one function is really the
main driver for backwards compat we decided to move the content path
registration into `registerPlugins` itself when it comes to paths
provided by plugins and configs.

This is an internal implementation detail (well this entire PR is) but
it's worth mentioning. This method is used to resolve a theme value from
a theme key.

## `registerPlugins` is now only called when necessary

All of the above work made it so that `registerPlugins` can be called
only as needed. This means that when no v3 plugins or configs are used,
`registerPlugins` is never called thus elminating the performance impact
of config resolution.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-07 13:18:30 -04:00
Jordan Pittman
783b32305f
Export Config type (#14360)
Right now the following does not work and instead produces a type error:

```
import { type Config } from 'tailwindcss'

export default {
  // … config here
} satisfies Config
```

We were not exporting a `Config` type but thankfully this already exists
in the codebase so we just need to export it.

It does _not_ have all properties of an existing config as not all
features have been implemented (or in some cases necessary / relevant
for v4).

Notably missing are:
- `important`
- `prefix`
- `separator`
- `safelist`
- `blocklist`
- `future`
- `experimental`
- `corePlugins`

Also, explicit keys for theme are not currently specified but we should
probably bring this back even if just as an auto-complete aid.
2024-09-06 16:10:18 -04:00
Jordan Pittman
b1e22e121e
Allow configs to override default CSS theme values in theme() function provided to plugins and configs (#14359)
Previously, given the following CSS and configuration:

```css
/* app.css */

@theme default {
  --font-size-base: 1.25rem;
  --font-size-base--line-height: 1.5rem;
}
@tailwind utilities;
@config "./config.js";
```

```js
// config.js

export default {
  theme: {
    fontSize: {
      // …
      base: ['1rem', { lineHeight: '1.75rem' }],
    },

    // …
  },
};
```

When a config or a plugin asked for the value of `theme(fontSize.base)`
like so:

```js
// config.js
export default {
  theme: {
    // …

    typography: ({ theme }) => ({
      css: {
        '[class~="lead"]': {
          fontSize: theme('fontSize.base')[0],
          ...theme('fontSize.base')[1],
        },
      }
    }),
  },
};
```

We would instead pull the values from the CSS theme even through they're
marked with `@theme default`. This would cause the incorrect font size
and line height to be used resulting in something like this (in the case
of the typography plugin with custom styles):

  ```css
  .prose [class~="lead"] {
    font-size: 1.25rem;
    line-height: 1.5rem;
  }
  ```

After this change we'll now pull the values from the appropriate place
(the config in this case) and the correct font size and line height will
be used:

  ```css
  .prose [class~="lead"] {
    font-size: 1rem;
    line-height: 1.75rem;
  }
  ```

This will work even when some values are overridden in the CSS theme:

  ```css
  /* app.css */
  @theme default {
    --font-size-base: 1.25rem;
    --font-size-base--line-height: 1.5rem;
  }
  @theme {
    --font-size-base: 2rem;
  }
  @tailwind utilities;
  @config "./config.js";
  ```

which would result in the following CSS:

  ```css
  .prose [class~="lead"] {
    font-size: 2rem;
    line-height: 1.75rem;
  }
  ```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-06 16:05:26 -04:00
Philipp Spiess
ee35a1d047
Support CSS theme() functions inside @custom-media rules (#14358)
This PR will now also scan `@custom-media` rules for invocations of the
CSS `theme()` function.
2024-09-06 19:05:48 +02:00
Adam Wathan
7b59aac274
Properly resolve theme('someKey.DEFAULT') when only --some-key-* keys exist (#14354)
This PR fixes an issue where theme function calls like
`theme('transitionTimingFunction.DEFAULT')` would incorrectly resolve to
an object when the set of defined CSS theme values looked like this:

```css
@theme {
  --transition-timing-function-in: ease-in;
  --transition-timing-function-out: ease-out;
  --transition-timing-function-in-out: ease-out;
}
```

We were mistakenly retrieving the entire
`--transition-timing-function-*` namespace in this case and returning an
object, even though the user is explicitly asking for a single value by
including `.DEFAULT` in their call.

This ensures it resolves to null instead. Fixes an issue I ran into on
this live stream earlier today:

https://x.com/adamwathan/status/1831740214051799281

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-06 09:00:28 -04:00
Philipp Spiess
f028eae75e
Integration tests: Move all file writes into retry block (#14350)
There are still instances in which CI is flaky after #14332. This PR
applies the same fix (that is, moving the file write into the retrying
block) to all `retryAssertion` callbacks.
2024-09-06 10:48:49 +02:00
Robin Malfait
7f06777d6c
Use a bit flags for theme options instead of an object with booleans (#14337)
This PR is a small improvement to the theme options where it's just a
simple number now instead of an object with booleans.
2024-09-06 00:38:43 +02:00
Robin Malfait
af774e8f24
Improve the CLI output when nothing changed (#14351)
When we observe that no new candidates were found, then we can return
early because nothing really changed. There is also no need to
re-optimize (use Lightning CSS) in this case.

But this had a side effect that when no new candidates were detected,
that you didn't see any output either. This feels like nothing is
working from a DX perspective.

Typically you are changing things, so it's not really a problem. But the
moment you use a class that already existed (e.g.: in another file) you
also don't get any output because we have a shared cache.

This PR solves that by always showing the output. But it still doesn't
write to disk if nothing changed.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-05 17:00:57 -04:00
Jordan Pittman
c37473e17b set registry url 2024-09-05 10:52:11 -04:00
Jordan Pittman
15d1714c33 v4.0.0-alpha.23 2024-09-05 10:43:07 -04:00
Jordan Pittman
2f9de02f24 Fix changelog 2024-09-05 10:40:00 -04:00
Jordan Pittman
4b94373e52 Update changelog
The release didn’t happen yesterday so the date is wrong
2024-09-05 10:30:41 -04:00
Jordan Pittman
c2f4623a68 Tweak tag fetching in GH actions release workflow 2024-09-05 10:18:51 -04:00
Jordan Pittman
c7d9af58c5 fix release workflow 2024-09-05 09:58:09 -04:00
Jordan Pittman
aa0075f57f
Add GitHub release workflow (#14346)
Co-authored-by: Philipp Spiess <hello@philippspiess.com>
2024-09-05 09:45:29 -04:00
Philipp Spiess
27cced0d16 Remove leftover .debug 2024-09-05 14:46:01 +02:00
Philipp Spiess
4297655a7a
Add integration test for Vite CSS module support (#14349)
Wanted to make sure stuff works with CSS modules for both the postcss
and the lightningcss pipeline.
2024-09-05 14:24:50 +02:00
Philipp Spiess
8f8803d855
Move opacity modifier support into plugin theme() function (#14348)
This PR moves support for opacity modifies from the CSS `theme()`
function into the plugin `theme()` implementation, this will allow
plugins to use this, too:

```ts
let plugin = plugin(function ({ addUtilities, theme }) {
    addUtilities({
      '.percentage': {
        color: theme('colors.red.500 / 50%'),
      },
      '.fraction': {
        color: theme('colors.red.500 / 0.5'),
      },
      '.variable': {
        color: theme('colors.red.500 / var(--opacity)'),
      },
    })
  })
}
```

There's a small behavioral change for the CSS `theme()` function. Since
tuples are resolved by default for the CSS `theme()` function only,
these will no longer have opacity applied to their first values. This is
probably fine given the reduced complexity as I don't expect the first
values of tuples to be colors and the fix would mean we would have to
parse the modifier in different places.
2024-09-05 12:40:16 +02:00
Adam Wathan
d9558bbc4c v4.0.0-alpha.22 2024-09-04 15:50:57 -04:00
Adam Wathan
7725a5fbb6
Update CHANGELOG.md 2024-09-04 15:46:39 -04:00
Adam Wathan
2c89645d26
Update CHANGELOG.md 2024-09-04 15:45:25 -04:00
Adam Wathan
530774b186
Ensure --default-font-* and --default-mono-font-* variables respect theme customizations in JS config files (#14344)
This PR fixes an issue where variables like `--default-font-family`
wouldn't behave as expected when customizing `fontFamily.sans` or
`fontFamily.mono` in a JS config.

Because theme values added by JS config files are added as `reference`,
customizing `fontFamily.sans` means the `--font-family-sans` variable no
longer exists in the generated CSS.

The `--default-font-family` variable is set to `var(--font-family-sans)`
by default, so because that variable doesn't exist,
`--default-font-family` is effectively undefined and the browser default
font stack is used. This is unexpected because historically customizing
`fontFamily.sans` has updated your default font for your entire project.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 15:30:21 -04:00
Adam Wathan
262e99e5a9
Support arrays in JS config values (#14343)
This PR fixes a small bug where theme values could not be defined as
arrays in JS config files, for example:

```js
export default {
  theme: {
    fontFamily: {
      sans: ['Inter', 'system-ui', 'sans-serif'],
    },
  },
}
```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 15:03:46 -04:00
Philipp Spiess
a3a16e64d2
Fix a crash with older Node.js versions (#14342)
Closes #14341

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-04 13:43:18 -04:00
Philipp Spiess
2dd52f5a0f
Vite: Add support for <style> tags in Astro files (#14340)
This works similar to the Vue setup. The styles that Astro will receive
might still contain Tailwind CSS APIs but since it's not picky, we can
pass that through to the regular Vite `transform` handlers for now.

This, however, will have issues like
https://github.com/tailwindlabs/tailwindcss/issues/14205. We have to fix
this together with Vue and other similar extensions later. For now, it
will break when syntax is used that lightningcss rewrites (like `@apply
text-3xl/tight;`)

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
2024-09-04 19:14:05 +02:00
Jordan Pittman
805c8a0201
Don’t suggest named opacity modifiers in intellisense (#14339)
We removed named opacity modifier support in #14278 but we (read: me
lol) totally forgot about the suggestions in intellisense. So we need to
make sure that we don't suggest those either.
2024-09-04 16:57:32 +00:00
Adam Wathan
d6a67beb76
Add default option to @theme to support overriding default theme values from plugins/JS config files (#14327)
This PR adds a new `default` option to `@theme` to make it possible for
plugins/JS config files to override default theme values, and also
ensures that the final set of CSS variables we output takes into account
any theme values added by plugins/JS config files.

---

Previously, if you were using the default theme but also had a JS config
file that overrode any of those defaults like this:

```js
// ./tailwind.config.js
export default {
  theme: {
    extend: {
      colors: {
        red: {
          '500': 'tomato',
        },
      }
    }
  }
}
```

…then utilities like `text-red-500` would correctly use `color: tomato`,
but the `--color-red-500` CSS variable would still be set to the default
value:

```css
:root {
  --color-red-500: #ef4444;
}
```

This feels like a straight-up bug — if `#ef4444` is not part of your
design system because you've overridden it, it shouldn't show up in your
set of CSS variables anywhere.

So this PR fixes this issue by making sure we don't print the final set
of CSS variables until all of your plugins and config files have had a
chance to update the theme.

---

The second issue is that we realized people have different expectations
about how plugin/config theme values should interact with Tailwind's
_default_ theme vs. explicitly user-configured theme values.

Take this setup for instance:

```css
@import "tailwindcss";
@config "./tailwind.config.js";
```

If `tailwind.config.js` overrides `red-500` to be `tomato`, you'd expect
`text-red-500` to actually be `tomato`, not the default `#ef4444` color.

But in this setup:

```css
@import "tailwindcss";
@config "./tailwind.config.js";
@theme {
  --color-red-500: #f00;
}
```

…you'd expect `text-red-500` to be `#f00`. This is despite the fact that
currently in Tailwind there is no difference here — they are both just
`@theme` blocks, one just happens to be coming from an imported file
(`@import "tailwindcss"`).

So to resolve this ambiguity, I've added a `default` option to `@theme`
for explicitly registering theme values as "defaults" that are safe to
override with plugin/JS config theme values:

```css
@import "tailwindcss";
@config "./tailwind.config.js";
@theme default {
  --color-red-500: #f00;
}
```

Now `text-red-500` would be `tomato` here as per the config file.

This API is not something users are generally going to interact with —
they will almost never want to use `default` explicitly. But in this PR
I've updated the default theme we ship with to include `default` so that
it interacts in a more intuitive way with plugins and JS config files.

---

Finally, this PR makes sure all theme values registered by
plugins/configs are registered with `isReference: true` to make sure
they do not end up in the final CSS at all.

This is important to make sure that the super weird shit we used to do
in configs in v3 doesn't get translated into nonsense variables that
pollute your output (hello typography plugin I'm looking at you).

If we don't do this, you'll end up with CSS variables like this:

```css
:root {
  --typography-sm-css-blockquote-padding-inline-start: 1.25em;
}
```

Preventing theme values registered in plugins/configs from outputting
CSS values also serves the secondary purpose of nudging users to migrate
to the CSS config if they do want CSS variables for their theme values.

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 11:49:50 -04:00
Adam Wathan
6d0371afb1
Evaluate theme functions in plugins (#14326)
This PR fixes a bug where CSS `theme()` functions were not evaluated
when present in rules added by plugins, using either `@plugin` or
registering a plugin in a JS config file.

For example, prior to this PR the `theme()` functions in this plugin
would make it into the final CSS without being evaluated:

```js
// ./my-plugin.js
export default plugin(({ addBase }) => {
  addBase({
    '.my-rule': {
      background: 'theme(colors.primary)',
      color: 'theme(colors.secondary)',
    },
  })
})
```

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 11:49:01 -04:00
Philipp Spiess
44dd6da4fe
Integration tests: Fix Windows flake for Vite watch mode (#14332)
I noticed the Windows integration tests for Vite's `watch` mode have
been flaky. Moving the file write into the retrying assertion callback
seems to fix it and allows us to get rid of the arbitrary timeout (I
don't remember that I ever added this in the first place 😅 ).
2024-09-04 17:09:33 +02:00
Philipp Spiess
719a5351c1
Fix Nuxt integration (#14319)
We noticed that Nuxt projects were not working with the tailwindcss
project. The issue was traced down to the fact that Nuxt starts multiple
Vite dev servers and calling the experimental `waitForRequestsIdle()` on
one of the test servers would never resolve.

This was fixed upstream and is part of the latest Vite/Nuxt release:
https://github.com/vitejs/vite/issues/17980.

We still need to handle the fact that Vite can spawn multiple dev
servers. This is necessary because when we invalidate all roots, we need
to find that module inside all of the spawned servers. If we only look
at the _last server_ (what we have done before), we would not find the
module and thus could not invalidate it.
2024-09-04 10:53:15 -04:00
Philipp Spiess
e7ca667f76 Remove leftover TODO in Vite plugin 2024-09-04 11:43:41 +02:00
Philipp Spiess
835922812b
Rework Vite plugin to support lightningcss pre processor and fast rebuilds (#14269)
Fixes #14205
Fixes #14106

This PR reworks the Vite extension in order to supprt `lightningcss` as
the pre-processor, enable faster rebuilds, and adds support for `vite
build --watch` mode. To make this change possible, we've done two major
changes to the extension that have caused the other changes.

## 1. Tailwind CSS is a preprocessor

We now run all of our modifications in `enforce: 'pre'`. This means that
Tailwind CSS now gets the untransformed CSS files rather than the one
already going through postcss or lightningcss. We do this because
Tailwind CSS _is_ a preprocessor at the same level as those tools and we
do sometimes use the language in ways that [creates problems when it's
the input for other
bundlers](https://github.com/tailwindlabs/tailwindcss/pull/14269).

The correct solution here is to make Tailwind not depend on any other
transformations. The main reason we were not using the `enforce: 'pre'`
phase in Vite before was becuase we relied on the `@import` flattening
of postcss so we now have to do this manually. `@import` flattening is
now a concern that every Tailwind V4 client has to deal with so this
might actually be something we want to inline into tailwindcss in the
future.

## 2. A Vite config can have multiple Tailwind roots 

This is something that we have not made very explicit in the previous
iteration of the Vite plugin but we have to support multiple Tailwind
roots in a single Vite workspace. A Tailwind root is a CSS file that is
used to configure Tailwind. Technically, any CSS file can be the input
for `tailwindcss` but you have to add certain rules (e.g. `@import
"tailwindcss";`) to make the compiler do something.

A workspace can have multiple of these rules (e.g. by having different
Tailwind configures for different sub-pages). With the addition of
[support for `@source`
rules](https://github.com/tailwindlabs/tailwindcss/pull/14078) and [JS
config files](https://github.com/tailwindlabs/tailwindcss/pull/14239),
Tailwind roots become more complex and can have a custom list of
_dependencies_ (that is other JavaScript modules the compiler includes
as part of these new rules). In order to _only rebuild the roots we need
to_, we have to make this separation very clear.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-04 10:09:24 +02:00
Philipp Spiess
390e2d3e8d
Allow @plugin and @config to point to TS files (#14317)
Tailwind V3 used [jiti](https://github.com/unjs/jiti/) to allow
importing of TypeScript files for the config and plugins. This PR adds
the new Jiti V2 beta to our `@tailwindcss/node` and uses it if a native
`import()` fails. I added a new integration test to the CLI config
setup, to ensure it still works with our module cache cleanup.
2024-09-03 18:35:39 +02:00
Philipp Spiess
191c544c67
CSS theme(): Add unit test that combines CSS variable syntax with opacity modifier (#14323)
This PR adds a new test case to the branches that test the CSS `theme()`
function with the CSS variable syntax. The new case includes an opacity
modifier and ensures that the opacity is properly added.
2024-09-03 18:01:04 +02:00
Philipp Spiess
adc8dfb1a2
Ensure CSS theme() functions are evaluated in media query ranges with collapsed whitespace (#14321)
Fixes #14320

This PR adds `>`, `<`, and `=` as separators into the CSS value parser.
This is necessary because [`@media` range
context](https://www.w3.org/TR/mediaqueries-4/#mq-range-context) does
not require spaces around these operators so something like this is a
valid value for the range syntax:

```css
@media (40rem<width<=48rem) { 
  /* ... */
}
```

If you add our CSS `theme()` function to the mix, this rule look like
that:

```css
@media (theme(--breakpoint-sm)<width<=theme(--breakpoint-md)) {
  /* ... */
}
```

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-03 17:27:18 +02:00
Philipp Spiess
a1d56d8e24
Ensure content globs defined in @config files are relative to that file (#14314)
When you configure custom content globs inside an `@config` file, we
want to tread these globs as being relative to that config file and not
the CSS file that requires the content file. A config can be used by
multiple CSS configs.

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-03 16:54:08 +02:00
Adam Wathan
dcfaaac8f6
Prepare v4.0.0-alpha.21 (#14313)
<!--

👋 Hey, thanks for your interest in contributing to Tailwind!

**Please ask first before starting work on any significant new
features.**

It's never a fun experience to have your pull request declined after
investing a lot of time and effort into a new feature. To avoid this
from happening, we request that contributors create an issue to first
discuss any significant new features. This includes things like adding
new utilities, creating new at-rules, or adding new component examples
to the documentation.


https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md

-->

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-09-02 15:43:28 -04:00
Jordan Pittman
c65f20ace0
Support plugin options in CSS (#14264)
Builds on #14239 — that PR needs to be merged first.

This PR allows plugins defined with `plugin.withOptions` to receive
options in CSS when using `@plugin` as long as the options are simple
key/value pairs.

For example, the following is now valid and will include the forms
plugin with only the base styles enabled:

```css
@plugin "@tailwindcss/forms" {
  strategy: base;
}
```

We handle `null`, `true`, `false`, and numeric values as expected and
will convert them to their JavaScript equivalents. Comma separated
values are turned into arrays. All other values are converted to
strings.

For example, in the following plugin definition, the options that are
passed to the plugin will be the correct types:
- `debug` will be the boolean value `true`
- `threshold` will be the number `0.5`
- `message` will be the string `"Hello world"`
- `features` will be the array `["base", "responsive"]`

```css
@plugin "my-plugin" {
  debug: false;
  threshold: 0.5;
  message: Hello world;
  features: base, responsive;
}
```

If you need to pass a number or boolean value as a string, you can do so
by wrapping the value in quotes:

```css
@plugin "my-plugin" {
  debug: "false";
  threshold: "0.5";
  message: "Hello world";
}
```

When duplicate options are encountered the last value wins:

```css
@plugin "my-plugin" {
  message: Hello world;
  message: Hello plugin; /* this will be the value of `message` */
}
```

It's important to note that this feature is **only available for plugins
defined with `plugin.withOptions`**. If you try to pass options to a
plugin that doesn't support them, you'll get an error message when
building:

```css
@plugin "my-plugin" {
  debug: false;
  threshold: 0.5;
}

/* Error: The plugin "my-plugin" does not accept options */
```

Additionally, if you try to pass in more complex values like objects or
selectors you'll get an error message:

```css
@plugin "my-plugin" {
  color: { red: 100; green: 200; blue: 300 };
}

/* Error: Objects are not supported in `@plugin` options. */
```

```css
@plugin "my-plugin" {
  .some-selector > * {
    primary: "blue";
    secondary: "green";
  }
}

/* Error: `@plugin` can only contain declarations. */
```

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-09-02 12:49:09 -04:00
Jordan Pittman
52012d90d7
Support loading config files via @config (#14239)
In Tailwind v4 the CSS file is the main entry point to your project and
is generally configured via `@theme`. However, given that all v3
projects were configured via a `tailwind.config.js` file we definitely
need to support those. This PR adds support for loading existing
Tailwind config files by adding an `@config` directive to the CSS —
similar to how v3 supported multiple config files except that this is
now _required_ to use a config file.

You can load a config file like so:

```
@import "tailwindcss";
@config "./path/to/tailwind.config.js";
```

A few notes:
- Both CommonJS and ESM config files are supported (loaded directly via
`import()` in Node)
- This is not yet supported in Intellisense or Prettier — should
hopefully land next week
- TypeScript is **not yet** supported in the config file — this will be
handled in a future PR.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-09-02 18:03:16 +02:00
Philipp Spiess
de3c696f07 Fix changelog 2024-09-02 17:36:04 +02:00
Philipp Spiess
c6e4dabfb2
Remove named opacity support for color opacity modifiers (#14278)
Right now if you have a custom opacity theme value configured like this…

```css
@theme {
  --opacity-disabled: 50%;
}
```

…then you can use that named opacity value as a color opacity modifier
like this:

```html
<div class="bg-red-500/disabled">
```

We think this behavior is confusing. The color opacity modifier is not
setting opacity but the alpha value of a color. Opacity is for setting
the opacity of an element, so the custom names you'd come up with are
named after those situations, which makes them not seem appropriate for
color modifiers.
2024-09-02 16:41:38 +02:00
Philipp Spiess
d9e3fd613b
Add standalone CLI (#14270)
This PR adds a new standalone client: A single-binary file that you can
use to run Tailwind v4 without having a node setup. To make this work we
use Bun's single-binary build which can properly package up native
modules and the bun runtime for us so we do not have to rely on any
expand-into-tmp-folder-at-runtime workarounds.

When running locally, `pnpm build` will now standalone artifacts inside
`packages/@tailwindcss-standalone/dist`. Note that since we do not build
Oxide for other environments in the local setup, you won't be able to
use the standalone artifacts for other platforms in local dev mode.

Unfortunately Bun does not have support for Windows ARM builds yet but
we found that using the `bun-baseline` runtime for Windows x64 would
make the builds work fine in ARM emulation mode:

![Screenshot
windows](https://github.com/user-attachments/assets/5b39387f-ec50-4757-9469-19b98e43162d)


Some Bun related issues we faced and worked around:

- We found that the regular Windows x64 build of `bun` does not run on
Windows ARM via emulation. Instead, we have to use the `bun-baseline`
builds which emulate correctly.

- When we tried to bundle artifacts with [embed
directories](https://bun.sh/docs/bundler/executables#embed-directories),
node binary dependencies were no longer resolved correctly even though
they would still be bundled and accessible within the [`embeddedFiles`
list](https://bun.sh/docs/bundler/executables#listing-embedded-files).
We worked around this by using the `import * as from ... with { type:
"file" };` and patching the resolver we use in our CLI.
  
  
- If you have an import to a module that is used as a regular import
_and_ a `with { type: "file" }`, it will either return the module in
both cases _or_ the file path when we would expect only the `with {
type: "file" }` import to return the path. We do read the Tailwind CSS
version via the file system and `require.resolve()` in the CLI and via
`import * from './package.json'` in core and had to work around this by
patching the version resolution in our CLI.
 
  ```ts
  import packageJson from "./package.json"
  import packageJsonPath from "./package.json" with {type: "file"}
  
  // We do not expect these to be equal
  packageJson === packageJsonPath 
  ```
- We can not customize the app icon used for Windows `.exe` builds
without decompiling the binary. For now we will leave the default but
one workaround is to [use tools like
ResourceHacker](698d9c4bd1)
to decompile the binary first.

---------

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
2024-09-02 15:23:46 +02:00