BryceWray.com

Webmentions in three SSGs: Part 3

IndieWebbin’ in Hugo

published:  April 28, 2020
last modified: May 16, 2020

Note: This is Part 3 of a five-part series about how you can set up webmentions in Web sites built by three different static site generators: Eleventy (the subject of Part 2), Hugo (the subject of this part), and Gatsby (covered in detail in Part 4). In the conclusion, you’ll find a bibliography of the best articles I found on the subject of this series. All of the articles link (even if only through tiny GitHub logos) to their authors’ code. They were invaluable to this effort, and I encourage you to take particular notice of them and their authors.

In the introduction to this five-part series, I gave you a quick run-through about the IndieWeb and the general setup of webmentions. In Part 2, the subject was how you implement webmentions specifically in the Eleventy SSG. Now, here in Part 3, we’ll talk about implementing them in the Hugo SSG.

Of the three repos, I worked on the Hugo repo before the Gatsby repo, because I figured (wrongly) that webmention-izing it to match the Eleventy repo would be more difficult than doing so for the Gatsby repo, so I wanted to get it over with. I based this assumption on the fact that both the Eleventy and Gatsby repos ran on JavaScript, while the Hugo repo was overwhelmingly Go-based.

In short: everything I’d learned up to that point involved JavaScript code and, with the Hugo repo, suddenly I’d be starting from scratch.

Or so I thought.

Fortunately, just as I’d already found ways to integrate JavaScript with the Hugo repo when adding PostCSS to it, it turned out there still would be use for some of the JS I’d borrowed/stolen for the Eleventy repo. Even better, it proved easier than I’d expected—not easy, but easier than I’d expected—to translate some of the JS to Hugo-flavored Go when that became utterly necessary.

Hugo: Fetching webmentions

There’s plenty of data-massaging capability built into Hugo, so I wasn’t so worried about how I’d handle that end of the process. My concern was how I’d go out to webmention.io and grab the data in the first place.

After I’d read a few articles and reviewed the associated code, I realized the best approach was, again, JavaScript-based. That ended up as /assets/js/webmentions.js which was based mostly on Paul Kinlan’s work but also, to a limited extent, on the code by Max Böck and Sia Karamalegos that I used in the Eleventy repo.

Kinlan’s code took a different approach: rather than fetching and then aggregating all the site’s currently available webmentions into one JSON file, it downloaded into /data/ a separate JSON file of webmentions for each page that had received them. To keep the files straight, the code applied MD5 hashing to the URL for each page with webmentions, then gave that page’s JSON file the same hashed name.

Or, at least it would if it could fetch the webmentions from webmention.io. And therein lay the biggest problem I faced with the Hugo repo.

You see, one thing you have to “present” to webmention.io to “prove” that your site “deserves” to grab the webmentions is an authentication token. In the Eleventy site, you can easily handle this by creating a file, /.env, for storing such so-called environment variables out of sight (don’t source-control such a file; instead, add it to your .gitignore) but exposing them to other code through generic names such as WEBMENTION_IO_TOKEN. In an SSG like Eleventy or Gatsby that uses Node JS, that works because of a widely used npm package called dotenv.[1]

Fine, I wondered, but how to do this in Hugo? Yes, I already had the repo using JavaScript because of PostCSS, but this was another matter. I was trying to get a non-Node-JS app to accept an environment variable from Node JS.

For a while, it looked as if the only working method would require including the token in plain sight in a GET-style query string: e.g., something like https://webmention.io/api/mentions.jf2?domain=brycewray.com&token=1234567890123. Not a good idea, as you can imagine.

Finally, after hours of sifting through similar issues reports from Hugo users, I found the answer: setting up the appropriate /package.json-based scripts to run /assets/js/webmention.js after a command that would first run dotenv and, thus, “force-feed” it the environment variable! For example, the /package.json line[2] for fetching webmentions in development mode was:

"dev:wmFetch": "node -r dotenv/config assets/js/webmentions.js"

Note: If you deploy a repo like this through Netlify, that /.env file is irrelevant in production, since the proper procedure is to let Netlify handle sending an environment variable at the appropriate time. Other than during development, I use that file only for executing “production” builds on my local setup in the testing process through the testbuild script in /package.json.

Hugo: Displaying webmentions

After that, the only major thing left was creating a Hugo “partial”—/layouts/partials/webmentions.html—which would make the data presentable. I relied heavily on the Eleventy /_data/webmentions.js as my guide for writing the Go-flavor Hugo code to make this happen.

I expected the biggest hassle in that final part of the “webmention-izing Hugo” project would be getting Hugo to recognize the MD5-hashed URLs of the respective JSON files. Not so. Fortunately, Hugo has built-in support for MD5. And, in the end, I actually appreciated the whole approach because it simplified the process of identifying which set of webmentions went with each respective Web page.

That left only:

Done.

Next up: Gatsby

So, it was on to the Gatsby repo, which I naïvely believed would be a relative piece of cake. All I’d have to do was make a few changes to the JS from my Eleventy repo (see Part 2 of this series). Right? Hmm?

Ahhh, not exactly, Space Cadet. Follow me to Part 4—if you have the stomach for witnessing a bloody struggle.


  1. But Gatsby still made it, um, interesting, as you’ll see in Part 4. ↩︎

  2. This is invoked by the npm run start or npm run build script, as appropriate for your use case, in conjunction with the necessary Hugo script. ↩︎

Webmentions

(No webmentions yet.)

Other posts

Next: Webmentions in three SSGs: Part 4

Previous: Webmentions in three SSGs: Part 2