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

[Svelte 5] Invalid CSS generated from Tailwind class names including [& and url( #14082

Closed
saadeghi opened this issue Oct 31, 2024 · 10 comments
Closed
Labels
awaiting submitter needs a reproduction, or clarification css Stuff related to Svelte's built-in CSS handling

Comments

@saadeghi
Copy link

saadeghi commented Oct 31, 2024

Describe the bug

@tailwindcss/vite@alpha gives Vite error if [&_div]:flex class name and url() from a Tailwind plugin exists in app together.

Note: I first opened an issue about this on Tailwind repo,
tailwindlabs/tailwindcss#14809
but apparently the issue is from how Svelte 5 compiles the class names, not from Tailwind.

✅ Having a Tailwind plugin like this works as expected

export default ({ addComponents }) => {
  addComponents({
    ".circlemask": {
      "mask-image": "url(\"data:image/svg+xml,%3csvg width='200' height='200' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle fill='black' cx='100' cy='100' r='100' fill-rule='evenodd'/%3e%3c/svg%3e\")"
    }
  })
}

✅ An arbitrary class name like [&_div]:flex works as expected.

❌ But having both in the same project using @tailwindcss/[email protected] causes Vite error:

[plugin:vite:css] [postcss] /src/tailwind.css:615:5: Unknown word

✅ This wasn't an issue in Tailwind CSS 3 or in Svelte 4
✅ The issue doesn't happen with @tailwindcss/[email protected]
It was really hard to debug for me because Vite just says Unknown word. No more details. After days I found that arbitrary class names with [] and & cause the issue if there's a plugin including url() with encoded image in it.


additional info from @thecrypticace

I did a bit of debugging here and it appears that Svelte has compiled the .svelte file before Tailwind is able to scan it. This causes [&_div]:flex to show up in the HTML as [&_div]:flex which produces invalid CSS and causes it to throw under certain situations.
In this case I think the presence of a potentially re-writable url(…) in the CSS causes additional validation to happen and is why the error is conditional on the inclusion of circlemask.
We don't have a workaround for this at the moment but wanted to drop in some details about what appears to be happening.

Reproduction

https://github.com/saadeghi/tw4alpha-vite-url-bug

it's an empty Vite/Svelte project.

npm i
npm run dev

There's [&_div]:flex class in src/routes/+page.svelte
There's a Tailwind plugin in src/myplugin.js

Logs

11:17:52 PM [vite] Pre-transform error: [postcss]/tw4alpha-vite-url-bug/src/tailwind.css:606:5: Unknown word
11:17:52 PM [vite] Error when evaluating SSR module /src/routes/+page.svelte:
|- CssSyntaxError: [postcss]/tw4alpha-vite-url-bug/src/tailwind.css:606:5: Unknown word
    at Input.error /tw4alpha-vite-url-bug/node_modules/postcss/lib/input.js:106:16)
    at Parser.unknownWord /tw4alpha-vite-url-bug/node_modules/postcss/lib/parser.js:593:22)
    at Parser.other /tw4alpha-vite-url-bug/node_modules/postcss/lib/parser.js:435:12)
    at Parser.parse /tw4alpha-vite-url-bug/node_modules/postcss/lib/parser.js:470:16)
    at parse /tw4alpha-vite-url-bug/node_modules/postcss/lib/parse.js:11:12)
    at new LazyResult /tw4alpha-vite-url-bug/node_modules/postcss/lib/lazy-result.js:133:16)
    at Processor.process /tw4alpha-vite-url-bug/node_modules/postcss/lib/processor.js:53:14)
    at compileCSS (file://tw4alpha-vite-url-bug/node_modules/vite/dist/node/chunks/dep-BWSbWtLw.js:36897:59)
    at async TransformPluginContext.transform (file://tw4alpha-vite-url-bug/node_modules/vite/dist/node/chunks/dep-BWSbWtLw.js:36170:11)
    at async PluginContainer.transform (file://tw4alpha-vite-url-bug/node_modules/vite/dist/node/chunks/dep-BWSbWtLw.js:49096:18)

CssSyntaxError: [postcss]/tw4alpha-vite-url-bug/src/tailwind.css:606:5: Unknown word
    at Input.error /tw4alpha-vite-url-bug/node_modules/postcss/lib/input.js:106:16)
    at Parser.unknownWord /tw4alpha-vite-url-bug/node_modules/postcss/lib/parser.js:593:22)
    at Parser.other /tw4alpha-vite-url-bug/node_modules/postcss/lib/parser.js:435:12)
    at Parser.parse /tw4alpha-vite-url-bug/node_modules/postcss/lib/parser.js:470:16)
    at parse /tw4alpha-vite-url-bug/node_modules/postcss/lib/parse.js:11:12)
    at new LazyResult /tw4alpha-vite-url-bug/node_modules/postcss/lib/lazy-result.js:133:16)
    at Processor.process /tw4alpha-vite-url-bug/node_modules/postcss/lib/processor.js:53:14)
    at compileCSS (file://tw4alpha-vite-url-bug/node_modules/vite/dist/node/chunks/dep-BWSbWtLw.js:36897:59)
    at async TransformPluginContext.transform (file://tw4alpha-vite-url-bug/node_modules/vite/dist/node/chunks/dep-BWSbWtLw.js:36170:11)
    at async PluginContainer.transform (file://tw4alpha-vite-url-bug/node_modules/vite/dist/node/chunks/dep-BWSbWtLw.js:49096:18) {
  reason: 'Unknown word',
  file: /tw4alpha-vite-url-bug/src/tailwind.css',


### System Info

```shell
Binaries:
    Node: 22.10.0 - ~/.nvm/versions/node/v22.10.0/bin/node
    Yarn: 1.22.22 - ~/.nvm/versions/node/v21.1.0/bin/yarn
    npm: 10.9.0 - ~/.nvm/versions/node/v22.10.0/bin/npm
    pnpm: 9.12.3 - ~/.nvm/versions/node/v21.1.0/bin/pnpm
    bun: 1.1.31 - ~/.bun/bin/bun
  Browsers:
    Chrome: 130.0.6723.71
    Firefox Nightly: 96.0a1
    Safari: 18.1
  npmPackages:
    svelte: ^5.1.9 => 5.1.9

Severity

blocking all usage of svelte

@dummdidumm
Copy link
Member

This comes from our attribute escaping, because & means the beginning of HTML entities. I'm not exactly sure if HTML is smart enough to detect if it's actually a real entity, and leaves it alone otherwise.

@Rich-Harris
Copy link
Member

It is:

document.body.innerHTML = `<div class="&"></div>`;
document.querySelector('div').className; // '&'

document.body.innerHTML = `<div class="&excl;"></div>`;
document.querySelector('div').className; // '!'

So — reluctantly — our escaping logic needs to get smart enough to handle this edge case.

@paoloricciuti
Copy link
Member

I think you should move your tailwind vite plugin before sveltekit in your vite config

@dummdidumm
Copy link
Member

If I put the tailwind plugin before the sveltekit plugin, as suggested by @paoloricciuti , this works. Is there any reason you can't do that?

@dummdidumm dummdidumm added the css Stuff related to Svelte's built-in CSS handling label Nov 1, 2024
@saadeghi
Copy link
Author

saadeghi commented Nov 4, 2024

@paoloricciuti @dummdidumm Changing the order like plugins: [tailwindcss(), sveltekit()], does not fix the issue.

@dummdidumm
Copy link
Member

Please provide an updated reproduction then - the given one causes no such error when changing the order.

@dummdidumm
Copy link
Member

@saadeghi in case you didn't notice the message - we need a reproduction that also fails when switching the order

@dummdidumm dummdidumm added the awaiting submitter needs a reproduction, or clarification label Nov 11, 2024
@saadeghi
Copy link
Author

Tried again, changing the order worked. Thanks!

Should I close this issue? or…
Because this looks like a workaround, than a fix.

@paoloricciuti
Copy link
Member

Because this looks like a workaround, than a fix.

The order of the plugins is important in vite. In this case you want to check the classes before anything touches them so I would close the issue.

What do you think @dummdidumm ?

@dummdidumm
Copy link
Member

As pointed out the order of plugins in Vite is important, so to me that's not a workaround but the proper solution. Therefore closing this for now - I asked a clarifying question regarding this in the related tailwind issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting submitter needs a reproduction, or clarification css Stuff related to Svelte's built-in CSS handling
Projects
None yet
Development

No branches or pull requests

4 participants