sveltejs / svelte-preprocess

A ✨ magical ✨ Svelte preprocessor with sensible defaults and support for: PostCSS, SCSS, Less, Stylus, Coffeescript, TypeScript, Pug and much more.
MIT License
1.73k stars 147 forks source link

Sass with non-ASCII characters can lead to unexpected/invalid `@charset` in output CSS #566

Open alecglassford opened 1 year ago

alecglassford commented 1 year ago

Describe the bug

When SCSS input contains any non-ASCII characters, Sass adds @charset: "UTF-8"; to CSS output (see discussion in https://github.com/sass/dart-sass/issues/567).

@charset in CSS has very specific rules: it should only appear at the beginning of a CSS file and only once. (https://developer.mozilla.org/en-US/docs/Web/CSS/@charset, https://drafts.csswg.org/css-syntax-3/#charset-rule)

Since svelte-preprocess runs Sass on each component separately, this can cause @charset to be generated multiple times (once per component with non-ASCII characters) or in the "wrong" place (intermediate CSS output that does not wind up at the beginning of the final CSS bundle).

Ultimately, it's the responsibility of downstream tools to ensure the CSS generated by each component gets bundled together in a valid way. In the case I've encountered, it's rollup-plugin-css-only that can cause a problem when concatenating the CSS from each Svelte component, so I've filed https://github.com/thgh/rollup-plugin-css-only/issues/54. (As a counterpoint, Vite correctly deduplicates and hoists @charset produced by intermediate outputs: see https://github.com/vitejs/vite/pull/7678 and https://github.com/vitejs/vite/pull/7691).

Still, I figured I'd file a bug in this repo because anyone else using sass + svelte-preprocess + rollup together are likely to encounter this problem (and the docs in this repo do point users toward this combo of tools!). It would probably be fair to close out this bug, since the most problematic behavior is the responsibility of rollup-plugin-css-only (and probably other downstream CSS handlers, I would guess!) But since this problem can be subtly introduced during the svelte-preprocess stage, it might be worth considering some mitigation (see "Expected behavior" section for suggestions).

Logs N/A

To Reproduce See this minimal reproduction: https://gist.github.com/alecglassford/e95ccb506089f76479bf170a0e96f270

Expected behavior

Stacktraces N/A

Information about your project: N/A

Additional context Users might run into a similar problem if they use plain CSS @import in their SCSS, since this type of statement also must only appear at the top of CSS output.)

```js
preprocess: sveltePreprocess({
    scss: {
        charset: false,
    },
})
```