Combine SASS/SCSS and CSS in a bundle

Hi

The theme I’m using uses a Partial to make use of Site.Params to set the colours in CSS variables.
Although this does work fine, I’m not really fan of this cluttering of my site’s <head>.

That’s why I was thinking of using SASS/SCSS variables, based on Initialize Sass variables from Hugo templates and hugo-testing/layouts/partials/get-scss-vars.html at hugo-github-issue-10558 · jmooring/hugo-testing · GitHub.

The transpiled CSS should then be included in the bundle together with the rest of the CSS files.

However, I just can’t wrap my head around it.

My setup looks as follows:


assets/scss/
├── _vars.scss
└── main.scss

layouts/partials/head
└── get-scss-vars.html
└── stylesheets.html

/* assets/scss/main.scss */

@import "vars";

/* assets/scss/_vars.scss */

@use "hugo:vars" as h;

body {
    --sidebar-bg-color: h.$sidebar_bg_color;
    --sidebar-img-border-color: h.$sidebar_img_border_color;
    --sidebar-p-color: h.$sidebar_p_color;
    --sidebar-h1-color: h.$sidebar_h1_color;
    --sidebar-a-color: h.$sidebar_a_color;
    /* ... */
    --moon-sun-color: h.$moon_sun_color;
    --moon-sun-background-color: h.$moon_sun_background_color;
};

# layouts/partials/head/get-scss-vars.html

{{ $vars := dict
    "sidebar_bg_color"                  (or .Site.Params.sidebar_bg_color "#202020")
    "sidebar_img_border_color"          (or .Site.Params.sidebar_img_border_color "#515151")
    "sidebar_p_color"                   (or .Site.Params.sidebar_p_color "#909090")
    "sidebar_h1_color"                  (or .Site.Params.sidebar_h1_color "#FFF")
    "sidebar_a_color"                   (or .Site.Params.sidebar_a_color "#FFF")
    # ...
    "moon_sun_color"                    (or .Site.Params.moon_sun_color "#FFF")
    "moon_sun_background_color"         (or .Site.Params.moon_sun_background_color "#515151")
}}

{{ return $vars }}

# layouts/partials/head/stylesheets.html

{{ $bundle := slice }}

{{ $opts := dict
  "targetPath"  "css/vars.css"
  "transpiler"  "dartsass"
  "vars"        (partialCached "head/get-scss-vars.html" .)
}}
{{ with resources.Get "scss/main.scss" | toCSS $opts }}
  {{ $bundle = $bundle | append (slice "{{ .RelPermalink }}") }}
{{ end }}

{{ $bundle = $bundle | append (slice
    (resources.Get "css/poole.css")
    (resources.Get "css/codeblock.css")
    (resources.Get "css/hyde.css")
    (resources.Get "css/poison.css")
    (resources.Get "css/fonts.css")
    (resources.Get "css/lib/katex.css")
    (resources.Get "css/tabs.css")
    (resources.Get "css/custom.css")
  )
}}

{{ $css_bundle := $bundle | resources.Concat "css/bundle.css" | minify | fingerprint }}

<link type="text/css" rel="stylesheet" href="{{ $css_bundle.RelPermalink }}" integrity="{{ $css_bundle.Data.Integrity }}" crossorigin="anonymous">

What is your question?

I would like to figure out how I can combine the transpiled SCSS>CSS in the same bundle as the rest of the CSS.

My current setup results in the error:
execute of template failed: template: partials/head/stylesheets.html:24:37: executing "partials/head/stylesheets.html" at <resources.Concat>: error calling Concat: expected slice of Resource objects, received []interface {} instead

Other attempts resulted in the following error:
error calling toCSS: runtime error: invalid memory address or nil pointer

You are appending a string, not the resource itself. Here’s a simple example of transpiling a Sass file and then appending the CSS files.

assets/
├── css/
│   ├── 01-typography.css
│   └── 02-components.css
└── sass/
    └── main.scss
{{ with resources.Get "sass/main.scss" }}
  {{ $opts := dict
    "transpiler" "dartsass"
  }}
  {{ with . | toCSS $opts }}
    {{ with slice . | append (resources.Match "css/*") | resources.Concat "css/styles.css" }}
      {{ if hugo.IsProduction }}
        {{ with . | minify | fingerprint }}
          <link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
        {{ end }}
      {{ else }}
        <link rel="stylesheet" href="{{ .RelPermalink }}">
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

