The JAMstack has piqued my interest. Not because it's fast, secure, or totally hot right now. But because it got me thinking, "We could run that on GitLab".
These thoughts cross my mind a lot. GitLab is such a versatile tool that it has endless applications. I use GitLab to run a conference, keep track of my wedding plans, and even help create GitLab. It's almost definitely a case of Maslow's Hammer where, "…everything looks like a nail". But who cares, I'm eyeing up a JAMstack shaped nail right now, with my GitLab branded hammer in hand.
A modern architecture —
The key part here is "served without web servers". JAMstack sites are static. They do all the compiling at build time, not at runtime. It's often confused with isomorphic websites built with Next, Nuxt, or similar. But the concept is entirely different. We're not rendering pages on the server, then hydrating them once they get to the frontend. We're building the pages once (at build time) then serving up those static pages at runtime. This makes for a blazing fast website with little to no server costs.
If you hadn't already guessed, the project I created on the JAMstack is the blog you're reading right now. It looks and behaves in much the same way that it did previously, it's just a lot faster, and easier to update.
The first thing I needed to do was pick a static site generator. I had a look at Gatsby and Eleventy, but ultimately settled on Gridsome. It's based on Vue.js and integrates with GraphQL, which is something I've been wanting to look into for a while. This seemed like the perfect excuse.
With the site generator chosen, I needed to work out where to store my data. When this site was running on Jekyll, I used markdown files stored in the repo. Whilst this worked well enough, I wanted a little more flexibility. Something that required a CMS. I chose Sanity based on a recommendation from Jamie Bradley. Sanity is a headless CMS with a GraphQL output layer, a perfect fit for my needs.
With those two chosen, I had everything I needed to get started developing locally. I moved over all my old posts to Sanity, which was a lot harder than I expected. I wish there was an easy way to convert markdown to Sanity blocks (Sanity's rich text editor) but I had to do it all manually. I guess the one upside to my low output on this blog is that there weren't too many posts to migrate.
I already had a lot of the components of my blog written in Vue from when I tried to move it over to VuePress. A Vue based static site generator that ended out being unfit for purpose. I copied these components over, tweaked them to fit, and added my GraphQL layer. Then I was good to go.
Once I was ready to deploy, I copied the example
.gitlab-ci file from Gridsome's documentation and pushed the site to GitLab. This triggered the build process on GitLab's CI pipeline and built out the static site to GitLab pages. After two painless DNS additions, I had my domain hooked up to GitLab pages with automatic SSL certs.
With very little set up—which consisted more of copy/pasting than any real hard work—I had my blog up-and-running. When I pushed a change to the
master branch, GitLab's CI pipeline would trigger a build, regenerate all the static files, and re-deploy my website. This was the boring solution. The smallest possible change I could make to get my blog migrated to the JAMstack with GitLab.
The boring solution was great, but are were a few small tweaks I could do make to make the process a little nicer.
Because my content was in Sanity, GitLab wasn't aware of any changes I made to it. The content publised on the website would be the content from Sanity at the time of the most recent build. I could manually trigger the pipeline after I published a change to pull in the latest data, but I'm far too lazy for that. I needed to automate this. Thankfully, GitLab allows you to create pipeline triggers that can listen to a webhook and start a pipeline every time it's used. On the Sanity side of things, you can call that webhook every time you publish a post. Now, whenever I publish a post, it triggers the pipeline then the website is re-built and deployed. It's not as instant as a usual CMS set up but it only takes a minute or so, and it only has to happen once.
I'm also a bit of a stickler for performance. The boring solution was fast, but still fell down on a few points. I've fixed them all now and it's blazing fast. I'll save the story of how I did that for another day. To summarise, I minify, lazy-load, pre-fetch, and cache all of the things. I also added in a service worker for good measure and that sweet offline first experience.
Whilst this site has no need for serverless functions (Functions as a Service, FaaS), they are a large part of the JAMstack. Static websites are great for sites with little user interaction beyond reading information. But what if your site needed to be more complex? What if you needed to allow users to log in, make purchases, or post content? This is where serverless functions come in. They're API endpoints that (when called) spin up a VM, run some code, then disappear again until they're needed next time. There are a lot of different platforms that offer this service. AWS Lambda is the biggest right now, but there's also Azure Functions, Google Cloud Functions, and a load of other providers that offer functions as a service. All of these integrate nicely with GitLab Serverless should the need arise.
If you want a more in-depth look at how FaaS can be used with the JAMstack, take a look at this section of, "Are you being servered" by Phil Hawksworth. Then go back to the beginning and watch the entire talk. It's a great example of what you can do with the JAMstack.
If you want to have a go at building your own JAMstack website on GitLab, I've made this project completely public. You can look at the code, clone the project yourself, and even watch my pipelines. If GitLab's not your thing, head on over to staticgen.com, pick a generator, and get your site up and running in seconds on Netlify.