sveltejs / vite-plugin-svelte

Svelte plugin for http://vitejs.dev/
MIT License
844 stars 103 forks source link

Handle `<style global>` in dev #834

Closed kevinflint closed 8 months ago

kevinflint commented 8 months ago

Describe the problem

Related to: https://github.com/sveltejs/vite-plugin-svelte/issues/153

For <style> blocks vitePreprocess prepends/append a * {} causing a .hash {} to be generated. AFAIK, there are good reasons for this (see related issue).

@dominikg

This extra * {} is used to ensure that the svelte compiler adds the components css-hash class to every element of the rendered template. Which in turn means we can get more "css-only" updates when editing classes in template and style sections of a component.

However when a block has styles that must be global, but are tightly coupled to the component, it is frustrating.

Describe the proposed solution

Ideally, vitePreprocess should support the <style global> pattern and for <style global> blocks it should not emit a * {} to cause a hash class to be generated for the component.

Alternatives considered

Documentation would suggest that instead these styles should be moved into a separate .css file (e.g. +page.css or Component.css).

However this alternative is undesirable when the styles are tightly scoped to a specific .svelte component, but need to be global for practical reasons, e.g.

Importance

nice to have

dominikg commented 8 months ago

<style global> is a feature of svelte-preprocess https://github.com/sveltejs/svelte-preprocess?tab=readme-ov-file#global-attribute

iirc it just wraps the content in a :global . But if you want to target unknown children, it should always happen with a scope selector, or the styles can "bleed out".

so this should really lead to a warning at least. we may be able to test for the global attribute but i have reservations against it as it could be misunderstood as blessing a feature thats problematic and has more idiomatic alternatives available in vite

dominikg commented 8 months ago

Also the * {} rule is not added by vitePreprocess, but vite-plugin-svelte itself - only during dev.

If you need support for <style global>, you have to use svelte-preprocess instead of vitePreprocess.

It would still add the scope class during dev to improve DX with css updates. Are these dev-only scope classes an issue for you @kevinflint ? if yes please clarify why. The only rule they would have if there is no scoped style is * {}, so they won't affect the output visually at all.

kevinflint commented 8 months ago

I must be partially confused somehow.

In one of my use cases, I have a nested component I'm passing a class to as part of a 3rd-party library.

When using <style> :global(.scoped--nested-class) { ... } </style>, either the preprocess or the plugin is logging a warning and adding the hashClass to the component in 'production' builds.

Switching to using <style global> with svelte-preprocess is my currently implemented solution, but I'm worried about it being a temporary if the functionality of the two pre-processers drift apart.

I'd suggest that I appreciate the original warning, but that guard rails should generally have an escape hatch.

dominikg commented 8 months ago

if the rule is injected into builds that would be a bug. please file a separate issue and provide a reproduction. It seems unlikely though because like I said, the preprocessor is not used during build: https://github.com/sveltejs/vite-plugin-svelte/blob/d5a6dad8da2da3e505433e1290e9f2aa9bb82d4e/packages/vite-plugin-svelte/src/utils/compile.js#L84

dominikg commented 8 months ago

closing this as we do not plan to add <style global> support to vitePreprocess.

Additionally if you insist on using it, you can use onwarn to suppress messages with code vite-plugin-svelte-css-no-scopable-elements.

This only affects vite dev, during vite build vite-plugin-svelte does not inject anything into your styles or scripts (during dev, scripts get changed to add svelte-hmr).

kevinflint commented 8 months ago

Thanks for calling out the ability to use onwarn 🙂