Configurable SASS/SCSS variables with `@use` rule

Hi everyone, I’m looking for a way to config the SASS/SCSS variables via configuration file with @use rule.

Motivation

I used to use ExecuteAsTemplate the variables’ template, and then append the generated resource that contains configured vars via resources.Concat, so that the others files can access the global SASS/SCSS variables.

Now the @import rule was marked deprecated two years ago, may be removed in the next few years. I would like to use the @use instead, but I don’t know if it’s possible. I’m unable to access the generated vars resource.

I think it could be done by overriding the assets (Hugo look up order), but this way is a little complicated compared with the configurable way for end users.

Error: Error building site: TOCSS-DART: failed to transform "hbs/scss/main.scss" (text/x-scss): "<stream>:1:1": Can't find stylesheet to import.

Code Snippet

I’ve also committed the codes to GitHub repo, see GitHub - razonyang/hugo-lab at scss-configurable-vars.

$ tree assets
└── hbs
    └── scss
        ├── main.scss
        └── vars.tmpl.scss

I got two assets that content as following.

$ cat assets/hbs/scss/vars.tmpl.scss
$heading-color: '{{ default "skyblue" .Site.Params.heading_color }}';

vars.tmpl.scss is the template for generating vars from config file.

$ cat assets/hbs/scss/main.scss
@use 'vars';

.heading {
    color: vars.$heading_color;
}
{{ $varsTmpl := resources.Get "hbs/scss/vars.tmpl.scss" }}
{{ $vars := $varsTmpl | resources.ExecuteAsTemplate "hbs/scss/_vars.scss" . }}
{{ $styles := slice $vars (resources.Get "hbs/scss/main.scss") }}
{{ $style := $styles | resources.Concat "css/hbs.css" | toCSS (dict
    "transpiler" "dartsass"
) }}
<link href="{{ $style.Permalink }}" rel="stylesheet">

The hard part is that I don’t know how to @use the generated vars stylesheet.
I’m wondering that will resources.ExecuteAsTemplate "hbs/scss/_vars.scss" . create the file assets/hbs/scss/_vars.scss, which @used by assets/hbs/scss/main.scss?

The short answer is that you need to use the Dart Sass transpiler. I suggest you search this forum for similar topics.

1 Like

Thanks for the quick response.

I’m using the dart-sass transpiler, but IDK how to @use the right path of the runtime vars SASS/SCSS file.

OK, then I misunderstood your problem.

I must admit that I don’t understand/remember the details good enough to give you a good answer to this.

1 Like

It’s been a while since I’ve looked at this, but I think you need to initialize in the top level file.

https://discourse.gohugo.io/t/using-a-data-file-for-scss-variables/32742/4

1 Like

Yes, @jmooring is right.

It would, however, be useful if you could do:

{{ $scss := resources.Get "sass/main.scss" }}
{{ $scss = $scss | resources.ExecuteAsTemplate "foo.scss" . }}
{{ $reloaded = resources.Get "foo.scss" . }}
{{ if ne $scss $reloaded }}
{{ error "these should be the same" }}
{{ end }}

If done right, then foo.scss should be importable as described in the first post above, which would also work with JS imports. I will think about it.

1 Like

Thank you.

I tried, but it’s weird that the resources.Get responses nil on reload.

{{ $vars := resources.Get "hbs/scss/vars.tmpl.scss" }}
{{ $vars = $vars | resources.ExecuteAsTemplate "vars.scss" . }}
{{ $reloaded := resources.Get "vars.scss" }}
{{ if ne $vars $reloaded }}
    {{ errorf "%s, %#v != %#v.\n" "these should be the same" $vars $reloaded }}
{{ end }}
...
ERROR 2022/12/01 13:14:15 these should be the same, &resources.resourceAdapter{commonResource:resources.commonResource{}, resourceTransformations:(*resources.resourceTransformations)(0xc00013f040), resourceAdapterInner:(*resources.resourceAdapterInner)(0xc00033b320)} != <nil>.
Error: Error building site: logged 1 error(s)
...
$ cat assets/hbs/scss/vars.tmpl.scss 
$heading-color: '{{ default "skyblue" .Site.Params.heading_color }}';

Thank you, the answer helps.

In order to avoid naming collisions between SASS/SCSS modules, I made a little improvement. I post the code snippet here, hope it helps others.

// assets/hbs/scss/index.tmpl.scss 
@use 'heading' with (
    $color: {{ default "blue" .Site.Params.heading_color }},
);
@use 'link' with (
    $color: {{ default "black" .Site.Params.link_color }},
);
// assets/hbs/scss/_heading.scss 
$color: null !default;

.heading {
    color: $color;
}
// assets/hbs/scss/_link.scss 
$color: null !default;

a {
    color: $color;
}
{{ $tmpl := resources.Get "hbs/scss/index.tmpl.scss" }}
{{ $style := $tmpl | resources.ExecuteAsTemplate "hbs/scss/index.scss" . }}
{{ $style := $style | toCSS (dict
    "transpiler" "dartsass"
) }}
<link href="{{ $style.Permalink }}" rel="stylesheet">

OK, so I was just thinking out loud above, the feature I described above doesn’t exist, but it would be useful.

Currently when you do

  • resources.FromString “foo.css”
  • resources.ExecuteAsTemplate “bar.css”

The resources returned are only available in the current template context; any import of e.g “foo.css” will fail. This is by design.

So, the only current way to do what you want is to make the main.scss into a template.

1 Like

I see, I’m sorry to bother you.

I agreed with you, that’s a very useful feature that allow generating isolated SASS/SCSS modules from Hugo template.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.