How I made this page

Introduction

Anyone who has ever dabbled in HTML is probably aware that to make even a basic page you need a lot of boilerplate: The tags are lengthy and getting even just the header set up requires multiple lines of code. Engineers, however, are extremely lazy: If you present them with a problem that is mere busy work, they will rather invest multiple hours into an optimized and streamlined process instead of taking slightly longer to write the boilerplate. All this was a roundabout way saying that I wanted to find a nice and easy way to concentrate on actually writing for my blog, and not having to create so much boilerplate.

Making the writing process sufferable

If you've ever been to a GitHub or GitLab repository, or managed a few yourself, you might have noticed those mysterious README.md files. the md stands for Markdown, a markup language designed to quickly format texts without all the boilerplate from HTML. Its extreme simplicity allows for fast typing, however, you are quite restricted in styling your files. For example, you can't make index tabs, put background images into your pages or stylize the text by exchanging fonts mid text or coloring it. It is good enough for READMEs or other texts that don't require a lot of stylization.

Markdown is in fact the main language in which these pages are written, however, it is not HTML and thus (most likely) not readable by your web browser, and I also lose a lot of the amenities aforementioned. If I wanted to create a good looking blog though, I needed to find some way to turn my Markdown into HTML.

Turning Markdown into Markup

As standards go, Markdown is extremely small, featuring only a few formatting options. This includes #, ## and ### for headers, **bold**, *italics* and ~~strike through~~ among other things. I could have written my own script turning Markdown into HTML, but again, engineers are lazy. Lucky for me, there was a tool: It's called markdown. It takes as an input a Markdown text and prints out the equivalent HTML code. That's the main body taken care of, but it doesn't generate the rest of the boilerplate html code like the header, or the <body> and <html> tags. Sadly, neither Markdown the language nor markdown the tool had any options for including one file in another. In the spirit of eliminating boilerplate though, I was determined.

Eliminating the boilerplate

Fellow C programmers might know about the glorious C Preprocessor. Its central role is in eliminating a lot of boilerplate by declaring functions that another file might want to use. The best thing about it is that it doesn't really care what the actual contents of the source files are. It only cares about preprocessor directives placed inside that file. The plan was to include templates by using the appropriate directive and passing it through the preprocessor, however, there were always some preceding lines of the form # n "some text".... Aside from just being weird to see, in Markdown, a # text is a Level 1 heading, not good.

So I was faced with a choice: Sanitize the output, meaning I get rid of any erroneous lines, or I could write my own preprocessor. While the latter would saved me from this awful rabbit hole, the former one sounded more fun, and I plain liked the idea of using the C preprocessor in cursed ways nobody intended to. It would also allow me to do more advanced things, like replacing any occurrence of a word with a Wikipedia link to that word, or a glossary link. Sadly, using the C preprocessor had proven to be overkill. The only use I could find was using it in conjunction with a macro to get the title of the page into the header of the HTML code.

Putting it all together

Finally, to put all the pieces together, I use the tool Make from the Free Software Foundation, Inc. to splice together the head, body and foot, construct each webpage from a few boilerplate files and the Markdown file that contains the actual article, and then output a single HTML file with everything configured correctly. Best of all, if anything changes about my setup it automatically rebuilds any pages that need to be built.

Make was originally designed to have easily expandable code projects, by defining so called Targets that you could tell Make to run, which means it looks at the source code of the target and all its dependencies, and if any changes were made since the last time that target was built, it builds the file again. Long story short: It lets software developers focus on just creating their software and not have to worry about how to compile it into a product. And if you think about it, this website here is the same right? All I want to worry about is just making a website, but there is so much boilerplate to deal with, so I just use Make to deal with that for me. But that comfort came with a price...

Something no man was meant to see

