Skip to content

Commit

Permalink
Add Hugo Piper with SCSS support and much more
Browse files Browse the repository at this point in the history
Before this commit, you would have to use page bundles to do image processing etc. in Hugo.

This commit adds

* A new `/assets` top-level project or theme dir (configurable via `assetDir`)
* A new template func, `resources.Get` which can be used to "get a resource" that can be further processed.

This means that you can now do this in your templates (or shortcodes):

```bash
{{ $sunset := (resources.Get "images/sunset.jpg").Fill "300x200" }}
```

This also adds a new `extended` build tag that enables powerful SCSS/SASS support with source maps. To compile this from source, you will also need a C compiler installed:

```
HUGO_BUILD_TAGS=extended mage install
```

Note that you can use output of the SCSS processing later in a non-SCSSS-enabled Hugo.

The `SCSS` processor is a _Resource transformation step_ and it can be chained with the many others in a pipeline:

```bash
{{ $css := resources.Get "styles.scss" | resources.ToCSS | resources.PostCSS | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Digest }}" media="screen">
```

The transformation funcs above have aliases, so it can be shortened to:

```bash
{{ $css := resources.Get "styles.scss" | toCSS | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Digest }}" media="screen">
```

A quick tip would be to avoid the fingerprinting part, and possibly also the not-superfast `postCSS` when you're doing development, as it allows Hugo to be smarter about the rebuilding.

Documentation will follow, but have a look at the demo repo in https://github.com/bep/hugo-sass-test

New functions to create `Resource` objects:

* `resources.Get` (see above)
* `resources.FromString`: Create a Resource from a string.

New `Resource` transformation funcs:

* `resources.ToCSS`: Compile `SCSS` or `SASS` into `CSS`.
* `resources.PostCSS`: Process your CSS with PostCSS. Config file support (project or theme or passed as an option).
* `resources.Minify`: Currently supports `css`, `js`, `json`, `html`, `svg`, `xml`.
* `resources.Fingerprint`: Creates a fingerprinted version of the given Resource with Subresource Integrity..
* `resources.Concat`: Concatenates a list of Resource objects. Think of this as a poor man's bundler.
* `resources.ExecuteAsTemplate`: Parses and executes the given Resource and data context (e.g. .Site) as a Go template.

Fixes #4381
Fixes #4903
Fixes #4858
  • Loading branch information
