Export SASS/SCSS variables to Javascript without exporting them to CSS
Asked Answered
N

3

33

Background

Consider the following _variables.scss file:

/* Define all colours */
$white:    #fff;
$black:    #000;
$grey:     #ccc;
// etc...

// Export the color palette to make it accessible to JS
:export {
    white: $white;
    black: $black;
    grey: $grey;
    // etc...
}

The purpose of the above code is to make the SCSS variables available to Javascript by means of importing like so:

import variables from 'variables.scss';

See a more detailed description here.

The Problem

Now consider the following template (I have used as Vue.js template as an example but this is relevant to numerous frameworks):

<!-- Template here... -->

<style lang="scss" scoped>

    // Import Partials
    @import "~core-styles/brand/_variables.scss";
    @import "~core-styles/brand/_mixins.scss";

    // Styles here...

</style>

In the above example I have used the scoped attribute as this demonstrates the worst case scenario for the upcoming problem, but even without scoped the problem is still relevant.

The above SCSS will compile to something along the lines of:

[data-v-9a6487c0]:export {
    white: #fff;
    black: #000;
    grey: #ccc;
    // etc...
}

In addition, with the scoped attribute, this will repeat every time _variables.scss is imported into a template, and can potentially result in additional redundant code. In some cases, for large applications (many components and a large colour palette), this can literally add 000's of lines of completely redundant code.

My Question

Is there a way to export the SCSS variables to Javascript without exporting them to CSS?

Potential (dirty) Solution

I am ideally trying to avoid a solution of having a separate file named, for example, _export.scss where its purpose is simply to export all SCSS variables to JS, but it is excluded from all CSS builds...

Just to expand on the above dirty solution, this is what I am currently resorting to (in my case, on a standard size website, it has so far saved me ~600 lines of redundant CSS code):

_export.scss

/*
 |--------------------------------------------------------------------------
 | SASS Export
 |--------------------------------------------------------------------------
 |
 | Define any variables that should be exported to Javascript. This file
 | is excluded from the CSS builds in order to prevent the variables from
 | being exported to CSS.
 |
 */

@import "variables";

:export {

    // Export the color palette to make it accessible to JS
    white: #fff;
    black: #000;
    grey: #ccc;
    // etc...

}

Then, in my Javascript instead of importing from _variables.scss, I import from _export.scss like so:

import styles from 'core-styles/brand/_export.scss';

And finally, the export statement, can now be removed from the _variables.scss file, thus preventing the compiled CSS export code.

Note: The _export.scss file must be excluded from the SCSS compilation!

Newspaperwoman answered 17/8, 2019 at 12:21 Comment(1)
Can anyone point to a way of actually excluding the file containing the exports from compilation? Specifically, when using Vite/Rollup for building. I have tried the build.optimizeDeps and build.rollupOptions.external options as well as the postcss-exclude-files plugin with the css.postcss.plugins option and the filter option of the plugin set to '**/*.module.*'. Nothing seems to have any effect.Portiaportico
N
33

Note: I have posted this answer because it seems there is no better solution, however, if someone subsequently provides a better solution, I will be more than happy to accept it.

It seems that the only real solution to this is to extract the export statement out of the _variables.scss file and place it into its own _export.scss file which will subsequently not be included in the SCSS compliation.

This will look something like this:

_variables.scss - included in the SCSS compilation

/* Define all colours */
$white:    #fff;
$black:    #000;
$grey:     #ccc;
// etc...

_export.scss - not included in the SCSS compilation

@import "variables";

:export {

    // Export the color palette to make it accessible to JS
    white: #fff;
    black: #000;
    grey: #ccc;
    // etc...

}

And then your app.scss (I use brand.scss) file will look something like this (note the absence of @include "export";):

@import "variables";
@import "mixins";
@import "core";
@import "animations";
// etc...

Then, _export.scss is simply referenced only in JavaScript like so (note that core-styles is just an alias that I used in my projects):

import styles from 'core-styles/brand/_export.scss';
Newspaperwoman answered 17/8, 2019 at 16:31 Comment(10)
I'm having some difficulties achieving what you have outlined here, would you mind taking a look at my question here: #61517617Electrician
If I do this with rollup the styles is an empty string, e.g. "". Any experience with getting this to work with Rollup?Decongestant
This wasn't working for me as is, I kept getting an empty object back for the styles variable. After updating _export.scss to be _export.module.scss, I was then able to get back the variablesHoskins
@Stetzon, your comment was the only solution that worked for me as well. I wonder what your webpack.js looks likeAmble
@Stetzon's solution works for Parcel as wellSnashall
When I use :export in one of my SCSS files, I get an webpack error: "Error: Module parse failed: Unexpected token" using [email protected][email protected][email protected] in an Angular / TS app. Any idea what is missing?Completion
@PeterT. Have you solved your problem? I have the same thing!Consumerism
@Murat No, I used a different approach and a workaround without :export then.Completion
How is your workaround I also had to there a workaround like keeping the content in a variable.Consumerism
@Stetzon’s comment about needing to use the “.module.scss” extension for exports to work applies to Vite/Rollup builds, too. I found the article medium.com/@UReyesMeUp/… that clearly states this as a general requirement for use of style exports in React components – but presumably for other frameworks, too.Portiaportico
K
1

I wonder if this is caused by using @import instead of using @use.

@import is deprecated precisely because it copy-pastes, so multiple imports result in multiple copies of the same contents.

Kalsomine answered 21/5, 2022 at 7:47 Comment(0)
R
0

Copy your SCSS vars as CSS vars (--white, --black etc) and then:

window.getComputedStyle(document.body).getPropertyValue('--white')

Downside is polluting the document with probably not needed CSS vars. Upside - you don't need any (convoluted) export/import.

Recite answered 3/1 at 12:9 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Rhododendron

© 2022 - 2024 — McMap. All rights reserved.