diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-03-16 17:49:47 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2020-03-16 23:21:44 +0100 |
commit | 1a8af7d4f087256710ae0bdf504ed53c0c24a211 (patch) | |
tree | 26201be3abd1d64c7cba69cf02c0c24f265c2688 | |
parent | 03b93bb9884ea479c855c2699e8c7b039dce6224 (diff) |
Add workaround for regular CSS imports in SCSS
Fixes #7059
-rw-r--r-- | hugolib/resource_chain_test.go | 63 | ||||
-rw-r--r-- | resources/resource_transformers/tocss/scss/client.go | 16 | ||||
-rw-r--r-- | resources/resource_transformers/tocss/scss/client_test.go | 49 | ||||
-rw-r--r-- | resources/resource_transformers/tocss/scss/tocss.go | 17 |
4 files changed, 143 insertions, 2 deletions
diff --git a/hugolib/resource_chain_test.go b/hugolib/resource_chain_test.go index 3b5150deb..39279b5bc 100644 --- a/hugolib/resource_chain_test.go +++ b/hugolib/resource_chain_test.go @@ -87,6 +87,69 @@ T1: {{ $r.Content }} } +func TestSCSSWithRegularCSSImport(t *testing.T) { + if !scss.Supports() { + t.Skip("Skip SCSS") + } + c := qt.New(t) + workDir, clean, err := htesting.CreateTempDir(hugofs.Os, "hugo-scss-include") + c.Assert(err, qt.IsNil) + defer clean() + + v := viper.New() + v.Set("workingDir", workDir) + b := newTestSitesBuilder(t).WithLogger(loggers.NewErrorLogger()) + // Need to use OS fs for this. + b.Fs = hugofs.NewDefault(v) + b.WithWorkingDir(workDir) + b.WithViper(v) + + scssDir := filepath.Join(workDir, "assets", "scss") + c.Assert(os.MkdirAll(filepath.Join(workDir, "content", "sect"), 0777), qt.IsNil) + c.Assert(os.MkdirAll(filepath.Join(workDir, "data"), 0777), qt.IsNil) + c.Assert(os.MkdirAll(filepath.Join(workDir, "i18n"), 0777), qt.IsNil) + c.Assert(os.MkdirAll(filepath.Join(workDir, "layouts", "shortcodes"), 0777), qt.IsNil) + c.Assert(os.MkdirAll(filepath.Join(workDir, "layouts", "_default"), 0777), qt.IsNil) + c.Assert(os.MkdirAll(filepath.Join(scssDir), 0777), qt.IsNil) + + b.WithSourceFile(filepath.Join(scssDir, "_moo.scss"), ` +$moolor: #fff; + +moo { + color: $moolor; +} +`) + + b.WithSourceFile(filepath.Join(scssDir, "main.scss"), ` +@import "moo"; +@import "regular.css"; +@import "moo"; +@import "another.css"; + +/* foo */ +`) + + b.WithTemplatesAdded("index.html", ` +{{ $r := resources.Get "scss/main.scss" | toCSS }} +T1: {{ $r.Content | safeHTML }} +`) + b.Build(BuildCfg{}) + + b.AssertFileContent(filepath.Join(workDir, "public/index.html"), ` + T1: moo { + color: #fff; } + +@import "regular.css"; +moo { + color: #fff; } + +@import "another.css"; +/* foo */ + +`) + +} + func TestSCSSWithThemeOverrides(t *testing.T) { if !scss.Supports() { t.Skip("Skip SCSS") diff --git a/resources/resource_transformers/tocss/scss/client.go b/resources/resource_transformers/tocss/scss/client.go index 9309e3fe5..85f6e5255 100644 --- a/resources/resource_transformers/tocss/scss/client.go +++ b/resources/resource_transformers/tocss/scss/client.go @@ -14,6 +14,8 @@ package scss import ( + "regexp" + "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/hugolib/filesystems" "github.com/gohugoio/hugo/resources" @@ -72,3 +74,17 @@ func DecodeOptions(m map[string]interface{}) (opts Options, err error) { return } + +var ( + regularCSSImportTo = regexp.MustCompile(`.*(@import "(.*.css)";).*`) + regularCSSImportFrom = regexp.MustCompile(`.*(\/\* HUGO_IMPORT_START (.*) HUGO_IMPORT_END \*\/).*`) +) + +func replaceRegularImportsIn(s string) (string, bool) { + replaced := regularCSSImportTo.ReplaceAllString(s, "/* HUGO_IMPORT_START $2 HUGO_IMPORT_END */") + return replaced, s != replaced +} + +func replaceRegularImportsOut(s string) string { + return regularCSSImportFrom.ReplaceAllString(s, "@import \"$2\";") +} diff --git a/resources/resource_transformers/tocss/scss/client_test.go b/resources/resource_transformers/tocss/scss/client_test.go new file mode 100644 index 000000000..8cc79136a --- /dev/null +++ b/resources/resource_transformers/tocss/scss/client_test.go @@ -0,0 +1,49 @@ +// Copyright 2020 The Hugo Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package scss + +import ( + "testing" + + qt "github.com/frankban/quicktest" +) + +func TestReplaceRegularCSSImports(t *testing.T) { + c := qt.New(t) + + scssWithImport := ` + +@import "moo"; +@import "regular.css"; +@import "moo"; +@import "another.css"; + +/* foo */` + + scssWithoutImport := ` +@import "moo"; +/* foo */` + + res, replaced := replaceRegularImportsIn(scssWithImport) + c.Assert(replaced, qt.Equals, true) + c.Assert(res, qt.Equals, "\n\t\n@import \"moo\";\n/* HUGO_IMPORT_START regular.css HUGO_IMPORT_END */\n@import \"moo\";\n/* HUGO_IMPORT_START another.css HUGO_IMPORT_END */\n\n/* foo */") + + res2, replaced2 := replaceRegularImportsIn(scssWithoutImport) + c.Assert(replaced2, qt.Equals, false) + c.Assert(res2, qt.Equals, scssWithoutImport) + + reverted := replaceRegularImportsOut(res) + c.Assert(reverted, qt.Equals, scssWithImport) + +} diff --git a/resources/resource_transformers/tocss/scss/tocss.go b/resources/resource_transformers/tocss/scss/tocss.go index a776b9f3b..20f0efbb9 100644 --- a/resources/resource_transformers/tocss/scss/tocss.go +++ b/resources/resource_transformers/tocss/scss/tocss.go @@ -65,7 +65,6 @@ func (t *toCSSTransformation) Transform(ctx *resources.ResourceTransformationCtx // 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) { - // We get URL paths from LibSASS, but we need file paths. url = filepath.FromSlash(url) prev = filepath.FromSlash(prev) @@ -170,12 +169,26 @@ func (c *Client) toCSS(options libsass.Options, dst io.Writer, src io.Reader) (l } in := helpers.ReaderToString(src) + + // See https://github.com/gohugoio/hugo/issues/7059 + // We need to preserver the regular CSS imports. This is by far + // a perfect solution, and only works for the main entry file, but + // that should cover many use cases, e.g. using SCSS as a preprocessor + // for Tailwind. + var importsReplaced bool + in, importsReplaced = replaceRegularImportsIn(in) + res, err = transpiler.Execute(in) if err != nil { return res, errors.Wrap(err, "SCSS processing failed") } - _, err = io.WriteString(dst, res.CSS) + out := res.CSS + if importsReplaced { + out = replaceRegularImportsOut(out) + } + + _, err = io.WriteString(dst, out) return res, err } |