bep committed Jul 6, 2018
1 parent a5d0a57 commit dea7167
Show file tree
Hide file tree
Showing 90 changed files with 4,686 additions and 1,126 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ vendor/*/
*.debug
coverage*.out

dock.sh

GoBuilds
dist
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
language: go
sudo: false
dist: trusty
env:
HUGO_BUILD_TAGS="extended"
git:
depth: false
go:
Expand All @@ -18,8 +20,9 @@ install:
- go get github.com/magefile/mage
- mage -v vendor
script:
- mage -v hugoRace
- mage -v test
- mage -v check
- mage -v hugo
- ./hugo -s docs/
- ./hugo --renderToMemory -s docs/
before_install:
Expand Down
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ To list all available commands along with descriptions:
mage -l
```

**Note:** From Hugo 0.43 we have added a build tag, `extended` that adds **SCSS support**. This needs a C compiler installed to build. You can enable this when building by:

This comment has been minimized.

Copy link
@caarlos0

caarlos0 Jul 6, 2018

Contributor

@bep did you test building it with goreleaser yet? Just wondering if the CGO can bring in any issues...


```bash
HUGO_BUILD_TAGS=extended mage install
````
### Updating the Hugo Sources
If you want to stay in sync with the Hugo repository, you can easily pull down
Expand Down
Empty file modified Dockerfile
100644 → 100755
Empty file.
66 changes: 65 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@
branch = "master"
name = "github.com/bep/gitmap"

[[constraint]]
branch = "master"
name = "github.com/bep/go-tocss"

[[override]]
branch = "master"
name = "github.com/wellington/go-libsass"

[[constraint]]
name = "github.com/chaseadamsio/goorgeous"
version = "^1.1.0"
Expand Down Expand Up @@ -149,3 +157,15 @@
[[constraint]]
name = "github.com/bep/debounce"
version = "^1.1.0"

[[constraint]]
name = "github.com/tdewolff/minify"
version = "^2.3.5"

[[constraint]]
branch = "master"
name = "github.com/BurntSushi/locker"

[[constraint]]
branch = "master"
name = "github.com/mitchellh/hashstructure"
8 changes: 7 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
image: Visual Studio 2015

init:
- set PATH=%PATH%;C:\MinGW\bin;%GOPATH%\bin
- set PATH=%PATH%;C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%GOPATH%\bin
- go version
- go env

environment:
GOPATH: C:\GOPATH\
HUGO_BUILD_TAGS: extended

# clones and cd's to path
clone_folder: C:\GOPATH\src\github.com\gohugoio\hugo

Expand Down
84 changes: 84 additions & 0 deletions commands/commandeer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package commands
import (
"os"
"path/filepath"
"regexp"
"sync"
"time"

Expand Down Expand Up @@ -46,6 +47,10 @@ type commandeerHugoState struct {
type commandeer struct {
*commandeerHugoState

// Currently only set when in "fast render mode". But it seems to
// be fast enough that we could maybe just add it for all server modes.
changeDetector *fileChangeDetector

// We need to reuse this on server rebuilds.
destinationFs afero.Fs

Expand Down Expand Up @@ -105,6 +110,68 @@ func newCommandeer(mustHaveConfigFile, running bool, h *hugoBuilderCommon, f fla
return c, c.loadConfig(mustHaveConfigFile, running)
}

type fileChangeDetector struct {
sync.Mutex
current map[string]string
prev map[string]string

irrelevantRe *regexp.Regexp
}

func (f *fileChangeDetector) OnFileClose(name, md5sum string) {
f.Lock()
defer f.Unlock()
f.current[name] = md5sum
}

func (f *fileChangeDetector) changed() []string {
if f == nil {
return nil
}
f.Lock()
defer f.Unlock()
var c []string
for k, v := range f.current {
vv, found := f.prev[k]
if !found || v != vv {
c = append(c, k)
}
}

return f.filterIrrelevant(c)
}

func (f *fileChangeDetector) filterIrrelevant(in []string) []string {
var filtered []string
for _, v := range in {
if !f.irrelevantRe.MatchString(v) {
filtered = append(filtered, v)
}
}
return filtered
}

func (f *fileChangeDetector) PrepareNew() {
if f == nil {
return
}

f.Lock()
defer f.Unlock()

if f.current == nil {
f.current = make(map[string]string)
f.prev = make(map[string]string)
return
}

f.prev = make(map[string]string)
for k, v := range f.current {
f.prev[k] = v
}
f.current = make(map[string]string)
}

func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {

if c.DepsCfg == nil {
Expand Down Expand Up @@ -202,6 +269,23 @@ func (c *commandeer) loadConfig(mustHaveConfigFile, running bool) error {
fs.Destination = new(afero.MemMapFs)
}

doLiveReload := !c.h.buildWatch && !config.GetBool("disableLiveReload")
fastRenderMode := doLiveReload && !config.GetBool("disableFastRender")

if fastRenderMode {
// For now, fast render mode only. It should, however, be fast enough
// for the full variant, too.
changeDetector := &fileChangeDetector{
// We use this detector to decide to do a Hot reload of a single path or not.
// We need to filter out source maps and possibly some other to be able
// to make that decision.
irrelevantRe: regexp.MustCompile(`\.map$`),
}
changeDetector.PrepareNew()
fs.Destination = hugofs.NewHashingFs(fs.Destination, changeDetector)
c.changeDetector = changeDetector
}

err = c.initFs(fs)
if err != nil {
return
Expand Down
Loading

1 comment on commit dea7167

@rdwatters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bep Not sure if the idea is that the above description is going to be used directly in the docs, but thought I would mention $styles and not $css. Pretty minute detail, but I noticed while trying to test new SASS features locally 😄

{{ $css := resources.Get "styles.scss" | toCSS | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Digest }}" media="screen">

Please sign in to comment.