How to reduce the length of the site stylesheet filename?

My CloudFlare build is busted because stylesheet is not being linked to the site. Dev at CloudFlare is acknowledging a possible bug in their build pipeline. Problem is that css is assigned a mime type of either application/octet-stream or text/html. Caused (not known for sure yet) by either CloudFlare thinking a long sha fingerprint in the filename is binary data or is simply too long for it!

So, it was suggested that I use a shorter fingerprint. Well, that is not so easy:

I tried this:

{{ $styles := resources.Get "scss/main.scss" | resources.ExecuteAsTemplate "style.main.scss" . | toCSS | minify | fingerprint }}

    {{ $pieces := path.Split $styles}}
    {{ $ext := path.Ext $styles }}
    {{ $basename :=  strings.TrimSuffix $ext $pieces.File}}
    {{ $basename := slicestr $basename 0 9 }}
    {{ $styles := path.Join $pieces.Dir $basename $ext}}

The problem is that the thing called $styles is not a string of the file name. it is some sort of slice with a bunch of properties. Is there a $styles.Name property? If I reset the basefile name within this property, could I truncate it? Sure, some uniqueness is lost and maybe I wouldn’t invalidate the cache when I should be I’ll go with the first 10 chars of a SHA fingerprint “frequently” being unique.

Until then, I am just going to eliminate the fingerprint from the pipeline. So, won’t invalidate the cache if I change baseof.html, but I never will again once this all works.

Thanks.

PS–Folks at CloudFlare are looking into this. Realize they should just use the filename as provided.

Here is a better version that almost works except…

{{ $styles := resources.Get "scss/main.scss" | resources.ExecuteAsTemplate "style.main.scss" . | toCSS | minify | fingerprint }}


    {{ $hrefstyles := $styles.Permalink }}
    {{ $pieces := path.Split $hrefstyles}}
    {{ $ext := path.Ext $hrefstyles }}
    {{ $basename :=  strings.TrimSuffix $ext $pieces.File}}
    {{ $basename := slicestr $basename 0 20 }}
    {{ $hrefstyles := path.Join $pieces.Dir (print $basename $ext) }}


    <link rel="stylesheet" href="{{ $hrefstyles }}" />

This correctly grabs the text of the url to the style sheet and truncates the sha that is put into the base filename. Slight problemma: then, the url doesn’t match the actual link to the resource! So, I need to “fix” the name before the layout gets the Permalink to it.

The fingerprint is there to compare the content of your stylesheet against that fingerprint and go sure, that there is no pampering done between the server and the browser. You are using it to add it to a filename which is useless and overwork for Hugo, the server, and the browser. Just do a random string if you need a cachebuster.

It’s not just the cache as a whole. It is about invalidating individual files in the resources directory or build cache. Hugo changes resources incrementally. It is also about the browser caches of individual users so that their browsers load a new version of files from sites they are using…

Just sayin’

@davidsneighbour Is quite correct in saying that a sha hash is overkill for cachebusting purposes and given that it is giving you an issue with cloudflare also you may want to rethink that. Fingerprinting with a strong sha is only required for implementing subresource integrity, a security mechanism, like this:

<link href="/main.42c2d.css" rel="stylesheet" integrity="sha512-AVMHwiIToB9NSz2UcedQ0IwNL3dbl28ORpV3d4F/2uDSpXszTNisnK630ZHnlO+j0q59FgJDyJfYWf8O+8YgbA==" crossorigin="anonymous">

The shortest you get with fingerprinting is

{{ $styles := resources.Get "scss/main.scss" | resources.ExecuteAsTemplate "style.main.scss" . | toCSS | minify | fingerprint "md5" }}

We have an open issue about somehow making these shorter, but I’m a little bit surprised about the issues we’ve seen with Cloudflare lately. They are a multibillion dollar company and should do better. I had a similar issue myself where they, for some reason, defaulted to minifying all CSS/JS, totally ignoring the fact that they had SRI hashes.

