23 Commits

Author SHA1 Message Date
Adam Wathan
65f6f7c1ca
Prepare alpha.8 release (#13203)
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2024-03-11 15:10:21 -04:00
Robin Malfait
d230f2e13b
Improve incremental builds (#13168)
* ensure we don't crash on deleted files

* change return type of `compile` to include a `rebuild()` function

This will allow us in the future to perform incremental rebuilds after
the initial rebuild. This is purely the API change so that we can
prepare all the call sites to use this new API.

* set `@tailwind utilities` nodes

Instead of replacing the node that represents the `@tailwind utilities`
with the generated AST nodes from the rawCandidates, we will set the
nodes of the `@tailwind utilities` rule to the AST nodes instead.

This way we dont' have to remove and replace the `@tailwind utilities`
rule with `n` new nodes. This will later allow us to track the
`@tailwindcss utilities` rule itself and update its `nodes` for
incremental rebuilds.

This also requires a small change to the printer where we now need to
print the children of the `@tailwind utilities` rule. Note: we keep the
same `depth` as-if the `@tailwindcss utilities` rule was not there.
Otherwise additional indentation would be present.

* move sorting to the `ast.sort()` call

This will allow us to keep sorting AST nodes in a single spot.

* move parser functions to the `DesignSystem`

This allows us to put all the parsers in the `DesignSystem`, this allows
us to scope the parsers to the current design system (the current theme,
current utility values and variants).

The implementation of these parsers are also using a `DefaultMap`
implementation. This allows us to make use of caching and only parse a
candidate, parse a variant or compile AST nodes for a given raw
candidate once if we've already done this work in the past.

Again, this is scoped to the `DesignSystem` itself. This means that if
the corresponding theme changes, then we will create a new
`DesignSystem` entirely and the caches will be garbage collected. This
is important because a candidate like `bg-primary` can be invalid in
`DesignSystem` A, but can be valid in `DesignSystem` B and vice versa.

* ensure we sort variants alphabetically by root

For incremental rebuilds we don't know all the used variants upfront,
which means that we can't sort them upfront either (what we used to do).

This code now allows us to sort the variants deterministically when
sorting the variants themselves instead of relying on the fact that they
used to be sorted before.

The sort itself could change slightly compared to the previous
implementation (especially when you used stacked variants in your
candidates), but it will still be deterministic.

* replace `localeCompare` comparisons

Use cheaper comparisons than `localeCompare` when comparing 2 strings.
We currently don't care if it is 100% correctly sorted, but we just want
consistent sorting. This is currently faster compared to
`localeCompare`.

Another benefit is that `localeCompare` could result in
non-deterministic results if the CSS was generated on 2 separate
computers where the `locale` is different.

We could solve that by adding a dedicated locale, but it would still be
slower compared to this.

* track invalid candidates

When an incoming raw candidates doesn't produce any output, then we can
mark it as an invalid candidate. This will allow us to reduce the amount
of candidates to handle in incremental rebuilds.

* add initial incremental rebuild implementation

This includes a number of steps:

1. Track the `@tailwind utilities` rule, so that we can adjust its nodes
   later without re-parsing the full incoming CSS.
2. Add the new incoming raw candidates to the existing set of
   candidates.
3. Parse the merged set to `compileCandidates` (this can accept any
   `Iterable<string>`, which means `string[]`, `Set<string>`, ...)
4. Get the new AST nodes, update the `@tailwind utilities` rule's nodes
   and re-print the AST to CSS.

* improvement 1: ignore known invalid candidates

This will reduce the amount of candidates to handle. They would
eventually be skipped anyway, but now we don't even have to re-parse
(and hit a cache) at all.

* improvement 2: skip work, when generated AST is the same

Currently incremental rebuilds are additive, which means that we are not
keeping track if we should remove CSS again in development.

We can exploit this information, because now we can quickly check the
amoutn of generated AST nodes.

- If they are the same then nothing new is generated — this means that
  we can re-use the previous compiled CSS. We don't even have to
  re-print the AST because we already did do that work in the past.
- If there are more AST nodes, something new is generated — this means
  that we should update the `@tailwind utilities` rule and re-print the
  CSS. We can store the result for future incremental rebuilds.

* improvement 3: skip work if no new candidates are detected

- We already know a set of candidates from previous runs.
- We also already know a set of candidates that are invalid and don't
  produce anything.

This means that an incremental rebuild could give us a new set of
candidates that either already exist or are invalid.

If nothing changes, then we can re-use the compiled CSS.

This actually happens more often than you think, and the bigger your
project is the better this optimization will be.

For example:

```
// Imagine file A exists:
<div class="flex items-center justify-center"></div>
<button class="text-red-500">Delete</button>
```

```
// Now you add a second file B:
<div class="text-red-500 flex"></div>
```

You just created a brand new file with a bunch of HTML elements and
classes, yet all of the candidates in file B already exist in file A, so
nothing changes to the actual generated CSS.

Now imagine the other hundreds of files that already contain hundreds of
classes.

The beauty of this optimization is two-fold:

- On small projects, compiling is very fast even without this check.
  This means it is performant.
- On bigger projects, we will be able to re-use existing candidates.
  This means it stays performant.

* remove `getAstNodeSize`

We can move this up the tree and move it to the `rebuild` function
instead.

* remove invalid candidate tracking from `DesignSystem`

This isn't used anywhere but only in the `rebuild` of the compile step.
This allows us to remove it entirely from core logic, and move it up the
chain where it is needed.

* replace `throwOnInvalidCandidate` with `onInvalidCanidate`

This was only needed for working with `@apply`, now this logic _only_
exists in the code path where we are handling `@apply`.

* update `compile` API signature

* update callsite of `compile()` function

* fix typo
2024-03-11 14:24:49 -04:00
Robin Malfait
388d1b0298
add "access": "public" to publishConfig (#13164) 2024-03-08 22:04:05 +01:00
Robin Malfait
d68a4af58e
Prepare next 4.0.0-alpha.7 release (#13163)
* bump versions to `4.0.0-alpha.7`

* update changelog
2024-03-08 21:46:03 +01:00
Kris Braun
065bbd3c99
[v4] Add provenance to all published packages (#13160)
* Add provenance to all packages

Based on #13097 by @saibotk

Add [provenance](https://docs.npmjs.com/generating-provenance-statements) for all published packages.

---
Co-authored-by: saibotk <git@saibotk.de>

* Document reason for id-token permission

* Update changelog
2024-03-08 21:30:13 +01:00
Can Kolay
0e1af11b30
[v4] Android binaries for Oxide (#13115) 2024-03-08 12:08:24 -05:00
Robin Malfait
d288c52780
bump versions to 4.0.0-alpha.6 2024-03-07 16:00:23 +01:00
Robin Malfait
9864b9c9cd
bump versions to 4.0.0-alpha.5 2024-03-07 00:40:10 +01:00
Jordan Pittman
e2dcbad153
Always honor git ignore files (#13119) 2024-03-06 18:24:34 -05:00
Robin Malfait
722f436956
bump versions to 4.0.0-alpha.4 (#13113) 2024-03-06 21:00:27 +01:00
Robin Malfait
dd2c68080b
bump versions to 4.0.0-alpha.3 (#13106) 2024-03-06 17:27:17 +01:00
Robin Malfait
0a2b319ada
bump versions to 4.0.0-alpha.2 2024-03-06 15:13:45 +01:00
Robin Malfait
bab74da932
Prep alpha release (#13089)
* use `next` as default release channel

* bump versions to `4.0.0-alpha.1`
2024-03-05 14:46:10 -05:00
Robin Malfait
a68de1df27
introduce v4 codebase 2024-03-05 14:29:15 +01:00
Robin Malfait
32cf8aa0fb
remove v3 codebase 2024-03-05 13:29:12 +01:00
Adam Wathan
47dbb4a2b3 Add * variant for targeting direct children (#12551)
* add `*` as child variant

* add `*` as allowed variant character

* update test to reflect Lightning CSS output

* add `childVariant` test

* Update changelog

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Co-authored-by: Gregor Kaczmarczyk <github@aggreggator.de>
2023-12-18 13:58:22 -05:00
Robin Malfait
51157717da
Add gradient color stop position utilities (#10886)
* add gradient color stop positions

* update tests to include gradient position color stop reset values

* add dedicated color stop position tests

* use `%` sign in the name of the uility

* update changelog

* ensure `length` values and css variables work
2023-03-28 15:39:00 +02:00
depfu[bot]
e96071a0e4
Update @napi-rs/cli to version 2.15.2 2023-03-28 15:39:00 +02:00
Robin Malfait
7e9a53f6cb
Enable ESM and TS based config files (#10785)
* add `jiti` and `detective-typescript` dependencies

* use `jiti` and `detective-typescript`

Instead of `detective`, this way we will be able to support
`tailwind.config.ts` files and `ESM` files.

* use `@swc/core` instead of the built-in `babel` form `jiti`

* update changelog

* add `jiti` and `detective-typescript` dependencies to `stable`

* use `sucrase` to transform the configs

* add `sucrase` dependency to `stable` engine

* make loading the config easier

* use abstracted loading config utils

* WIP: make `load` related files public API

* use new config loader in PostCSS plugin

* add list of default config files to look for

* cleanup unused arguments

* find default config path when using CLI

* improve `init` command

* make eslint happy

* keep all files in `stubs` folder

* add `tailwind.config.js` stub file

* Initialize PostCSS config using the same format as Tailwind config

* Rename config content stubs to config.*.js

* Improve option descriptions for init options

* Remove unused code, remove `constants` file

* Fix TS warning

* apply CLI changes to the Oxide version

* update `--help` output in CLI tests

* WIP: make tests work on CI

TODO: Test all combinations of `--full`, `--ts`, `--postcss`, and `--esm`.

* wip

* remove unused `fs`

* Fix init tests

Did you know you could pass an empty args to a command? No? Me neither. ¯\_(ツ)_/¯

* bump `napi-derive`

* list extensions we are interested in

* no-op the `removeFile` if file doesn't exist

* ensure all `init` flags work

* ensure we cleanup the new files

* test ESM/CJS generation based on package.json

* remove unnecessary test

We are not displaying output in the `--help` anymore based on whether
`type: module` is present or not.
Therefore this test is unneeded.

* only look for `TypeScript` files when the entryFile is `TypeScript` as well

* refactor `load` to be `loadConfig`

This will allow you to use:

```js
import loadConfig from 'tailwindcss/loadConfig'

let config = loadConfig("/Users/xyz/projects/my-app/tailwind.config.ts")
```

The `loadConfig` function will return the configuration object based on
the given absolute path of a tailwind configuration file.

The given path can be a CJS, an ESM or a TS file.

* use the `config.full.js` stub instead of the `defaultConfig.stub.js` file

The root `defaultConfig` is still there for backwards compatibilty
reasons. But the `module.exports = requrie('./config.full.js')` was
causing some problems when actually using tailwindcss.

So dropped it instead.

* apply `load` -> `loadConfig` changes to `Oxide` engine CLI

* ensure we write the config file in the Oxide engine

* improve type in Oxide engine CLI

* catch errors instead of checking if the file exists

A little smaller but just for tests so doesn't matter too much here 👍

* ensure we publish the correct stub files

---------

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Nate Moore <nate@natemoo.re>
Co-authored-by: Enzo Innocenzi <enzo@innocenzi.dev>
2023-03-15 17:04:18 -04:00
depfu[bot]
5bb351ea75 Update @napi-rs/cli to version 2.14.8 2023-03-08 10:07:12 +00:00
depfu[bot]
6cf5ab43a4 Update @napi-rs/cli to version 2.14.7 2023-02-15 10:06:20 +00:00
Adam Wathan
ed8ff92b03
Always sort candidates (#10382)
* Always sort candidates

* Sort candidates in Rust in Oxide engine

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2023-01-21 10:52:02 -05:00
Robin Malfait
2a403267d8
Oxide (#10252)
* temporarily disable workflows

* add oxide

Our Rust related parts

* use oxide

- Setup the codebase to be able to use the Rust parts based on an
  environment variable: `OXIDE=1`.
- Setup some tests that run both the non-Rust and Rust version in the
  same test.
- Sort the candidates in a consistent way, to guarantee the order for
  now (especially in tests).
- Reflect sorting related changes in tests.
- Ensure tests run in both the Rust and non-Rust version. (Some tests
  are explicitly skipped when using the Rust version since we haven't
  implemented those features yet. These include: custom prefix,
  transformers and extractors).
  - `jest`
  -`OXIDE=1 jest`

* remove into_par_iter where it doesn't make sense

* cargo fmt

* wip

* enable tracing based on `DEBUG` env

* improve CI for the Oxide build

* sort test output

This happened because the sorting happens in this branch, but changes
happened on the `master` branch.

* add failing tests

I noticed that some of the tests were failing, and while looking at
them, it happened because the tests were structured like this:

```html
    <div
      class="
        backdrop-filter
        backdrop-filter-none
        backdrop-blur-lg
        backdrop-brightness-50
        backdrop-contrast-0
        backdrop-grayscale
        backdrop-hue-rotate-90
        backdrop-invert
        backdrop-opacity-75
        backdrop-saturate-150
        backdrop-sepia
      "
    ></div>
```

This means that the class names themselves eventually end up like this: `backdrop-filter-none\n`
-> (Notice the `\n`)

/cc @thecrypticace

* fix range to include `\n`

* Include only unique values for tests

Really, what we care about most is that the list contains every expected candidate. Not necessarily how many times it shows up because while many candidates will show up A LOT in a source text we’ll unique them before passing them back to anything that needs them

* Fix failing tests

* Don’t match empty arbitrary values

* skip tests in oxide mode regarding custom separators in arbitrary variants

* re-enable workflows

* use `@tailwindcss/oxide` dependency

* publish `tailwindcss@oxide`

* drop prepublishOnly

I don't think we actually need this anymore (or even want because this
is trying to do things in CI that we don't want to happen. Aka, build
the Oxide Rust code, it is already a dependency).

* WIP

* Defer to existing CLI for Oxide

* Include new compiled typescript stuff when publishing

* Move TS to ./src/oxide

* Update scripts

* Clean up tests for TS

* copy `cli` to `oxide/cli`

* make CLI files TypeScript files

* drop --postcss flag

* setup lightningcss

* Remove autoprefixer and cssnano from oxide CLI

* cleanup Rust code a little bit

- Drop commented out code
- Drop 500 fixture templates

* sort test output

* re-add `prepublishOnly` script

* bump SWC dependencies in package-lock.json

* pin `@swc` dependencies

* ensure to install and build oxide

* update all GitHub Workflows to reflect Oxide required changes

* sort `content-resolution` integration tests

* add `Release Insiders — Oxide`

* setup turbo repo + remote caching

* use `npx` to invoke `turbo`

* setup unique/proper package names for integration tests

* add missing `isomorphic-fetch` dependency

* setup integration tests to use `turborepo`

* scope tailwind tasks to root workspace

* re-enable `node_modules` cache for integration tests

* re-enable `node_modules` cache for main CI workflow

* split cache for `main` and `oxide` node_modules

* fix indent

* split install dependencies so that they can be cached individually

* improve GitHub actions caching

* use correct path for oxide node_modules (crates/node)

* ensure that `cargo install` always succeeds

cargo install X, on CI will fail if it already exists.

* figure out integration tests with turbo

* tmp: use `npm` instead of `turbo`

* disable `fail-fast`

This will allow us to run integration tests so that it still caches the
succesful ones.

* YAML OH YAML, Y U WHITESPACE SENSITIVE

* copy the oxide-ci workflow to release-oxide

* make `oxide-ci` a normal CI workflow

Without publishing

* try to cache cargo and node_modules for the oxide build

* configure turbo to run scripts in the root

* explicitly skip failing test for the Oxide version

* run oxide tests in CI

* only use build script for root package

* sync package-lock.json

* do not cache node_modules for each individual integration

* look for hoisted `.bin`

* use turbo for caching build tailwind css in integration tests

* Robin...

* try to use the local binary first

* skip installing integration test dependencies

Should already be installed due to workspace usage

* Robin...

* drop `output.clean`

* explicitly add `mini-css-extract-plugin`

* drop oxide-ci, this is tested by proxy

* ensure oxide build is used in integration tests

This will ensure the `@tailwindcss/oxide` dependency is available
(whether we use it or not).

* setup Oxide shim in insiders release

* add browserslist dependency

* use `install:all` script name

Just using `install` as a script name will be called when running
`npm install`.
Now that we marked the repo as a `workspace`, `npm install` will run
install in all workspaces which is... not ideal.

* tmp: enable insiders release in PRs

Just to check if everything works before merging. Can be removed once
tested.

* don't cache node_modules?

I feel there is some catch 22 going on here.
We require `npm install` to build the `oxide/crates/node` version.
But we also require `oxide/crates/node` for the `npm install` becaus of
the dependency: `"@tailwindcss/oxide": "file:oxide/creates/node"`

* try to use `oxide/crates/node` as part of the workspace

* let's think about this

Let's try and cache the `node_modules` and share as much as possible.
However, some scripts still need to be installed specific to the OS.

Running `npm install` locally doesn't throw away your `node_modules`,
so if we just cache `node_modules` but also run `npm install` that
should keep as much as possible and still improve install times since
`node_modules` is already there.

I think.

* ensure generated `index.js` and `index.d.ts` files are considered outputs

* use `npx napi` instead of `napi` directly

* include all `package-lock.json` files

* normalize caching further in all workflows

* drop nested `package-lock.json` files

* `npm uninstall mini-css-extract-plugin && npm install mini-css-extract-plugin --save-dev`

* bump webpack-5 integration tests dependencies

* only release insiders on `master` branch

* tmp: let's figure out release insiders oxide

* fix little typo

* use Node 18 for Oxide Insiders

* syncup package-lock.json

* let's try node 16

Node 18 currently fails on `Build x86_64-unknown-linux-gnu (OXIDE)`
Workflow.

Install Node.JS output:

```
Environment details
Warning: /__t/node/18.13.0/x64/bin/node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /__t/node/18.13.0/x64/bin/node)
/__t/node/18.13.0/x64/bin/node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /__t/node/18.13.0/x64/bin/node)

Warning: node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)
```

* bump some Node versions

* only release oxide insiders on `master` branch

* don't cache `npm`

* bump napi-rs

Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
2023-01-13 12:22:00 +01:00