Skip to content

Commit 3e9d7e3

Browse files
bluwydominikg
andauthored
fix(hmr): handle compiler warning caused by injected css selector (#154)
* fix: suppress css warning when no template * chore: add changeset * docs(faq): add info about global styles * docs(faq): fix typo * feat: update warning handling * feat: improved warning message handling for extra warnings * fix: spelling of scopeable and duplicate changeset * docs: fix typo in changeset Co-authored-by: dominikg <dominik.goepel@gmx.de>
1 parent eea0999 commit 3e9d7e3

File tree

6 files changed

+85
-6
lines changed

6 files changed

+85
-6
lines changed

.changeset/six-ears-grow.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/vite-plugin-svelte': minor
3+
---
4+
5+
Improve dev warning message for components including only unscoped styles (fixes #153)

docs/faq.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,34 @@ Bad:
4545
<script type="text/typescript"></script>
4646
```
4747

48+
### Where should I put my global styles?
49+
50+
Global styles should always be placed in their own stylesheet files whenever possible, and not in a Svelte component's `<style>` tag. The stylesheet files can then be imported directly in JS and take advantage of Vite's own style processing. It would also significantly improve the dev server startup time.
51+
52+
Good:
53+
54+
```scss
55+
/* global.scss */
56+
html {
57+
color: $text-color;
58+
}
59+
```
60+
61+
```js
62+
// main.js
63+
import './global.scss';
64+
```
65+
66+
Bad:
67+
68+
```svelte
69+
<style lang="scss">
70+
:global(html) {
71+
color: $text-color;
72+
}
73+
</style>
74+
```
75+
4876
### How do I add a Svelte preprocessor from a Vite plugin?
4977

5078
If you are building a Vite plugin that transforms CSS or JS, you can add a `api.sveltePreprocess: PreprocessorGroup` to your Vite plugin definition and it will be added to the list of Svelte preprocessors used at runtime.

packages/playground/preprocess-with-vite/src/App.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<script lang="ts">
22
import Foo from './Foo.svelte';
3+
import Bar from './Bar.svelte';
34
const world: string = 'world'; // edit world and save to see hmr update
45
</script>
56

67
<h1 class="foo">Hello {world}</h1>
78
<p>This is styled with scss using darken fn</p>
89
<Foo />
10+
<Bar />
911

1012
<style lang="scss">
1113
$blue: blue;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script>
2+
import Foo from './Foo.svelte';
3+
</script>
4+
5+
<Foo />
6+
7+
<style>
8+
:global(.note) {
9+
background-color: lightblue;
10+
}
11+
</style>

packages/vite-plugin-svelte/src/utils/log.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,9 @@ export const log = {
102102
export function logCompilerWarnings(warnings: Warning[], options: ResolvedOptions) {
103103
const { emitCss, onwarn, isBuild } = options;
104104
const warn = isBuild ? warnBuild : warnDev;
105-
warnings?.forEach((warning) => {
106-
if (!emitCss && warning.code === 'css-unused-selector') {
107-
return;
108-
}
105+
const notIgnoredWarnings = warnings?.filter((w) => !ignoreCompilerWarning(w, isBuild, emitCss));
106+
const extraWarnings = buildExtraWarnings(warnings, isBuild);
107+
[...notIgnoredWarnings, ...extraWarnings].forEach((warning) => {
109108
if (onwarn) {
110109
onwarn(warning, warn);
111110
} else {
@@ -114,6 +113,40 @@ export function logCompilerWarnings(warnings: Warning[], options: ResolvedOption
114113
});
115114
}
116115

116+
function ignoreCompilerWarning(
117+
warning: Warning,
118+
isBuild: boolean,
119+
emitCss: boolean | undefined
120+
): boolean {
121+
return (
122+
(!emitCss && warning.code === 'css-unused-selector') || // same as rollup-plugin-svelte
123+
(!isBuild && isNoScopableElementWarning(warning))
124+
);
125+
}
126+
127+
function isNoScopableElementWarning(warning: Warning) {
128+
// see https://github.com/sveltejs/vite-plugin-svelte/issues/153
129+
return warning.code === 'css-unused-selector' && warning.message.includes('"*"');
130+
}
131+
132+
function buildExtraWarnings(warnings: Warning[], isBuild: boolean): Warning[] {
133+
const extraWarnings = [];
134+
if (!isBuild) {
135+
const noScopableElementWarnings = warnings.filter((w) => isNoScopableElementWarning(w));
136+
if (noScopableElementWarnings.length > 0) {
137+
// in case there are multiple, use last one as that is the one caused by our *{} rule
138+
const noScopableElementWarning =
139+
noScopableElementWarnings[noScopableElementWarnings.length - 1];
140+
extraWarnings.push({
141+
...noScopableElementWarning,
142+
code: 'vite-plugin-svelte-css-no-scopable-elements',
143+
message: `No scopable elements found in template. If you're using global styles in the style tag, you should move it into an external stylesheet file and import it in JS. See https://github.com/sveltejs/vite-plugin-svelte/blob/main/docs/faq.md#where-should-i-put-my-global-styles.`
144+
});
145+
}
146+
}
147+
return extraWarnings;
148+
}
149+
117150
function warnDev(w: Warning) {
118151
log.info.enabled && log.info(buildExtendedLogMessage(w));
119152
}

packages/vite-plugin-svelte/src/utils/options.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,8 +426,8 @@ export interface ResolvedOptions extends Options {
426426
// extra options
427427
root: string;
428428
isProduction: boolean;
429-
isBuild?: boolean;
430-
isServe?: boolean;
429+
isBuild: boolean;
430+
isServe: boolean;
431431
server?: ViteDevServer;
432432
}
433433

0 commit comments

Comments
 (0)