I think it is worth mentioning that md5 should not be used for subresource integrity values though, as browsers should reject it: Subresource Integrity

That is correct.

If you really need to use md5 for fingerprinting and still use SRI, you can do:

{{ $styles := resources.Get "scss/main.scss" | resources.ExecuteAsTemplate "style.main.scss" . | toCSS | minify }}
{{ $sri := $styles | fingerprint }}
{{ $styles = $styles | fingerprint "md5" }}

And then use both of them to construct the CSS link.

Thanks all. They’re still working on it. Turns out issue has nothing to do with length of filename or embedded strings in the file name. I tried md5 (which I’ll get rid and go back to default sha256) and no fingerprinting. No effect. I will look at no minify also. They acknowledge it is their problem (devs on discord are straightforward). My other blog there doesn’t have a problem but I think the difference might be between scss compiled to css and straight css. Not clear why… …just trying to pinpoint the difference. Meanwhile the worker thingee works fine and costs 1.2 ms a request. A work-around, but not a costly one.

1 Like

So, should I get rid of it? Why is it designed into many themes? What’s the alternative for the case when I do modify the css (especially rare since the site css is compiled from scss…)?

Thanks. Learning a lot here…

The prime motivation for fingerprinting is “cache busting”, and the only way around that is to turn off caching or set the cache expiry to a short value.

So, I should do it.

Why the advice not to?

Not sure who said that? I saw a question about some problem with long filenames, and we were discussing workarounds for that.

Asset revving is very useful as a cache-invalidation mechanism, simple and reliable. As you saw, it’s something I rely on.

Not fingerprinting. It wasn’t you. Someone (forgot…) said it was overkill for cache-busting and there were other ways. Someone else pointed out that it was a security measure to make sure the stylesheet wasn’t altered “during delivery”. But, that could be said for everything in the http response. Do browsers check the hash in the filename of the stylesheet, recalculate the cache and check?

Yes.

https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity

1 Like

Tx.

As someone else pointed out, we can do SRI with specific tags in the script or link element rather than in the filename—the latter of which serves more for cache-busting.

Do you have an example of doing this using the Hugo fingerprint function? It would be a way to eliminate one variable in sorting CloudFlare’s problems—although I turned fingerprinting off entirely and they still generated the wrong mime type.

Thanks for everyone’s suggestions. I think I’ll just let CF people do their jobs to debug their product and see if they can…

This template code:

{{ $css := resources.Get "scss/main.scss" | resources.ExecuteAsTemplate "assets/css/style.css" . | toCSS | minify }}
{{ $temp := $css | fingerprint }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $temp.Data.Integrity }}">

Produces something like:

<link rel="stylesheet" href="/assets/css/style.min.css" integrity="sha256-FcQqt3aNlV7AZnGV4zkQRVeCeJOxbMPnQSx258L803E=">

So you get SRI without a cache-busting file name.

Thank you very much. This is worth trying.

Sorry, couldn’t leave this alone. Here’s a way to use a short cache-buster with SRI.

{{ $resource := resources.Get "scss/main.scss" }}
{{ $cacheBuster := $resource.Content | sha1 | first 7 }}
{{ $options := dict "targetPath" (printf "assets/css/style.%s.css" $cacheBuster) }}
{{ $css := $resource | toCSS $options | minify }}
{{ $temp := $css | fingerprint "sha512" }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}" integrity="{{ $temp.Data.Integrity }}">

This produces something like:

<link rel="stylesheet" href="/assets/css/style.1dcc57d.min.css" integrity="sha512-fmZ7KIvKJWaEORLQ2z2&#43;&#43;C7Hlc1fyYRXraeMLFwi38W00&#43;Az3xZ&#43;yFQsve16eKZwL0&#43;yPrJQ0W/s&#43;IT2XZ3i0Q==">

1 Like