gohugoio / hugo

The world’s fastest framework for building websites.
https://gohugo.io
Apache License 2.0
73.49k stars 7.38k forks source link

PostCSS and sourcemaps #6189

Open XhmikosR opened 4 years ago

XhmikosR commented 4 years ago

I'm trying to use Hugo assets in an upcoming project.

While I enable sourcemaps in Sass and it's output, I can't find a way for postcss to use the sourcemap from Sass thus making it possible to debug the final PostCSS-processed CSS.

I'm not sure if this is even possible with postcss-cli, but in Bootstrap core we use a postcss.config.js with the following map options:

    {
      inline: false,
      annotation: true,
      sourcesContent: true
    }

This is what I've tried so far:

{{- $sassOptions := (dict "targetPath" "assets/css/docs.css" "enableSourceMap" true) }}
{{- $postcssOptions := (dict "no-map" false "nomap" false) }}
{{- $style := resources.Get "scss/docs.scss" | toCSS $sassOptions | postCSS $postcssOptions | fingerprint }}
<link rel="stylesheet" href="{{ $style.Permalink | relURL }}">

docs.css does not have the sourceMappingURL comment and the map file is the one from the Sass build.

If I set the aforementioned map options then I get a PostCSS error:

Building sites … Output Error: Cannot output external sourcemaps when writing to STDOUT
bep commented 4 years ago

This has been discussed before and is currently not possible. The best you can do is to disable postCSS in development and use the SASS source maps.

XhmikosR commented 4 years ago

Hmm, true, that's an acceptable workaround.

I wonder, how this could be implemented later. I mean, if postcss-cli can't do this, there's not much you can do on Hugo's side, right?

bep commented 4 years ago

Yes, it can be implemented, but it's not something that can be done in 5 minutes ... And I have some other ideas in this department that involve talking with the JS world, so we may rethink this when that happens.

XhmikosR commented 4 years ago

Cool, I'll wait for a proper solution :)

In the meantime this is what I did:

{{- $sassOptions := dict "targetPath" "assets/css/docs.css" -}}

{{- if (eq (getenv "HUGO_ENV") "production") -}}
  {{- $sassOptions = merge $sassOptions (dict "outputStyle" "compressed") -}}
{{- else -}}
  {{- $sassOptions = merge $sassOptions (dict "enableSourceMap" true) -}}
{{- end -}}

{{- $style := resources.Get "scss/docs.scss" | toCSS $sassOptions -}}

{{- if (eq (getenv "HUGO_ENV") "production") -}}
  {{- $style = $style | postCSS | fingerprint -}}
{{- end }}
<link rel="stylesheet" href="{{ $style.Permalink | relURL }}">
bep commented 4 years ago

I suggest you use:

{{- if eq hugo.Environment "production" -}}

Which gets sensible defaults.

XhmikosR commented 4 years ago

I didn't even know there was a hugo.Environment. I guess this will simplify how we set HUGO_ENV which ATM we do with the cross-env package. Thanks for the tip!

bep commented 4 years ago

Note that you need to set HUGO_ENVIRONMENT if you want to set that value (you can also set it in config.toml etc.).

But it defaults to sever=development and regular hugo=production.

bep commented 4 years ago

There is docs about this, but one nice benefit is that you can add environment specific config below config/development etc.

XhmikosR commented 4 years ago

Note that you need to set HUGO_ENVIRONMENT if you want to set that value (you can also set it in config.toml etc.).

I tried searching the docs and nothing comes up about HUGO_ENVIRONMENT. I only found your post on the forum :) https://www.google.com/search?q=site%3Agohugo.io+%22HUGO_ENVIRONMENT%22

Thanks for the tip, I'll probably make the switch to HUGO_ENVIRONMENT instead of HUGO_ENV, although arguably it's shorter :P

Traumflug commented 4 years ago

Dropping PostCSS for development isn't really an option in our setup, because one of the PostCSS modules copies required fonts from the NPM repository into place. No PostCSS means no fonts.

(Yes, this also requires adding the --renderToDisk parameter to hugo server)

Traumflug commented 4 years ago

Regarding a solution: enabling inline source maps when running libsass shouldn't be too hard to implement. This would also better match the meaning of "Pipes", IMHO.

Traumflug commented 4 years ago

Actually, a change as simple as this (and rebuilding Hugo) got inline source maps working:

diff --git a/resources/resource_transformers/tocss/scss/tocss.go b/resources/resource_transformers/tocss/scss/tocss.go
index ad581d68..ba21a3f1 100644
--- a/resources/resource_transformers/tocss/scss/tocss.go
+++ b/resources/resource_transformers/tocss/scss/tocss.go
@@ -132,7 +132,7 @@ func (t *toCSSTransformation) Transform(ctx *resources.ResourceTransformationCtx
                options.to.OutputPath = outName
                options.to.SourceMapContents = true
                options.to.OmitSourceMapURL = false
-               options.to.EnableEmbeddedSourceMap = false
+               options.to.EnableEmbeddedSourceMap = true
        }

        res, err := t.c.toCSS(options.to, ctx.To, ctx.From)

PostCSS or its config needs no change, inline source maps are enabled by default already.

Verified to work even after melting down CSS from 13598 lines to 1723 lines with various PostCSS modules (PurgeCSS, etc.). Minor caveat: an external source map still gets generated, it matches CSS before PostCSS processing.