javascriptreactjssasscreate-react-appnode-sass

How to correctly access nested aliases with sass/node-sass in create-react-app


I am trying to break my scss partials into multiple files and aggregate it into one file and access variables accordingly. I have this folder structure:

create-react-app/src  
│
└───Styles
│   │
│   └───Tokens
│   |   │ _Colors.scss
│   |   │ _Tokens.scss
│   | _Base.scss

Inside _Colors.scss, I have a simple variable: $primary-color: red;.

// _Colors.scss

$primary-color: red;

Inside _Tokens.scss I use the @use rule to import my partial and give it an alias: @use "./Colors.scss" as colors;.

// _Tokens.scss

@use "./Colors" as colors;

In my _Base.scss I am importing my Tokens.scss and giving that an alias as well: @use "Styles/Tokens/Tokens" as tokens;. I then try to access the nested alias/namespace, eg:

// _Base.scss

@use "Styles/Tokens/Tokens" as tokens;

body {
  color: tokens.colors.$primary-color; // Linter has an issue with .colors
}

I am confronted with a linter error: identifier or variable expectedscss(css-idorvarexpected). React also spits out an error:

Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: expected "(".
   ╷
10 │   color: tokens.colors.$primary-color;
   │                       ^

Confused on what to do at this point, I've tried for a few hours poking around Google but can't find anything. Help would be appreciated, thank you! Let me know if you need any more information!


Solution

  • I solved this with the @forward syntax.

    From the docs: "The @forward rule loads a Sass stylesheet and makes its mixins, functions, and variables available when your stylesheet is loaded with the @use rule. It makes it possible to organize Sass libraries across many files, while allowing their users to load a single entrypoint file."

    This allows you to import a single file, eg. _tokens.scss, rather than importing multiple files.

    For example, we have a directory called tokens/. Inside tokens/, we have multiple different partial files to hold many different variables, based off their category (eg. colors, fonts). Lastly, we have a single _tokens.scss partial file which we will use to "forward" all of our separate partial files so that we only need to import one partial, instead of every single partial file.

    Take a look at this example:

    tokens/
      _colors.scss
      _fonts.scss
      _tokens.scss
    

    Inside _colors.scss:

    $brand: rebeccapurple;
    

    Now, we can forward this in our _tokens.scss and namespace it as needed:

    // _tokens.scss
    
    // we namespace our variables inside _colors.scss as colors-* meaning we need to prefix our variable names inside _colors.scss as $colors-VARIABLE, in this case $colors-brand
    
    @forward "./colors" as colors-*;
    

    Now, we only need to call _tokens.scss in any sass file that may need our tokens. Let's say we have a _sections.scss partial file that holds our section components:

    // _sections.scss
    @use "path/to/tokens" as tokens; // namespaced as tokens
    
    // we can call our $brand variable inside _colors.scss as follows:
    
    .section-about {
      // notice the "$colors-" prefix. This is how I namespaced it in _tokens.scss.
      color: tokens.$colors-brand; 
    }
    

    See: https://sass-lang.com/documentation/at-rules/forward