Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: tailwindcss v4 #25

Draft
wants to merge 30 commits into
base: main
Choose a base branch
from
Draft

feat: tailwindcss v4 #25

wants to merge 30 commits into from

Conversation

schoero
Copy link
Owner

@schoero schoero commented Apr 30, 2024

Continuation of #18

Add support for tailwindcss v4.

schoero added 4 commits May 4, 2024 20:19
* refactor: use native test runner, remove vite, use tsc

* ci: use `zsh` to glob test files

* ci: use `glob` package for older node versions that don't support glob patterns

* ci: remove eslint9 workaround

* style: fix linting issues

* chore: update eslint config

* chore: fix glob pattern on windows

* ci: upgrade to node 22

* ci: update npm test command to use "npm test" instead of "npm t"
@schoero
Copy link
Owner Author

schoero commented May 5, 2024

Status update

cc: @zcf0508

There were (and still are) some issues making this plugin compatible with tailwindcss v4.

  • Tailwindcss v4 is completely different from an API perspective, so I needed a way to conditionally import the different APIs from tailwindcss.
    ESLint is not capable of asynchronous rules, so I cannot use await import() to dynamically import the respective functions. Since this plugin is written as ESM, require() is also not available for synchronous imports. I have experimented with numerous variants to work around this limitation, two of them I considered to be viable:

    • Create different entrypoints for each tailwindcss version, load the correct APIs and use dependency injection to pass them to the rules. This would eventually end up in a breaking change and I didn't like the resulting API.
    • Change some specific files to CJS and use require() to load the APIs. Since ESM is capable of importing CJS, the API can be kept as is.

    I decided to choose the second option but had no luck getting it to work in a way that those files would be kept as CJS in the transpiled output using the current build system with vite.
    Therefore I decided to get rid of vite and use tsc for transpilation and the native node:test runner for the tests instead.

  • Tailwindcss v4 does not handle imports in the new css configs internally. They propose to use postcss-import to load, parse and resolve the imports in the css config but again postcss-import is asynchronous.
    I ended up using lightningcss as I have read in their announcement blog post that their goal is to eventually switch to lightningcss as well.

TODO

@zcf0508
Copy link

zcf0508 commented May 19, 2024

I was inspired to create the feature from https://github.com/hyoban/tailwindcss-classname-highlight/blob/main/src/index.ts#L78, and wish this is helpful for you to resolve the problem.

For now, I think we can publish an alpha version for v4 users, as tailwind v4 has not been release. Or we can release two versions that one for v3 and one for v4 to prevent code coupling and enhance clarity.

@schoero
Copy link
Owner Author

schoero commented May 19, 2024

My current branch doesn't yet work with tailwindcss v4 because I couldn't yet figure out how to resolve the @import statements in the css files.

I think the approach taken in https://github.com/hyoban/tailwindcss-classname-highlight is pretty hacky as it just reads all css files and creates the tailwind context from them. There is no resolving of import statements and the tailwind internals and it also includes css files that may not be intended for tailwindcss.

The same problem exists in the branch you created for #18.

I got pretty deep into a rabbit hole trying to resolve this problem and I have posted my findings in my comment above.

In the anouncement blog post, they wrote about integrating lighntingcss and automatically handle those problems.

In their codebase as it is right now, they have not done this integration yet and they still rely on postcss, which is not an option for eslint plugins, because postcss-import is async.

The plan is now to wait for tailwindcss v4 to be more mature and let them figure out the solution to this problem. Any additional effort I put into this right now will eventually be wasted time in the long run and this is not sustainable for me right now.

What I can do prior to this, is to make the plugin work with v4 in a way that it no longer crashes.
The sort-classes rule is the only rule that depends on tailwindcss internals. I can refactor the plugin so that the tailwind internals are not loaded until they are used.

If you disable the sort-classes rule, or change the order to asc for example, there would be no need to load the tailwind internals and the plugin would therefore not crash.

I have done a lot of preparation work in #26 for this.

@schoero
Copy link
Owner Author

schoero commented May 24, 2024

I created a feature request in lightningcss for synchronous custom resolvers: parcel-bundler/lightningcss#747

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants