Search code examples
vue.jssassvite

Using @use 'sass:color' is making variables imported via additionalData unavailable in my Vue.js / Vite app


I am using Vue.js with Vitest with the sass loader.

When I use @use 'sass:color' in an inline scss file or in a component, it seems to override variables which are set in css.preprocessorOptions.scss.additionalData in my vite.config.ts file.

The issue is reproduced here: https://stackblitz.com/edit/vitejs-vite-nk8yf5?file=src%2Fstyle%2Fsample.scss

For future reference, the setup is as follows:

./src/style/vars.scss

$sample-var: red;

vite.config.js

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@use "./src/style/vars.scss" as *;`,
      },
    },
  },
});

./src/style/sample.scss

@use 'sass:color';

.sample-style {
  color: $sample-var;
}

Component:

<script setup>

</script>

<template>
  <div class="sample-style">Hello sample style</div>
</template>

<style lang="scss" scoped>
@import '../style/sample.scss';
</style>

With this code, I get Undefined variable. for the $sample-var in sample.scss.

However, if I comment out @use 'sass:color'; it works as expected (I can access $sample-var within my component files.

What is going on here? How can I properly import sass:color in my component styles, while making a set of variables globally accessible using additionalData in vite.config.js? I'm interested in learning what the best practice is.


Solution

  • The Scss code defined in additionalData gets prepended to the <style> tag of the component. So what the Sass compiler ends up processing is:

    @use "./src/style/vars.scss" as *;
    @import '../style/sample.scss';
    

    When sample.scss does not include any @use statements, as per the documentation:

    When Sass imports a file, that file is evaluated as though its contents appeared directly in place of the @import. Any mixins, functions, and variables from the imported file are made available, and all its CSS is included at the exact point where the @import was written.

    That means that the above is evaluated similarly to:

    @use "./src/style/vars.scss" as *;
    .sample-style {
      color: $sample-var;
    }
    

    However, as per the documentation on importing a module-system file (emphasis mine):

    When you import a file that contains @use rules, the importing file has access to all members (even private members) defined directly in that file, but not any members from modules that file has loaded.

    $sample-var is a member from a module, and thus sample.scss does not have access to $sample-var.