Hacktoberfest week two! Week one was all about getting into the groove of Hacktoberfest, making a small change to contribute, and finding out about other awesome projects in open source and my area of interest.
My contribution for this week had a bit more self-interest involved; I contributed a change to dplesca/purehugo, the Hugo blog theme I use for this blog, to normalize URLs that use Hugo’s .Site.BaseURL
variable.
The Problem
Using the dplesca/purehugo theme, I was noticing that many links to other parts of the site - that is, links that were not external links to e.g. GitHub or Twitter - contained multiple slashes after the site root. Modern web browsers are really good at dealing with partially-malformed URLs so there was no functional problem with any of the links as the browser’s URL parser took over and cleaned them up into a value it could resolve, but it would still be better if the URLs were correctly formatted when Hugo generates the static site content.
The malformed URLs looked something like this:
<a class="pure-button" href="http://localhost:1313//index.xml">[...]</a>
<a class="post-category post-category-open source" href="http://localhost:1313//categories/open-source">open source</a>
Delving into the template code revealed how dplesca/purehugo
was generating the URLs:
<a class="pure-button" href="{{ .Site.BaseURL }}/index.xml">[...]</a>
<a class="post-category post-category-{{ . }}" href="{{ $baseUrl }}/categories/{{ . | urlize }}">{{ . }}</a>
The template string used .Site.BaseURL
and appended a slash before the next URL fragment. Since this results in a double slash in the generated output, I presume but have not confirmed that .Site.BaseURL
always ends in a trailing slash that needs to be taken into consideration when generating URLs relative the the site’s root.
The Solution
In a similar way to how we join file paths in NodeJS with path.join(), we almost never want to be responsible for building URL paths ourselves. Luckily, Hugo provides many built-in helper functions that cover a whole range of use cases, including the one I decided to use to normalize URL paths throughout dplesca/purehugo
: absURL
From the Hugo documentation, absURL
Creates an absolute URL based on the configured
baseURL
.
where baseURL
is the hostname (and path) to the root of the site which is set as part of Hugo’s site configuration.
This function was a perfect solution in most of the places where static files need to be linked and served to the client, such as JavaScript or CSS content. In those cases it was a simple matter of removing .Site.BaseURL
and the subsequent concatenation and replace it with a call to the absURL
function, like so:
<a class="pure-button" href='{{ "index.xml" | absURL }}'>[...]</a>
Normalizing the post category links turned out to be a bit more complicated than this simple substitution because these links needed to include more URL fragments to create the complete path. In order to correctly concatenate and then normalize these URLs, I turned to another of Hugo’s built-in functions: printf.
Hugo’s templating system is built almost entirely on top of Go’s built-in template package, which makes things very familiar if you have worked with Go templates before. It also means that Hugo can expose a lot of Go functions as Hugo functions available inside templates. In this case, Hugo’s printf
function exposes Go’s fmt.Sprintf
function which works much like printf
in C.
This is the solution I came up with for building the more complicated post category link URLs while still being able to normalize the resulting URL using absURL
:
<a class="post-category post-category-{{ . }}" href='{{ ( printf "categories/%s" . ) | absURL }}'>{{ . }}</a>
Unlike in NodeJS, in this case it’s safe to do a simple string concatenation of categories/<category-name>
because unlike with file systems, the fragment separator in URLs is always the /
character.
To be Continued
I am very thankful to purehugo
’s author, @dplesca, for responding so quickly to my pull request with this change and for merging the pull request within a few hours of my submission. While working on this change I noticed a few other areas where I think dplesca/purehugo
could be improved, and I’m looking forward to working on it more as I continue using it to generate my blog and host my site content.
Hacktoberfest continues on, and I need to start thinking about my next contribution. My school is on a break starting next week, so I’m hoping to find the time to dig into something a bit larger and more challenging based on the projects I’ve seen so far or had recommended to me by classmates.