Jon Ellis

The musings of an "engineer"

Jon Ellis

Website Rewrite 2020

The old website

The previous website was a simple, static, and bootstrap-based website that I quickly threw together on an aeroplane on the way to and probably from the Velocity Europe 2014 conference.

I still quite like the design of the old website (hence keeping the general design for the rewrite). I should probably say that I am by no means a designer, but I wanted a website that was a little different to a completely minimalist design.

The intention was that simple pages would be akin to a business card as they're not going to have all that much content on them anyway, then the blog pages can expand so that more space for content is available. I wanted to keep everything in a single page app to improve the responsiveness and to make page transitions less jarring as they could be achieved by some sort of smooth transition.

The old website worked very well on mobile devices with some simple media queries to change how things were rendered.

I always had big plans for the old website. I wanted the blog writing to be as simple as possible, so Markdown seemed an easy method for minimal formatting. I'm not a fan of had-writing boring HTML documents. Of course, you can't just serve markdown documents as web pages - well I suppose you can as they are merely plain text documents but no one seems to do that - so I would need a CI step to build them. The plan was to also create "API" documents for the frontend to fetch when the user navigated around the website.

For some reason - at the time - I liked the idea of a minimalist menu with nice icons instead of words for each item to keep the size to a minimum. Unfortunately this fell straight into the mystery meat trap. I've learned my lesson. I'm sorry. Perhaps it would have been better if I'd been able to design my own icons rather than stick with the few that could be shoe-horned in from Bootstrap.

Speaking of bootstrap, it had somewhat irked me that I included the entirety of the bootstrap framework pretty much just for a some minimal layout classes, loading about 112KB of CSS. According to Google PageSpeed Insights, I only actually used 4KB of that!

The old website did not work much at all if JavaScript was not available or disabled. I wonder how many people were not able to read my single blog post because of that. My guess is zero, but that doesn't mean that it shouldn't be improved with the new revision.

The old website did have a nice CI setup to put changes live. The old website was a simple Git repository hosted on my Gitea instance, and my Drone CI instance would be invoked when a new revision was pushed to the repository. The whole pipeline took about 40 seconds from pushing to the changes being put on the server.

I think the main failing of the old website was that there was always too far away from what I wanted it to be, but making it what I wanted it to be would take too much time. Time I didn't have, especially after having 2 children.

Old website good points

  • Static website
  • Simple
  • General design - well, I'm sure it wouldn't win any awards, but I like it...
  • Responsive - works well on mobile devices
  • Easy and quick to promote new code to the server

Old website bad points

  • Bootstrap, and not using much of it
  • Sections are not visible on different URLs
  • Did not work well if JavaScript was disabled
  • Did not fulfil the plans I had for it without significant work
  • Mystery meat menu
  • Very little content
  • Google fonts directly from Google

The new website

This re-write was triggered after I wrote my first React app. I wrote a custom alert dashboard for Sensu Go, which is the monitoring platform we use at iWeb. Hopefully this is something I can write about soon. The experience was generally positive and quite intuitive to build a reasonably simple web app. At some point I wondered whether someone had already created method to build static react apps, which would not need javascript to load the pages that it built. This might let me build the website that I had envisioned, but failed to build six years ago.

It turns out that there was a project that may well do what I wanted! Gatsby is a web framework built built around react that can (with some plugins) render markdown documents to pages, and create "API" documents which can be used to load in subsequent pages, and many other niceties besides like Sass compilation and image processing.

To be absolutely frank, Gatsby is massively above what a trivial little website like mine requires. But when given the opportunity to over engineer something - why wouldn't you. Of course, over engineering is most fun when you don't have to justify it to your client or boss. If nothing else, it would be an interesting learning experience to write something else in a React-like way.

Gatsby good points

There are a huge number of features for achieving various pieces of functionality:

  • gatsby-image, which will automatically resize your images to a few different sizes and places them in a picture element containing the various size images for the browser to pick from based on the browser size. This even handles nice little features like serving a 20x20px data URL image as a placeholder, then having the full image fade in when it has been downloaded to the browser.

  • Gatsby GraphQL allows you to access your website data though GraphQL, this can then be queried by your pages and components. The database is not needed when the website is built, but it is used when building your website to static files.

  • Sass - simply install the gatsby-plugin-sass npm package, add it to your gatsby config file and include your sass/scss files.

  • gatsby-plugin-react-svg allows you to import SVG files and import them like other components.

  • Markdown pages can be easily added as a source of pages instead of writing full HTML pages for each page. The GraphQL entries these create can then be queried to generate additional pages. I didn't get on all that well with this plugin. More on that later.

  • MDX is "markdown for the component era". It allows JSX to be written in markdown files. This was what I settled on after the issues I had with Markdown pages. It did not require the extra code to fetch and include pages that was required for the Markdown equivalent, and it also supported more complex pages as I could simply include a standard component in the page.

  • gatsby-remark-prismjs adds syntax highlighting to code blocks in markdown documents.

