Serverless dynamic content with Hugo and JavaScript

Wow that’s a $10 title, but it’s really the goal of this post - to show you how you can use Hugo and still retain all of the JavaScript goodies for dynamic content. For those who don’t know, in general for dynamic content you will typically require having a server with a database somewhere which allows you to request data. With Hugo there is no database, or place to pull the content, at least at first glance.

Recently, I ran into this very problem due to the Google maps static map API only supporting single digits. I had proudly wrapped up the tenth camping review and then checked out the Camping Reviews page and was greeted with a dot instead of 10. At first I thought it was an issue with how it rendered on my ThinkPad Chromebook, but after trying on another device I found that it was not. I looked around the internet for a few hours trying to resolve the issue, but it was what it was. Without going to an A-Z and then 1-9 system or some funky color coding system, I was stuck.

So I then did what every other coder would do and stared at my source code, hoping the coding gods would grant me some enlightenment. After a few minutes of just blindly staring at my code, this particular code block got my attention.

{{ range sort (index .Site.Taxonomies.tags "tagFilter") ".Page.Params.date" }}
    ...Some code to build out the strings here
{{ end }}

For those not familiar with Hugo, or at least its short codes, the prior code block is simply saying give me all of the posts with the tag “tagFilter” and then return those posts in date order. I had been using the code to build out the Google Maps Static maps for many of the pages, mainly to reduce the API calls to the service, because JavaScript maps count as extra calls. This block got me thinking - why couldn’t I use the same pattern to build out an JavaScript array?

This would mean that I would need to use the Google Maps JavaScript API, but then I could get all of the other goodies that came with it - hover overs, click through links, etc. So I changed the loop to build out an array with the following code:

</script>
var array = [
    {{ range sort (index .Site.Taxonomies.tags "tagFilter") ".Page.Params.date" }}
      [
        {{ .Page.Params.YourAttribute1 }},
        {{ .Page.Params.YourAttribute2 }},
        {{ .Page.Params.YourAttribute3 }},
      ],
    {{ end }}
  ];
</script>

I’m passing more then three attributes, but this is the general idea

With this pattern, you can grab any of the attributes that you like from the pages and build out your array. I then used the developer documentation for the Google Maps API to fill in the missing parts of the mapping code. To my delight, I was greeted with the following display:

It still works!

Meaning that everything worked as planned and that it is possible to do this. After multiple interactions and adjusting the Google maps code, I was happy with the results and committed my code for deployment. You can check out the results on Camping Reviews page

Overall

While there are many ways to accomplish this same effect, this worked out well for my use case. If I needed to pull the same information on multiple pages, then I’d probably do something more elegant, such as building out a XML or JSON file with all of the data, then pulling it in with a AJAX call. In the end it’s about the simplest solution to solve the problem, and this fit perfectly in with that. No extra database, no special pages for data calls, and one easy to maintain code base.

Always follow the manufacturers instructions, this write up is simply the way that I do it, and it may or may not be the right way. Use your common sense when applying products to or altering your stuff and always wear the appropriate safety gear.