How I Made This Blog
Oct 31st, 2019
The architecture of this blog was designed over one day, Thanksgiving on my reading week break.
Due to these conditions, I believe the design of this blog to be simplistic and lightweight.
Overview
Put simply, I write markdown files (some may have LaTeX) and store them in a directory server side.
I push my blog posts to a git repository that my Heroku website reads. From there, my server reboots and loads each MD filename into an
array.
Then, I use Showdown JS to parse the Markdown and convert it to HTML.
With the data all processed, I have a small REST API (A single app.get in Express.js). The API takes a GET request of the form /blog/x,
where x is the blog post number (or could be empty, which defaults to 0).
Because the blog posts are handled in a parsed array, x corresponds
to the HTML file that is loaded. I then pass the HTML data, as well as the sorted list of file names into a PUG template to load the current post.
if not 0 < x < # of blog posts, then I just send back the 404 page.
The nitty gritty: code samples
Reading the blog posts
postNames = [];
renderedPosts = [];
numPosts = 0;
converter = new sd.Converter();
fs.readdirSync(__dirname + '/blog/').forEach(file => {
postNames.push(file.substring(4));
numPosts += 1;
contents = fs.readFileSync(__dirname + '/blog/' + file, 'utf8');
renderedPosts.push(converter.makeHtml(contents));
});
postNames = postNames.reverse();
This code is placed at the beginning of my index.js file. Anybody who is familiar with web development may notice something stinky
about this code. That is that all of my I/O is synchronous and therefore blocking. While I agree in most cases the asynchronous
approach is the way to go, this code runs before my server accepts web connections, so it doesn't need to callback. Furthermore,
I need each file read to be synchronous so that the posts do not get entered out of order.
As well, you may notice that I only use a substring of the filename. That is because I keep my blogposts numbered so that the OS orders them,
but I don't want to display the numbers on the post list.
REST API
app.set('views', __dirname + '/views/');
app.set('view engine', 'pug');
app.get("/blog/*", (req, res) => {
if (req.originalUrl.substring(6) == "") {
postNum = 0;
}
else {
postNum = parseInt(req.originalUrl.substring(6), 10);
}
if (postNum > numPosts - 1 || postNum < 0 || isNaN(req.originalUrl.substring(6), 10)) {
res.sendFile(path.resolve(__dirname + '/pages/error.html'));
}
else {
res.render('blog',
{postTitle: postNames[numPosts], posts: postNames, numPosts: numPosts, post: renderedPosts[postNum]});
}
});
We initialize the PUG template engine outside of the API.
Within the GET response, we first check if a number is provided in the GET request. If it isn't, we default to 0.
Then, we check if our blog number is within the range of blog posts, and isn't NAN. If our blog number doesn't fit, we send the 404 page.
Finally, we filtered all the erroneous input, so we pass the blog information and specific post into our template, which is returned to our client.
PUG Template
doctype html
html(lang='en')
head
title=postTitle
link(rel="stylesheet", type="text/css", href="/pages/styles/blog.css")
link(href="https://fonts.googleapis.com/css?family=Raleway&display=swap", rel="stylesheet")
link(rel="stylesheet", href="https://use.typekit.net/hpc5yft.css")
body
div.sidebar
- var n = 0
each pTitle in posts
li
b
a(href="/blog/"+(numPosts - 1 - n++))=pTitle
div.blog
|!{post}
script(src="/views/mdToTeX.js")
script(async, src="//mathjax.rstudio.com/latest/MathJax.js?config=TeX-MML-AM_CHTML")
There isn't much to explain here. We have an iterable sidebar that displays the blog posts as links. We also display the Markdown rendered HTML
as the main page. We load in some scripts that I will explain below.
Bonus: Converting LaTeX to HTML from Markdown
I'm not displaying the code to solve this problem, as it's not mine and belongs to Yihui Xie, and I am linking his post here.
I wanted to implement LaTeX into my posts for whenever I needed to demonstrate something mathematical.
Yihui's code scans for inline LaTeX in my markdown (at this stage rendered as HTML), and processes it through MathJax.
Concluding remarks
This was a fun little implementation for me. I'm especially pleased with the outcome because the blog requires minimal upkeep from me.
All I need to do is write my posts, push to git, and my website is updated. My only bottleneck now is my commitment to writing blog posts!
You can see the full code for my website here.