Hugo

I’ve been doing front end web dev more and more lately, and wow. Hugo. We know you have your choice of Static Site generators, and we are glad you chose us today It’s nothing revolutionary, you use some markup and it does the thing for you. But the way it extends, how easy it is to hit the edge cases such as adding structured data, have been just pleasant. I’ve been predominantly using it outside of the blog sphere, on a business website. But dang.

Those I’ve Loved Before

I use Jekyll, clearly. It also mostly just works, but it doesn’t tickle the fancies, you know. (Of note, while writing this post I had great difficulty with the templating system, because it tried to parse stuff in the code blocks. Smart. Or, probably actually the other thing.) I’ve used others in the past as well, from simple C-based to Bash shell scripts. The very simple nature of those solutions was wonderful, but that was when very, very basic needs were all I had. No generative stylesheets, no mindfulness about SEO. No real need for bells and whistles. I need a few though, to get things right when the things I’m making aren’t just for me.

Shortcodes

They look like this, ``. They are used to inject snippets into your markdown. They differ from partials which are html snippets and can be used in different scenarios.

I use shortcodes for structuring pages. I started out with a theme called Hugo Story which uses shortcodes for things like Spotlight sections, Banners, etc. Starting from there, it was pretty easy to get what I wanted.


{{ if .IsNamedParams }}
    {{ partial "section" (dict
        "id"      $.Params.id
        "justify" $.Params.justify
        "align"   $.Params.align
        "title"   $.Params.title
        "style"   $.Params.style
        "content" .Inner
    ) }}

{{- end -}}

This little bit of code wraps the use of a tag, like so:


{{< section id="foo" justify="left" align="right" title="My thing" style="2" >}}
Some content here 
{{< /section >}}

Shortcodes are generally most useful when they have a complementary Partial, described below.

A shortcode can also ust be arbitrary:


<button onclick="topFunction()" class="totop" id="totop">
    Back to top
</button>

<script>
// Get the button:
let mybutton = document.getElementById("totop");

// When the user scrolls down 20px from the top of the document, show the button
window.onscroll = function() {scrollFunction()};

function scrollFunction() {
  if (document.body.scrollTop > 400 || document.documentElement.scrollTop > 400) {
    mybutton.style.display = "block";
  } else {
    mybutton.style.display = "none";
  }
}

// When the user clicks on the button, scroll to the top of the document
function topFunction() {
  document.body.scrollTop = 0; // For Safari
  document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
}
</script>

There’s some really cool example shortcodes as well for things like Youtube embeds, this way

Partials

Partials are the HTML complement to Shortcodes, and they have a larger pool of data to pull from such as page front matter and site configuration data. As alluded to above, partials can be called with user-supplied data, which I generally encapsulate with a shortcode.

A details element is commonly used to show more information on a subject, on user request.


<details class="details" aria-expanded="false">
    {{ with .summary }}<summary class="summary">{{ . }}</summary>{{ end }}
    <div class="content">
        {{ .content | safeHTML }}
    </div>
</details>

This would be called with a shortcode, or simply supplying the data


{{ partial "details" (dict 
    "summary" "My summary"
    "contant" "Some more content"
)}}

That’s basically it, they’re simple. They use Go’s powerful templating system, allowing most anything you can dream! This monster handles adding some Schema sections:


<!-- Single nested entries, outside of arrays -->
{{ define "schemaNested" }}  {{ template "schemaSection" (dict "meta" .nested ) -}}
{{ end }}
<!-- Array entries -->
{{ define "schemaArray" }}[
{{ range $index, $value := .array }}{{ if $index }},{{ end }}{
  {{ template "schemaSection" (dict "meta" $value ) }}
}{{ end }}]
{{ end }}
<!-- Nested entries inside arrays -->
{{ define "schemaMap" }}    {{ template "schemaSection" (dict "meta" .map ) }}
{{ end }}
{{ define "schemaSection" }}{{ $items := .meta }}
  {{ if $items }}{{ if $items.type }}"@type": "{{ $items.type }}"{{ end }}{{ range $key, $value := $items }}{{ if not (eq $key "type") }}{{ if (index $items $key) }},{{ end }}
  "{{- $key -}}": {{ if eq (printf "%T" $value) "maps.Params" }}{ {{ template "schemaNested" (dict "nested" $value)}}
  }{{ else if eq (printf "%T" $value) "[]interface {}" }}{{ template "schemaArray" (dict "array" $value)}}{{ else if eq (printf "%T" $value) "map[string]interface {}" }}{ {{ template "schemaMap" (dict "map" $value)}}
  }{{ else }}"{{- $value | safeHTML -}}"{{ end }}{{ end }}{{ end }}{{ end }}{{ end }}
  <script type="application/ld+json">
  {
    "@context": "http://schema.org",
    {{ template "schemaSection" (dict "meta" .Params.meta) -}}
    {{ end }}
  }
  </script>

It’s a lot, and it’s vary specific to my needs, but it uses a recursive template to make the necessary nested elements used in json+ld files, and I only have to think about it one time! This pulls from a pages frontmatter. Given the following:

---
title: "My fine page"
description: "My fine description"
meta:
    type: "BlogPosting"
    name: "My post"
    headline: "Check out my blog!"
---

Which was awesome. You can get as deep structures as you need. Even arrays work:

meta:
  type: "FAQPage"
  mainEntity:
  - type: "Question"
    name: "Why Hugo?"
    acceptedAnswer:
      type: "Answer"
      text: "It is so nice!"
  - type: "Question"
    name: "Why not Jekyll?"
    acceptedAnswer:
      type: "Answer"
      text: "Personal preference"

Which generates something like this:

{
    "@type": "FAQPage",
    "mainEntity": [{
        "@type": "Question",
        "name": "Why Hugo?"
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "It is so nice!"
        }
    }, {
        "@type": "Question",
        "name": "Why not Jekyll?",
        "acceptedAnswer": {
            "@type": "Answer",
            "text": "Personal preference"
        }
    }]
}

Pretty awesome, pretty freaking handy.

SCSS

I use SCSS in my dayjob, not much I can say that isn’t covered excellently elsewhere. The theme I have been using has great breakpoints, and honestly it has really grown on me.

Accessibility

…it isn’t there, but really it isn’t anywhere. But it is easy to add in to your partials, shortcodes, and bam your site no longer sucks to use on anything that isn’t Chrome at default settangs and a mouse.

<nav role="navigation" aria-label="main-navigatioh" id="nav" class="main-navigation">
  <ul id="list">
    
    <li><a class="nav-item" href=""></a></li>
    
    
  </ul>
</nav>

Roll your own in a templating system isn’t all bad, really.

Conclusion

My main use case for Hugo is https://alltogethersurrogacy.ca, it’s pure Hugo, it’s fast and easy to extend. It’s been very nice to use so far, and with the familiarity and flexibility of Go templates I’ve been more than happy!