exsertus.com
The ramblings of an IT Professional, Long Distance Runner, Creative, and Maker of Stuff.
Site Rebuild 2020
Jamstack - The next iteration
15th November 2020
 7 min read
Categoriessoftware

Contents


There's a bit of trend that I rebuild my site around this time of year, not sure why. The most recent incarnation was my first foray into React having previously migrated from Wordpress (yuk).

The React based architecture is hosted on AWS in S3+Cloudfront and represented a big evolution towards a more serverless architecture and frankly, cheaper run costs.

The core function of my site is that its largely a static collection of blog posts and some social integration with Flickr and Youtube, plus some fairly lightweight data functionality for tunes and run events. For this, React was (and still is) largely ideal - its all lightweight rendering/construction that works well with client side JS rather than expensive compute intensive server side rendering like PHP/Wordpress.

The blog functionality was based around markdown, and I've got used to writing in markdown language and publishing. The markdown was rendered at runtime which gave me a few issues with posting links on social media etc, and with SEO/crawling.

The tech world never stands still, and this problem has been eloquently tackled with Jamstack. Its a further evolution in the web app / web site architectures that moves away from heavy server side rendering and hosting, to lighter client side rendering and pre-rendering (ie render at build time rathe than runtime)


Enter; GatsbyJS

I'd been aware of GatsbyJS for a while and had experimented earlier on in the year, but didn't have the motivation to take it further.

For the unacquainted, Gatsby is a framework that sits atop of React, and allows you to design and author pages in much the same way as you'd do with React - ie create components, assemble components into pages/views - all the good Atomic design principles.

The boon is that Gatsby can pre-render the pages to flat HTML at build time - this makes them easier to set meta tags and clearly faster.

For the dynamic functionality this wasn't a great benefit, but for blogs, it was a no-brainer as it meant fast load times, proper meta tagging with OG, twitter etc and much better support for SEO.

Shot from Facebooks sharing developer tool, showing the OG tags
Shot from Facebooks sharing developer tool, showing the OG tags

From a content editing workflow point of view, the flow is largely unchanged:

  • Author the content in markdown and run a local instance on my laptop during authoring to check formatting etc.
  • Once ready to publish, build the site and push the contents into S3

The change is subtle; the pure React approach, to develop locally:

npm run start

To publish:

npm run build aws s3 sync build s3://$SITE_BUCKET --delete --quiet aws cloudfront create-invalidation --distribution-id $CLOUDFRONT --paths '/*'

The new Gatsby way, to dev local:

gatsby clean && gatsby develop

Then to build and push to S3:

gatsby clean && gatsby build aws s3 sync build s3://$SITE_BUCKET --delete --quiet aws cloudfront create-invalidation --distribution-id $CLOUDFRONT --paths '/*'

Plugins & GraphQL

Gatsby is all about plugins (and there is a rich collection of these) and GraphQL. The later takes a bit of getting used to and I'd highly recommend this article on it.

Most of the plugins I've used work with the gatsby-transformer-remark plugin, and control how you render markdown into HTML, eg code snippets, handling images and embedded YouTube videos etc.


Architecture

The infrastructure architecture and build/pipeline approach remain unchanged, as does the core JS based ecosystem. The subtle change is simply in the libraries used.

Infrastructure Architecture

The site is based around AWS hosting via S3+Cloudfront - ie static content hosting. The resources are managed via Terraform.

The hosting architecture is broadly the same as the IoT WebUI, with the site content held in an S3 bucket, and served through Cloudfront.

IoT Web UI hosting
IoT Web UI hosting

One gotcha was the default behaviour of Cloudfront, which handles index.html in the root folder only, hence www.site.com -> www.site.com/index.html, but not in subfolders, so www.site.com/page1 -> www.site.com/page1/index.html doesn't work.

To resolve this we use Lambda@Edge to handle the pre-pend. Good article on this posted by Ximedes

The result is a very simple Lambda@Edge function the fires on the Origin Request event from CloudFront:

'use strict'; exports.handler = (event, context, callback) => { console.log(event) const request = event.Records[0].cf.request; const uri = request.uri; if (uri.endsWith('/')) { request.uri += 'index.html'; } else if (!uri.includes('.')) { request.uri += '/index.html'; } callback(null, request); };

Typically I use Serverless framework for managing the deployment of Lambda functions, however, its a bit of a faff with Lambda@Edge and tries to create the Cloudfront distribution, rather than append to an existing one. This is something I'll look at later, but in the interim I've just manually deployed the Lambda function (shudder).

Application Architecture

The application is based around the following core technologies:

  • React (16.12)
  • Gatsby (2.24)
  • Bootstrap (4.5)

The quite a few plugins to make things easier, including:

  • Helmet (for meta tagging)
  • Moment for date formatting
  • Axios for API calls
  • Font Awesome for icons
  • Google maps for React, for the running map.
  • ABCJS for the tune database manuscript rendering.

The structure of the site its build around components; blog posts, blog lists, youtube lists, scaffolding etc, which are assembled into pages.


Images

Another great find with Gatsby is how it handles images and how you can manipulate them with the image sharp renderer. In short you can chuck in hi-res images into your images folder, reference them in the markdown and control breakpoint sizing and aspect ratios so that images are resized/baked during build. It means the right image resolution is then served on page, so no client resizing. Again, resulting in blazing fast page load times.


MDX

So this a new one on me - MDX is to Markdown what JSX is to HTML/Javascript. It allows you to write markdown content, and pepper that content with JSX or React components. At first, it sounds like a bit of a disaster as you are mixing structure and content. But in reality it just extends the principles of React's atomic design and component architecture.

I've used MDX and regular markdown all over the site, and particularly:

  • MDX - For static pages like Home, Running, Software, Hardware, etc
  • "Regular" markdown - For blog posts

The simple reason behind this is that blog posts are designed to be simple - just blog content, no distractions. Whereas the other pages are typically a meld of blogs lists, youtube links and content.

Here's an example of MDX in action with the photography page. Note the mixture of regular markdown content, and the various JSX components for Flickr, Bloglists and YouTube video lists.

import Layout from "../components/layout" import BlogList from "../components/bloglist" import YouTubePlaylist from "../components/youtube-playlist" import FlickrCarousel from "../components/flickr-carousel" <Layout logo="camera-retro" title="Photography" description="Photography projects"> I take pictures of stuff, used to do loads, now it tends to be more holiday snaps or GoPro running footage. --- <FlickrCarousel title="Flickr"/> --- <BlogList category="photography" full="true" title="Photography posts"/> --- <YouTubePlaylist playlistId="PLvBy2iVVlTu2gEuSvpqIIN0Hi_U4Bv-3t" full="true" title="YouTube"/> </Layout>

Summary

I like it!. it probably took around 3-4 days to affect the rebuild, with a few additional cosmetic tweaks and enhancements along the way whilst the "bonnet was open".

For websites rather than web applications, its a no-brainer choice, and I see more and more commercial sites now starting to leverage the Jamstack architecture. But even for web-apps, I can see a more blended micro-frontend based architecture that uses both regular React and Gatsby.

The ponderable though is around the future of CMS and particularly how this would fit into a corporate scenario where content editors are used to the likes of Wordpress and Drupal. If we can change that, we'd save a lot of trees by removing huge amounts of compute power from data centers running traditional server side hosting.


Links & Further Reading


Blogs