Gems in the rough #18

Code for copying code, HugoConf, loose ends.


General note: This site’s appearance, configuration, hosting, and other basic considerations will change over time. As a result, certain content on this page could be at variance with what you’re currently seeing on the site, but the two were consistent when this post originally appeared.

Each entry in the “Gems in the rough” series is a collection of tips, explanations, and/or idle observations which I hope will be at least somewhat useful to those of you with websites built by static site generators (SSGs).

Code for copying code

I’ve long appreciated the way some sites have code blocks which include “Copy” buttons or links. Especially since many code blocks have long lines which extend well beyond the blocks’ widths, this “click-to-copy” feature is extremely useful. This week, I finally bit the bullet and researched how to do this (links to come shortly), then implemented it herein.

Here’s a sample with some JavaScript code. To see the “Copy” button, move the cursor over the code block. To copy the code, click/tap on the resulting button. The “Copy” icon changes to a checkmark, indicating that the copying was successful; to prove it, paste the copied code into a text file.

async function handleRequest(req) {
	const res = await fetch(req);
	const contentType = res.headers.get("Content-Type");
	if (contentType.startsWith("text/html")) {
		return rewriter.transform(res);
	} else {
		return res;
const rewriter = new HTMLRewriter()
	.on("a", new AttributeRewriter("href"))
	.on("img", new AttributeRewriter("src"));
addEventListener("fetch", (event) => {

My research found four sources on which I chose to rely (and the latter three all relied on the first for guidance). As of this writing, I’m using a slight variation on the code suggested by the Simpler Nerd site, but I recommend all the below-listed articles for your own consideration. While they’re aimed at Hugo users and some of their instructions are Hugo-specific as a result, their JavaScript should be readily adaptable for use with other SSGs.1

Note: It’s not a typo; two of the articles do have identical titles.

Incidentally, I purposely chose not to add visible indications of each code block’s language. Those are nice, but I sometimes have to fudge that setting a bit2 to get decent highlighting on certain code; so, say, it wouldn’t help you to see a balloon calling that code jinja if it isn’t really from the Jinja2 template engine.

HugoConf is coming

In recent months, the folks at CloudCannon have been making significant gains to their support for Hugo. Up to now, that support has taken the form of software development and online content (some of the latter of which I’ve had the pleasure of helping to create). It now also includes an online event, HugoConf, coming in July, as noted on Twitter:

Introducing the inaugural #HugoConf, celebrating the world’s fastest static site generator, @GoHugoIO. (And the legion of developers and contributors who make it possible!) 🤩

Register free at to join us on July 8-9.

I’d urge Hugo aficionados, as well as those simply curious about Hugo, to give this a look-see.

Loose ends

Following up on things I’d mentioned in previous posts, whether “Gems in the rough” or otherwise:

  • After last year’s series of articles about password management, during which I mentioned that I’d pretty much abandoned 1Password for Bitwarden, I re-thought that decision and came back to 1Password. Also, contrary to the reactions of the folks whose opinions I cited, I am delighted by 1Password 8. The anti-Electron crowd and anti-subscription crowd will never relent, but I’ve never been in either of those respective camps and, thus, don’t give a hang.
  • Vercel still hasn’t provided non-Next.js code examples for the Edge Functions it announced last October 26. I’ve pretty much given up waiting.3 Besides, Vercel Edge Functions are really just white-labeled Cloudflare Workers, and I’ve found the real thing more than good enough, especially considering how Workers mesh so seamlessly — as you’d expect — with Cloudflare Pages.
    Speaking of CFP . . .
  • To repeat what I said in a May 10 update to a CFP-related story in “Gems in the rough #15,” in case you missed it: “Cloudflare announced today that the [Fast Build] infrastructure fixes are now generally available.” The only remaining piece of the puzzle is for CFP to use build caching, as does Vercel, to make the process even quicker. According to what I’ve seen on the Cloudflare Developers Discord, build caching is in the works for CFP, albeit without a publicly disclosed ETA.
  • I no longer use Bitbucket as a remote host for any of my various repositories. This closes the chapter on some of this site’s history because, until I began also using both GitHub and GitLab in 2019, Bitbucket was the site’s only repo host. My decision to drop it came after I found increasing difficulty with logins: something became repeatedly borked with Bitbucket’s two-factor authentication process, and I simply ran out of patience. Honestly, it wasn’t that painful a choice, given that I’ve long preferred GitHub and GitLab for a variety of reasons, anyway.

  1. The JavaScript is looking for a specific class, so just look at the HTML/CSS your SSG generates to separate a code block from regular text. Here’s a fictional example: if you see that the SSG assigns <div class="codeBlock"> to each code block, edit the JavaScript so that it seeks divs with the codeBlock class. (As-is, the JavaScript looks for highlight, which Hugo uses to designate a code block.) ↩︎

  2. The quality of a site’s syntax highlighting is, in large part, governed by the available language choices which vary from SSG to SSG. For example, only when a site is on Hugo does it know how to highlight go-html-template for Hugo’s mixture of Go and HTML for templating. On the other hand, I doubt if any SSGs other than Astro know astro code, so you end up having to tag it as plain old JavaScript. And none of them, so far, seem to recognize the Nunjucks templating language often used in Eleventy, so I tend to end up tagging it as Jinja2 or Twig↩︎

  3. Update from the future: Finally, in March, 2023, I was able to start using Vercel Edge Functions — or, to be more precise, Vercel Edge Middleware — with my very-non-Next.js projects. ↩︎