kit
kit copied to clipboard
Using Vite alises in <style>
Describe the problem
Currently if I do:
<style lang="scss">
@import '$lib/scss';
<style>
I get a Can't find stylesheet to import. error. While a normal path that doesn't use aliases works.
I also get an error in my editor (VSCode + Svelte extension) when I use Vite aliases in the <style> tag.
Describe the proposed solution
It should work with Vite aliases, and also CSS url() functions should also be processed by Vite.
Vue has this feature, I was surprised to see that SvelteKit doesn't even though it uses Vite too.
Alternatives considered
Obviously you could do @import '../lib/scss' or whatever but you don't get any of the advantages that aliases bring you.
Importance
would make my life easier
Additional Information
No response
This is likely because svelte-preprocess tries to locate the import, but it doesn't know about alias. The SCSS never reaches Vite. There are two options:
- Use
useVitePreprocessin the svelte config. This sends the SCSS to Vite instead. Make sure to disable SCSS transformation in sveltePreprocess:
const config = {
preprocess: sveltePreprocess({ typescript: false, scss: false }),
experimental: {
useVitePreprocess: true
}
}
Note this uses Vite to process the script tag with esbuild too. We could probably split this option in vite-plugin-svelte side if needed.
- Adjust scss importer option.
const config = {
preprocess: sveltePreprocess({
scss: {
importer(url, prev, done) {
// handle $lib
}
}
}
}
I dont think theres much sveltekit can do at the moment.
I dont think theres much sveltekit can do at the moment.
This provides a bad developer experience in my opinion. Then how is it that Vite with Vue (or Nuxt) handles this by default?!
They do option 1 by default.
@bluwy Ok, but if I implement option 1, could I still use svelte-preprocess-special features like <style global>?
No, but for <style global> specifically, it's recommended to do import "./style.scss" in JS instead as that's faster performance-wise.
So this is a bummer unfortunately, I'd very much rather have the styles in the .svelte file as opposed to a separate .scss file, isn't there a way to combine the functionality of sveltePreprocess and useVitePreprocess either?
But in the case of Vue, even though it uses useVitePreprocess by default, as you said, it also supports things like <style scoped>. (styles are global by default in Vue, unlike Svelte, but that's beside the point)
@bluwy Sorry, when I do import "./style.scss" instead of <style global>, it seems like SvelteKit's SSR stops working properly, the styles aren't included in the initial markup and are then added via JavaScript, it seems.
Any ideas?
Update: Apparently SSR only fails to work when it's an .scss file, when it's .css it seems to work as expected. Weird!
Should I create a separate issue for this? Is this a known bug or something?
That will only happen during dev. It behaves correctly after a production build. Consider ignoring it.
Yes, this is known and it's a Vite thing rather than a SvelteKit one, but I do not know if there is an existing issue for it.
I'm having the same issue and I have tried dozens of workarounds of which none of them worked, I have almost given up on this 😒
Here's a workaround for having a global SCSS file (which is why I care about the aliases to begin with) that worked for me based off of the comment by @bluwy above, and another Stack Overflow answer that I can't seem to find again.
With a little more finagling/coding, you could use this to get actual working aliases functional — but this was an easy mod for me just to have a global scss variables repo. Naturally, modify paths/files as necessary to suit your own needs.
Step 1:
Create ./src/styles/global.scss to hold any global styles that you want to use — things that actually output css like resets, body styles, font imports, etc. (be sure to wrap the whole file contents in :global {}. Then import this directly from the app's root file using relative imports, e.g. @import '../../style/global.scss';
Step 2:
Create ./src/styles/vars.scss to hold ONLY scss variables that you want to use globally (I actually only have @imports in this file and split variables up into different files imported from the same directory).
Step 3
Add the following options to the preprocessor in the svelte.config.js file:
preprocess: sveltePreprocess({
scss: {
prependData: `@import '$VARS';`,
importer(url, prev, done) {
if (url === '$VARS') {
return done({ file: './src/style/vars' });
}
return done({ file: prev });
},
},
}),
What's this doing? First, prependData adds the import directive to every style in your app — we are intentionally setting this here to something unique and easily identified. Second the importer looks for our unique string as the url, if it finds it, it replaces it with the path to our vars.scss file; if it doesn't match, it just returns the path that it normally would have generated.
This works because — thankfully, at least in my environment — the file reference injected by the preprocessor becomes relative to the config file (or more likely, the app root) instead of relative to the path of whatever nested component file is getting processed.
svelte-preprocess v5 broke the async importer using done for me, switched to
preprocess: sveltePreprocess({
scss: {
prependData: `@import '$VARS';`,
importer(url, prev) {
if (url === '$VARS') {
return { file: './src/style/vars' };
}
return { file: prev };
},
},
}),
I think this is supported now with the new vitePreprocess API.