vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.02k stars 6.02k forks source link

Support Vanilla JS CSS Modules / CSS import attributes #17700

Open m-jung opened 1 month ago

m-jung commented 1 month ago

Description

It seems that Vite does not support imports of CSS Style Sheets in ES modules with or without import attributes like import styles from './styles.css' or import styles from './styles.css' with { type: 'css' }.

A workaround seems to be the ?inline query parameter like import styles from './styles.css?inline'.

I see that import attributes are at state 3 still, but constructable stylesheets aren't and ES-Modules are both in base-line now.

So i'd like to the (configurable) support for import of CSS as CSSStyleSheet.

Suggested solution

A configurable option to handle imports of *.css as CSS Modules / CSSStyleSheet.

Alternative

No response

Additional context

Why don't you just use the ?inline-query? We're targeting browsers with native CSS Module import support, like Chrome, for internal enterprise web apps. Third parties now want to start using our custom elements which make use of those imports.

Since they to not have access to the source and we cannot add ?inline to all imports, the potential users are limited to use the bundled version, which hinders them to extend und bundle custom-element on their behalf.

See the reproducer on stackblitz which illustrates the issue, when running npm run build

Validations

stackblitz[bot] commented 1 month ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

klebba commented 3 weeks ago

It appears that Vite deliberately strips the import attribute syntax:

https://github.com/vitejs/vite/blob/3af02bde7e7f26889d5c0eb300219c43ed1293ad/packages/vite/src/node/plugins/importAnalysis.ts#L494-L497

Worth noting that import attributes are supported by TypeScript along with native support in Chrome.

It would be great it vite could avoid adulterating the import syntax in my code so that the runtime itself can interpret what I authored.

The workaround right now:

// vite strips the type declaration syntax
import stylesheet from './demo-badge.css' with { type: 'css' };

// vite does not modify the syntax
const { default: stylesheet } = await import('./demo-badge.css', { with: { type: 'css' } });

Some prior comments on the topic:

nolanlawson commented 1 week ago

As a first step toward solving this issue, I think it might be nice to have an option to disable the current CSS runtime behavior entirely.

In other words, *.css files would be treated the same as any non-JS file type (e.g. *.mdx, .tsx, etc.), and plugins would be able to transform the CSS files to JS as needed.

This would fit the usecase of the LWC framework – in LWC, importing a CSS file returns a function:

import stylesheet from './styles.css' // imports a function that returns a string

Currently, this functionality doesn't work in Vite even with our Rollup plugin (@lwc/rollup-plugin), due to Vite's default handling of CSS. (I have a minimal repro of this issue using Vitest.)

Unfortunately, the ?inline or with { type: 'css' } solutions would not work for us, because it would be a breaking change for existing components (which do not use such syntax when importing stylesheets).

Potentially, our Rollup plugin could apply these transformations itself (to the .js files that are importing .css files), but I wonder if a more generic "disable the current CSS behavior" option would be a simpler solution for other web component frameworks in general.