tocss: Add vars option

This commit adds a new `vars` option to both the Sass transpilers (Dart Sass and Libsass).

This means that you can pass a map with key/value pairs to the transpiler:

```handlebars
{{ $vars := dict "$color1" "blue" "$color2" "green" "$font_size" "24px" }}
{{ $cssOpts := (dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" $vars ) }}
{{ $r := resources.Get "scss/main.scss" |  toCSS $cssOpts }}
```

And the the variables will be available in the `hugo:vars` namespace. Example usage for Dart Sass:

```scss
@use "hugo:vars" as v;

p {
    color: v.$color1;
    font-size: v.$font_size;
}
```

Note that Libsass does not support the `use` keyword, so you need to `import` them as global variables:

```scss
@import "hugo:vars";

p {
    color: $color1;
    font-size: $font_size;
}
```

Hugo will:

* Add a missing leading `$` for the variable names if needed.
* Wrap the values in `unquote('VALUE')` (Sass built-in) to get proper handling of identifiers vs other strings.

This means that you can pull variables directly from e.g. the site config:

```toml
[params]
[params.sassvars]
color1 = "blue"
color2 = "green"
font_size = "24px"
image = "images/hero.jpg"
```

```handlebars
{{ $vars := site.Params.sassvars}}
{{ $cssOpts := (dict "transpiler" "dartsass" "outputStyle" "compressed" "vars" $vars ) }}
{{ $r := resources.Get "scss/main.scss" |  toCSS $cssOpts }}
```

Fixes #10555
This commit is contained in:
Bjørn Erik Pedersen
2022-12-19 18:49:02 +01:00
parent 9a215d6950
commit 41a080b268
7 changed files with 218 additions and 1 deletions

View File

@@ -60,6 +60,10 @@ type Options struct {
// When enabled, Hugo will generate a source map.
EnableSourceMap bool
// Vars will be available in 'hugo:vars', e.g:
// @import "hugo:vars";
Vars map[string]string
}
func DecodeOptions(m map[string]any) (opts Options, err error) {

View File

@@ -25,6 +25,7 @@ import (
)
func TestTransformIncludePaths(t *testing.T) {
t.Parallel()
if !scss.Supports() {
t.Skip()
}
@@ -57,6 +58,7 @@ T1: {{ $r.Content }}
}
func TestTransformImportRegularCSS(t *testing.T) {
t.Parallel()
if !scss.Supports() {
t.Skip()
}
@@ -113,6 +115,7 @@ moo {
}
func TestTransformThemeOverrides(t *testing.T) {
t.Parallel()
if !scss.Supports() {
t.Skip()
}
@@ -175,6 +178,7 @@ zoo {
}
func TestTransformErrors(t *testing.T) {
t.Parallel()
if !scss.Supports() {
t.Skip()
}
@@ -245,3 +249,45 @@ T1: {{ $r.Content }}
})
}
func TestOptionVars(t *testing.T) {
t.Parallel()
if !scss.Supports() {
t.Skip()
}
files := `
-- assets/scss/main.scss --
@import "hugo:vars";
body {
body {
background: url($image) no-repeat center/cover;
}
}
p {
color: $color1;
font-size: var$font_size;
}
b {
color: $color2;
}
-- layouts/index.html --
{{ $image := "images/hero.jpg" }}
{{ $vars := dict "$color1" "blue" "$color2" "green" "font_size" "24px" "image" $image }}
{{ $cssOpts := (dict "transpiler" "libsass" "outputStyle" "compressed" "vars" $vars ) }}
{{ $r := resources.Get "scss/main.scss" | toCSS $cssOpts }}
T1: {{ $r.Content }}
`
b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
NeedsOsFS: true,
}).Build()
b.AssertFileContent("public/index.html", `T1: body body{background:url(images/hero.jpg) no-repeat center/cover}p{color:blue;font-size:var 24px}b{color:green}`)
}

View File

@@ -31,6 +31,7 @@ import (
"github.com/gohugoio/hugo/hugofs"
"github.com/gohugoio/hugo/media"
"github.com/gohugoio/hugo/resources"
"github.com/gohugoio/hugo/resources/resource_transformers/tocss/internal/sass"
)
// Used in tests. This feature requires Hugo to be built with the extended tag.
@@ -63,11 +64,17 @@ func (t *toCSSTransformation) Transform(ctx *resources.ResourceTransformationCtx
}
}
varsStylesheet := sass.CreateVarsStyleSheet(options.from.Vars)
// To allow for overrides of SCSS files anywhere in the project/theme hierarchy, we need
// to help libsass revolve the filename by looking in the composite filesystem first.
// We add the entry directories for both project and themes to the include paths list, but
// that only work for overrides on the top level.
options.to.ImportResolver = func(url string, prev string) (newUrl string, body string, resolved bool) {
if url == sass.HugoVarsNamespace {
return url, varsStylesheet, true
}
// We get URL paths from LibSASS, but we need file paths.
url = filepath.FromSlash(url)
prev = filepath.FromSlash(prev)