Build Your Own Stuff: Part 3

In this part of the Build Your Own Stuff series, we're discussing two changes I've made to the static site generator: improvements to the <title> tag and better internal links.

Both of these are pretty basic website features, but building your own stuff means implementing even the most basic features. Neither of these were particularly time consuming, although the internal linking did require me to refactor some code.

Webpage <title> tag

The other day, I sent a few friends articles to review and I noticed something: the preview that is rendered by the Messages app only had to the site name in it. The article title was completely missing. I dug around and discovered that the generated <title> tag only had the site name within it.

The HTML <title> tag is what populates the text at the top of a browser window or in a browser tab. It's also used for generated previews, like the ones in Messages. In the first build of the static site generator, I included functionality to generate the <title> tag of each page from the article title. However, when I built the Article type, I didn't set the necessary struct field. Oops. As a result the <title> tag only contained the site name. The fix was a two line code change.

That would have been the end of it, except when I reviewed the rendered HTML the ordering of the site name and article title felt off. I had it ordered as "site name - article name". I did some research to figure out if this was a weird ordering or if I just hadn't paid attention to it before. In that research I found an article from WordPress Go and a Stack Overflow question that provided a clear answer: I had them backward. Instead of having the title "site name - article title", I should have "article title - site name". This fix was one line. The research to figure out how to do this correctly took more time than the code changes.

Internal Links

Another outstanding task that was increasingly annoying me was the lack of back links. You could arrive on the landing page for one of the publications, but once you clicked into an article there was no link on the page to go back to the landing page. While the browser back button handles this if you've navigated from the landing page, that won't work if someone's sent you a direct link to an article.

It's common for a website's name or logo to be a link back to the main page. I hadn’t done this in the original prototypes of the static websites, and I failed to add it when I built the static site generator. I also didn’t have any links leading back to the publishing website from any of the other websites, or back to the press website from either The Shaded Garden or Shaded Nuance. While linking back to the press website from either of the publications isn’t all that important, I did want to have at least one link that led back to the publishing website from all of the others. I decided to add this link in the footer of each page.

To do this I needed to update the code that handled rendering the header and footer of each webpage. The original code used static HTML strings, which the page builder would slot into the correct place. So all I needed to do was make this static string dynamic. Simple, right? Well, this change required extra plumbing because I didn't have the necessary information to create the URLs in the place where the dynamic strings would be generated. The information I needed included the target environment (development, staging, production, etc...) and what URL should be used, which depended on both the environment and what website the given page was for.

In the core of the site generator, I have page building functions. Each time that I needed to add a new feature, I would add a parameter to each function. I did this when I added fragments1 and again when I added link rewriting.2 Back links would have originally required two addition parameters, however, I pulled some redundant code a layer up, resulting in a single parameter addition.

When I reviewed the changes, I noticed that the site names were now underlined. They were also colored purple, because that's the color the browser chose for visited links. I added some CSS rules to remove the color for visited links and the default text decoration. I want to improve the accessibility of this in the future, but I want to do more research before I choose an approach.

Refactoring

There are ways I’d like to refactor this code. For example, since each page function has an identical signature, I could define a type that could be used as a single parameter. Adding new fields to that type would be simpler than adding additional parameters to each function. However, I'm not a fan of dumpster types where you pile more and more things into them. They usually decrease the readability of the code. Additionally, this code will change significantly when I switch from using Markdown to HTML. So I’m going to hold off on any major refactoring until that is done. I might wind up throwing away the code that is already there or rewriting it from scratch. Some of the features that I’ve added, like fragments, are only necessarily because I’m using Markdown instead of HTML.

Future Improvements

With these small changes made, I've decided it's time to tackle a much bigger change: migrating from Markdown to HTML. This will greatly simplify the drafting and editing process and enable me to have as much custom HTML as is required for each article that I write.


  1. Fragments are a feature I developed to allow composing a single HTML document from several Markdown files. There is a main Markdown file that represents the rendered page, and within the Markdown metadata, fragments are specified. Each fragment has an associated template. The main page template along with some glue code fuses all of the parts together into the final page. There are other ways I could have done this, like parsing the Markdown into sections and then rendering each section with a different template or using HTML embedded within the Markdown, but this method felt the simplest at the time. ↩︎

  2. Both of these features are described in Part 2 of this series ↩︎