Gatsby bad points

First, I should say that I'm hesitant to call these out as actual bad points. Because this framework is new to me I've not had opportunity to learn of it's warts yet. There were some things that I found more complicated than I'd have hoped, and some framework decisions that did not fit what I had planned for my particular use cases.

I would not be surprised if a number of these can be solved quite easily for someone who is more familiar with the Gatsby framework. In fact, this list has been written a couple of times as I've found solutions to some of the problems I encountered.

Layout

The first issue my website design had was that each page change would remove the whole page including the layout from the DOM, then replace it with the next page. While this seems to have been done for very good reasons for Gatsby version 2, it interfered with my plans to transition nicely between pages by altering the content rather than replacing the entire page.

Luckily, the gatsby-plugin-layout plugin reimplements the old behaviour.

While this seems straight forward now, it took me two attempts to get this to work without causing the website to load itself within it's layout - some sort of (luckily limited) page-inception.

Page metadata

By metadata, I don't mean the meta tags added to the HTML document. When using Markdown, you are able to specify a YAML document of metadata at the top of the Markdown file. For markdown, this includes the source of the page path, but you can insert whatever metadata you want for your requirements. For my Website, I planned to use this for the page size and background image.

These metadata items are picked up by Gatsby and entered into the GraphQL database. By adding configuration to the gatsby-node.js file, you can trigger pages to be loaded from GraphQL and pages created from them. There was a little edge case that bugged me when creating new markdown files where the development bundle would crash because the code that created them would try to create a page that did not have a path. This was fixed with this little addition before passing the page to the createPage function so that the page would be ignored until it was assigned a path:

gatsby-node.js
result.data.allMarkdownRemark.edges.forEach(({ node }) => {
  if (!node.frontmatter.path) {
    return
  }

  createPage({
    path: node.frontmatter.path,
    component: blogPostTemplate,
    context: {},
  })
})

Annoyingly, I didn't find a way to add the metadata to standard Javascript pages. Since migrating to MDX documents, I found gatsby-transformer-javascript-frontmatter which should do this, though I have a separate problem where this doesn't seem to work for the 404 page.

MDX is annoyingly a tiny bit different with it's meta data in that with Markdown the path is specified in the metadata, however, with MDX, the path is derived from the path to the .mdx file. To work around this (so that I didn't need to have structured blog posts in directories) I overwrote the page path with the value from the metadata in the gatsby-node.js file with a little code:

gatsby-node.js
exports.onCreatePage = ({ page, actions }) => {
  const { createPage, deletePage } = actions

  let frontmatter = {}

  if (page.context && page.context.frontmatter) {
    frontmatter = page.context.frontmatter
  }

  if (!frontmatter.path) {
    return
  }

  if (page.path === frontmatter.path) {
    return
  }

  deletePage(page)

  createPage({
    ...page,
    path: frontmatter.path
  })
}

Dependencies

While I probably shouldn't be surprised that a modern (especially JavaScript-based) framework has a lot of dependencies, I was not prepared for the node_modules directory containing 580MB of them! I suppose this isn't all that bad as this is only the development dependencies, including the development bundle and GraphiQL GraphQL browser. 217MB of that is Jimp, the JavaScript Image Manipulation Program.

Website Comparison

As I continue to avoid putting this new website live by finding new things to add to it (different page backgrounds, better image support from MDX documents, syntax highlighted code snippets, typography, styling tweaks, etc) I thought I'd take a quick look at the website size since page bloat is a problem the web faces.

File TypeOld WebsiteNew Website
HTML17KB28KB
CSS120KB0KB
JavaScript84KB359KB
Fonts50KB39KB
Images1438MB390KB
Total1709KB1001KB

As it turns out, the CSS is inlined into the HTML document itself, so no separate requests are needed to download the 8KB of CSS that the site uses. I wonder if that is still done if I had a significant amount of CSS.

Amazingly this new website goes against the trend of ever increasing bloat! However, the same could have been achieved by simply optimising the single large image that the old website used! Now all I need to do is get into the habit of writing blog posts. Wish me luck!