Notes:

  • If you can prefix the CSS file names as shown in the file structure above, they’ll be appended in numerical order. That makes it really easy to append all of the CSS files, in the desired order, with the resources.Match function
  • There’s no need set the target path in the transpiler options map. The target path is defined in the call to resources.Concat.
2 Likes

I’ll give this a shot tomorrow.

Thanks a lot!
Blazingly fast response :slight_smile:

Took a while before I had the spare time to give this another go.
Looks like the CSS isn’t being built.
My staging version currently has no CSS at all anymore.

No errors, so debugging is a bit hard.

It’s going to be a bit hard for me, or anyone else for that matter, without access to your project.

See Requesting Help.

Let us see your code

Include a link to the source code repository of your project, because we really need the context of seeing your templates and partials to be able to help you. It is trivial to do a quick git clone on your repo, then run hugo server in your project, to help you out. On the other hand, recreating your code from screenshots, or sort of guessing at it, is not.

If you can’t share your repository for whatever reason, consider creating a dummy repo that you can share, which reproduces the problem you’re experiencing.

My fork of the theme can be found at: GitHub - TheGroundZero/poison: Personalized copy of lukeorth/poison

Sharing my own site’s project is a bit harder.
My main project is a private repo and I have a main and staging branch that then have a build workflow using peaceiris/actions-gh-pages to push the generated site to different repos (1 for prod and 1 for staging), each with their own CNAME.

{{ with resources.Get "sass/main.scss" }}

You have an scss directory not a sass directory.

"vars" (partialCached "head/get-scss-vars.html" .)

You’re passsing the wrong context. The dot represents the resource; you need to pass the page (use $ instead of the dot).

1 Like

Dang it, completely missed the change in paths. Wouldn’t have figured out the .vs $ thing tho’.

However, still doesn’t seem to work :frowning:

After making those two small changes I see this when running hugo server:

That does look more like the wanted result.

My staging site can be found at: https://dev.sequr.be/ and – as you can see – it’s currently pretty broken.

It should look more like https://poison.lukeorth.com/

It’s going to be a bit hard for me, or anyone else for that matter, without access to your project.

I can’t put any more time into this.

I understand.

Thanks for you help so far! :hugs:

I’m currently trying to figure out why running hugo server (via the hugomods/hugo:exts podman container) gives me a less broken site than the Github build currently does…

Will update this post when I figure out what’s going wrong.

Seems like caching might have to do something with this…
I assume GitHub’s hashFiles may work differently with submodules. But I’m too much of a Git(Hub) novice to be sure.

Removed the GitHub Action cache and triggered the build workflow again. Now the site does seem to be OK lay-out wise. The dark/light mode switching does appear to be broken now.

Looks like the variables weren’t correctly replaced.
This is (part of) the content of the bundled CSS

Tried a few combinations so far. Doesn’t seem to work.


I changed the variable references to site. like in hugo-testing/layouts/partials/get-scss-vars.html at hugo-github-issue-10558 · jmooring/hugo-testing · GitHub

{{ $vars := dict
  "sidebar_bg_color" (or site.Params.sidebar_bg_color "#202020")
  // ...
}}

{{ return $vars }}

Restored the use of . as partial context, like in hugo-testing/layouts/partials/css.html at hugo-github-issue-10558 · jmooring/hugo-testing · GitHub

{{ with resources.Get "scss/main.scss" }}
  {{ $opts := dict
    "transpiler" "dartsass"
    "vars" (partialCached "head/get-scss-vars.html" .)
  }}
  // ...
}}

Tried with $ as Partial context.
Tried with a regular partial instead of partialCached.
Tried with $.Site.Params. and .Site in get-css-vars.html.


All seem to fail replacing the variables in the SCSS.


Extra context:

/config/_default/params.yaml

# Hex colors for your sidebar.
moon_sun_background_color: "#515151"   # default is #515151
moon_sun_color: "#FFF"                 # default is #FFF
sidebar_a_color: "#FFF"                # default is #FFF
sidebar_bg_color: "#202020"            # default is #202020
sidebar_h1_color: "#FFF"               # default is #FFF
sidebar_img_border_color: "#515151"    # default is #515151
sidebar_p_color: "#909090"             # default is #909090
sidebar_socials_color: "#FFF"          # default is #FFF

# Hex colors for your content in light mode.
code_color: "#000"                     # default is #000
code_background_color: "#E5E5E5"       # default is #E5E5E5
code_block_color: "#FFF"               # default is #FFF
code_block_background_color: "#272822" # default is #272822
content_bg_color: "#FAF9F6"            # default is #FAF9F6
date_color: "#515151"                  # default is #515151
link_color: "#268BD2"                  # default is #268BD2
list_color: "#5A5A5A"                  # default is #5A5A5A
post_title_color: "#303030"            # default is #303030
table_border_color: "#E5E5E5"          # default is #E5E5E5
table_stripe_color: "#F9F9F9"          # default is #F9F9F9
text_color: "#222"                     # default is #222