By far the most cursed line of code is in this Makefile for the project. That line creates the navigation bar at the top of the website. it looks something like this:
1. echo
2. $(foreach navgroup,$(NAV_FOLDERS),
3. "<div class="dropdown">
4. <button class="dropbtn">$(shell head pages/$(navgroup)/.page-info -n 1)</button>
5. <div class="dropdown-content">$(foreach file,$(shell find pages/$(navgroup) -name "*.md"),
6. <a href=\"https://keheck.github.io/$(navgroup)/$(notdir $(basename $(file)))\">$(shell head -n 1 $(file))</a>)
7. </div></div>")
8. >> $(BOILERPLATE_DIR)/navbar.html
The line has been broken up into several for your convenience, and line numbers have been added to the front to reference down below in the explanation. In reality, all this is one line. Don't worry, I will go over what each line does one by one:

  1. echo: All it does is output the result of whatever commands follow it, and using a structure seen in 8.
  2. $(foreach navgroup,$(NAV_FOLDERS),<something>): Here, we iterate, or loop, over every entry navgroup in a list called NAV_FOLDERS, and do <something> with them (that something is what happens between 3. and 7.). Each navgroup here represents a category of articles, like "This Page", which the article you're reading right now is a part of.
  3. <div class="dropdown">: Here we create a container that will hold all the relevant elements for the category. This is a so called "opening tag", which is part of HTML and represents a single element. Elements can contain other elements, so we also need to mark the end of this container. That we do with the second </div> in 7.
  4. <button class="dropbtn">$(shell head pages/$(navgroup)/.page-info -n 1)</button>: This part creates a button element that will be used by the user to open the menu by overing over it with their cursor. The $(shell head pages/$(navgroup)/.page-info -n 1) command tells Make (The utility used to build the webpages) to interpret the rest of the parentheses as a shell command (aka a terminal command), and replace it with whatever got reported back by that command. Here, the head command, with this specific configuration, returns the first line of the file it's given, here it's a .page-info file (a file format I made up) located in the navgroup directory under pages. It simply contains the name of the current category.
  5. <div class="dropdown-content">$(foreach file,$(shell find pages/$(navgroup) -name "*.md"),<something>): Here we open another group of elements by looping over this time the files contained in the pages/\<navgroup\> subdirectory, and doing <something> with them. That something is located in 6. The end of this container is the first </div> in 7. You'll notice that we're using shell again, this time to find every file in the current directory we're looking at ending in .md, which are the Markdown files we want to turn into our webpages.
  6. <a href=\"https://keheck.github.io/$(navgroup)/$(notdir $(basename $(file)))\">$(shell head -n 1 $(file))</a>): Finally, we create a hyperlink for each file we're looking at, by taking its navgroup and sticking the name of the file after that. Since the file variable we're using to loop over the files still has the extension and the path to that file, we use basename and notdir, which removes the file extension and the directory path respectively, leaving only the pure file name. Finally, we get the first line of the file, which is just the title of the article, and use that as the text to display to the user, because it just makes sense, unlike anything else outlined here.
  7. </div></div>: This just closes all the open containers (the one holding the) links and the one containing the entire navbar category
  8. >> $(BOILERPLATE_DIR)/navbar.html: Finally, after all this madness, we tell our echo command to append everything that resulted from this insanity into the navbar file, so that we may include it into every article for us.

To those asking the question: Yes, this is absolutely horrendous. Yes, I could have made it easier and no, this is not what you're dealing with when you write Makefiles. As I said, GNU Make was built to make software projects easier. That means its only job is to call other tools that actually build the files. But here I'm using Make as the tool that builds the pages, so it's no wonder that it ends up cursed.

Conclusion

And that is the way I created this website. To the layperson, it may seem quite complex, and yeah I suppose it kind of is, especially when reading it from someone like me. Who knows, maybe some day I'll create some more pages that go more in depth about a specific topic mentioned here. But you can expect some other, more serious topics as well, there are some ideas I would like to play around with. See this as a kind of experiment to my... carreer? as a software blogger. Until next time...

Thank you for reading!