kit icon indicating copy to clipboard operation
kit copied to clipboard

Using Vite alises in <style>

Open aradalvand opened this issue 3 years ago • 12 comments

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

aradalvand avatar Dec 08 '21 14:12 aradalvand

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:

  1. Use useVitePreprocess in 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.

  1. 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.

bluwy avatar Dec 08 '21 17:12 bluwy

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?!

aradalvand avatar Dec 08 '21 17:12 aradalvand

They do option 1 by default.

bluwy avatar Dec 08 '21 17:12 bluwy

@bluwy Ok, but if I implement option 1, could I still use svelte-preprocess-special features like <style global>?

aradalvand avatar Dec 08 '21 18:12 aradalvand

No, but for <style global> specifically, it's recommended to do import "./style.scss" in JS instead as that's faster performance-wise.

bluwy avatar Dec 08 '21 18:12 bluwy

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?

aradalvand avatar Dec 08 '21 18:12 aradalvand

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)

aradalvand avatar Dec 08 '21 18:12 aradalvand

@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?

aradalvand avatar Dec 09 '21 01:12 aradalvand

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.

babichjacob avatar Dec 09 '21 02:12 babichjacob

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 😒

mrfzd avatar Apr 19 '22 22:04 mrfzd

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.

valZho avatar Sep 07 '22 18:09 valZho

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 };
      },
    },
  }),

CanRau avatar Dec 15 '22 01:12 CanRau

I think this is supported now with the new vitePreprocess API.

bluwy avatar Dec 17 '22 08:12 bluwy