Permalink
Browse files

Add Hugo Piper with SCSS support and much more

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 Feb 20, 2018
1 parent a5d0a57 commit dea71670c059ab4d5a42bd22503f18c087dd22d4
Showing with 4,686 additions and 1,126 deletions.
  1. +2 −0 .gitignore
  2. +4 −1 .travis.yml
  3. +6 −0 CONTRIBUTING.md
  4. 0 Dockerfile
  5. +65 −1 Gopkg.lock
  6. +20 −0 Gopkg.toml
  7. +7 −1 appveyor.yml
  8. +84 −0 commands/commandeer.go
  9. +69 −23 commands/hugo.go
  10. +23 −0 common/errors/errors.go
  11. +1 −1 create/content_template_handler.go
  12. +3 −0 create/content_test.go
  13. +27 −5 deps/deps.go
  14. +3 −3 helpers/general.go
  15. +15 −0 helpers/path.go
  16. +9 −0 helpers/path_test.go
  17. +3 −0 helpers/testhelpers_test.go
  18. +84 −0 hugofs/basepath_real_filename_fs.go
  19. +96 −0 hugofs/hashing_fs.go
  20. +53 −0 hugofs/hashing_fs_test.go
  21. +4 −3 hugolib/alias.go
  22. +1 −1 hugolib/alias_test.go
  23. +1 −0 hugolib/config.go
  24. +177 −54 hugolib/filesystems/basefs.go
  25. +86 −6 hugolib/filesystems/basefs_test.go
  26. +5 −10 hugolib/hugo_sites.go
  27. +2 −2 hugolib/hugo_sites_build_test.go
  28. +26 −15 hugolib/page.go
  29. +1 −1 hugolib/page_bundler.go
  30. +3 −3 hugolib/page_bundler_capture_test.go
  31. +9 −4 hugolib/page_bundler_handlers.go
  32. +0 −2 hugolib/page_bundler_test.go
  33. +1 −1 hugolib/page_collections.go
  34. +19 −5 hugolib/page_output.go
  35. +5 −1 hugolib/page_paths.go
  36. +1 −1 hugolib/page_paths_test.go
  37. +1 −1 hugolib/pagination.go
  38. +2 −2 hugolib/pagination_test.go
  39. +9 −1 hugolib/paths/baseURL.go
  40. +5 −0 hugolib/paths/baseURL_test.go
  41. +32 −5 hugolib/paths/paths.go
  42. +4 −0 hugolib/paths/paths_test.go
  43. +63 −33 hugolib/prune_resources.go
  44. +210 −0 hugolib/resource_chain_test.go
  45. +5 −5 hugolib/shortcode.go
  46. +25 −11 hugolib/site.go
  47. +4 −4 hugolib/site_render.go
  48. +2 −2 hugolib/site_sections.go
  49. +1 −1 hugolib/site_sections_test.go
  50. +9 −3 hugolib/testhelpers_test.go
  51. +3 −0 i18n/i18n_test.go
  52. +16 −5 magefile.go
  53. +26 −2 media/mediaType.go
  54. +14 −0 media/mediaType_test.go
  55. +263 −263 parser/long_text_test.md
  56. +121 −0 resource/bundler/bundler.go
  57. +77 −0 resource/create/create.go
  58. +19 −51 resource/image.go
  59. +5 −11 resource/image_cache.go
  60. +9 −9 resource/image_test.go
  61. +106 −0 resource/integrity/integrity.go
  62. +54 −0 resource/integrity/integrity_test.go
  63. +115 −0 resource/minifiers/minify.go
  64. +175 −0 resource/postcss/postcss.go
  65. +439 −252 resource/resource.go
  66. +241 −0 resource/resource_cache.go
  67. +129 −0 resource/resource_metadata.go
  68. +230 −0 resource/resource_metadata_test.go
  69. +47 −265 resource/resource_test.go
  70. +76 −0 resource/templates/execute_as_template.go
  71. +10 −7 resource/testhelpers_test.go
  72. +101 −0 resource/tocss/scss/client.go
  73. +111 −0 resource/tocss/scss/tocss.go
  74. +30 −0 resource/tocss/scss/tocss_notavailable.go
  75. +487 −0 resource/transform.go
  76. +36 −0 resource/transform_test.go
  77. +7 −1 source/filesystem_test.go
  78. +2 −2 tpl/collections/apply_test.go
  79. +2 −2 tpl/os/init.go
  80. +1 −1 tpl/os/os.go
  81. +6 −5 tpl/partials/partials.go
  82. +68 −0 tpl/resources/init.go
  83. +255 −0 tpl/resources/resources.go
  84. +14 −1 tpl/template.go
  85. +73 −24 tpl/tplimpl/template.go
  86. +5 −5 tpl/tplimpl/templateFuncster.go
  87. +2 −0 tpl/tplimpl/templateProvider.go
  88. +10 −2 tpl/tplimpl/template_funcs.go
  89. +7 −2 tpl/tplimpl/template_funcs_test.go
  90. +7 −4 tpl/tplimpl/template_test.go
View
@@ -15,5 +15,7 @@ vendor/*/
*.debug
coverage*.out
dock.sh
GoBuilds
dist
View
@@ -1,6 +1,8 @@
language: go
sudo: false
dist: trusty
env:
HUGO_BUILD_TAGS="extended"
git:
depth: false
go:
@@ -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:
View
@@ -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.

@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
View
0 Dockerfile 100644 → 100755
No changes.
View

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
View
@@ -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"
@@ -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"
View
@@ -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
View
@@ -16,6 +16,7 @@ package commands
import (
"os"
"path/filepath"
"regexp"
"sync"
"time"
@@ -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
@@ -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 {
@@ -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
Oops, something went wrong.

1 comment on commit dea7167

@rdwatters

This comment has been minimized.

Contributor

rdwatters commented on dea7167 Jul 7, 2018

@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.