# Hex colors for your content in dark mode
code_color_dark: "#FFF"                        # default is #FFF
code_background_color_dark: "#515151"          # default is #515151
code_block_color_dark: "#FFF"                  # default is #FFF
code_block_background_color_dark: "#272822"    # default is #272822
content_bg_color_dark: "#121212"               # default is #121212
date_color_dark: "#9A9A9A"                     # default is #9A9A9A
link_color_dark: "#268BD2"                     # default is #268BD2
list_color_dark: "#9D9D9D"                     # default is #9D9D9D
post_title_color_dark: "#DBE2E9"               # default is #DBE2E9
table_border_color_dark: "#515151"             # default is #515151
table_stripe_color_dark: "#202020"             # default is #202020
text_color_dark: "#EEE"                        # default is #EEE

@jmooring

I think I may have figured it out.
I believe the DartCSS compiler doesn’t like working with CSS variables.

Made a small changes to /assets/scss/_vars.scss, using one of the Sass variable for the background colour directly in background-color instead of first setting var(--bkg-color).

body {
    --bkg-color: h.$content_bg_color;
    /* ... */

    background-color: h.$content_bg_color;
};
body.dark-theme {
    --bkg-color: h.$content_bg_color_dark;
    /* ... */

    background-color: h.$content_bg_color_dark;
};

/*
body {
    background-color: var(--bkg-color);
};
*/

Looking at /css/bundle.css in the built site, I see

body {
  --bkg-color: h.$content_bg_color;
  /* ... */
  background-color: #FAF9F6;
}

body.dark-theme {
  --bkg-color: h.$content_bg_color_dark;
  /* ... */
  background-color: #121212;
}

Sadly, this doesn’t bring me much closer to a fix, unless I replace all var() in the different stylesheets with references to the Sass variables (and migrate the CSS files to SCSS).

without digging into the details…

sounds a little like that one may be related.

if not, not :slight_smile:

1 Like

That was it!!!

/assets/scss/_vars.scss

@use "hugo:vars" as h;

body {
    --bkg-color: #{h.$content_bg_color};
    /* ... */
};
body.dark-theme {
    --bkg-color: #{h.$content_bg_color_dark};
    /* ... */
};

body {
    background-color: var(--bkg-color);
}

results in

/css/bundle.css

body {
  --bkg-color: #FAF9F6;
    /* ... */
}

body.dark-theme {
  --bkg-color: #121212;
    /* ... */
}

body {
  background-color: var(--bkg-color);
}

The final solution, with thanks to @jmooring and @irkode

assets/
├─ css/
│  ├─ various_files.css
├─ scss/
│  ├─ main.scss
│  ├─ _vars.scss
layouts/
├─ partials/
│  ├─ head/
│  │  ├─ get-css-vars.html
│  │  ├─ stylesheets.html

/layouts/partials/head/stylesheets.html

{{ $opts := dict
  "targetPath" "css/style.css"
  "transpiler" "dartsass"
  "vars" (partialCached "head/get-scss-vars.html" .)
}}

{{ with resources.Get "scss/main.scss" }}
  {{ with . | toCSS $opts }}
    {{ with slice . | append (resources.Match "css/*") | resources.Concat "css/bundle.css" }}
      {{ if hugo.IsProduction }}
        {{ with . | minify | fingerprint }}
          <link rel="stylesheet" href="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
        {{ end }}
      {{ else }}
        <link rel="stylesheet" href="{{ .RelPermalink }}">
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

/layouts/partials/head/get-scss-vars.html

{{ $vars := dict
    "content_bg_color"       (or site.Params.style.content_bg_color "#FAF9F6")
    "content_bg_color_dark"  (or site.Params.style.content_bg_color_dark "#121212")
}}

{{ return $vars }}

/assets/scss/main.scss

@use "vars";

/assets/scss/_vars.scss

@use "hugo:vars" as h;

body {
    --bkg-color: #{h.$content_bg_color};
};
body.dark-theme {
    --bkg-color: #{h.$content_bg_color_dark};
};

body {
    background-color: var(--bkg-color);
}

Note, looks like this doesn’t work with subfolders in /assets/css. I either need to find a fix for this, or would have to move the single CSS file.

1 Like