Static Generators versus Databases

For a simple blog, having a database backend is too much overhead for little to no gain.

First, your hosting will be more expensive as you'll require not only something to respond to web requests but also a database server that stores your blog posts. Second, because your posts live in your database, you will need backups configured. Otherwise, you run the risk of losing everything you've written in the event of some unrecoverable failure. Lastly, if you are successful and traffic increases, you have to start dealing with scale issues like the sizing of your database, slow queries, and caching.

Generally, with a static generator, your posts will live as markdown files in your repository, side-by-side with the static generator code. That means your posts can be version-controlled and therefore backed up. The generator builds your site before or at deployment. By only having to serve up static web assets, you'll only require a simple hosting setup. You could even copy to something like Amazon S3. Finally, with a statically generated site, you never have to worry about scale (not that most blogs do), but it is also super cheap because of that.

Gridsome

There are plenty of popular static generators, but being a fan of Vue, I've decided to go with Gridsome. One cool feature is that I can make Vue components to build my static site. It's very pluggable and easy to get going. It also has an excellent local development/drafting experience. I can write a markdown post and view it rendered in real-time.

It's extensible as well.

For example, I like adding images to my posts from Unsplash. Instead of downloading the image and cropping it to the two sizes I want and then storing it in my repo, I wrote a little utility function that takes an Unsplash image id and calls their API for the different sizes I want. More on what this looks like in a minute.

Tailwind CSS

I was a Bootstrap fan for a long time, but I've become a Tailwind CSS convert more recently. You can do so much styling without writing any custom CSS. Some people argue that you are just writing CSS with all the utility classes in the HTML, and at first, that is how I saw it.

However, I realized that by only using the utility classes and resisting custom CSS for only the rare occasion, you have the guardrails in place that help you keep consistency in font sizes, padding, and margin. It is common when writing custom CSS to end up with many subtle differences, which can lead to style drift that is hard to see unless you are looking for it specifically.

Another aspect that I love about Tailwind CSS is how it leverages the PostCSS plugin, purgecss, which cuts out any classes you are not using from the built CSS.

Getting Gridsome and Tailwind CSS to Work Together

Out of the box, getting these two play together was a bit tricky. It comes down to issues around PostCSS versions. The latest (at the time of this writing) version for PostCSS is v8. Out of the box, Tailwind CSS works with v8. Gridsome won't work with [anything past v7 yet].

There is a plugin, but I had trouble getting it to work. I followed the manual steps and got things working just fine with some modifications to those instructions:

yarn add @tailwindcss/postcss7-compat yarn add @fullhuman/postcss-purgecss=3.0.0 yarn add @postcss=^7

My resulting package.json looks like (snipped for relevance):

  "dependencies": {
    "@fullhuman/postcss-purgecss": "3.0.0",
    "@tailwindcss/postcss7-compat": "^2.1.4",
    "postcss": "^7",
    "tailwindcss": "npm:@tailwindcss/postcss7-compat"
  },

With a tailwind.config.jsthat looks like this (don’t have a separate purgecss.config.js) like the instructions say:

module.exports = {
  purge: {
    enabled: process.env.NODE_ENV === 'production',
    content: [
      './src/**/*.vue',
      './src/**/*.js',
      './src/**/*.jsx',
      './src/**/*.pug',
      './src/**/*.html',
      './src/**/*.md',
      './posts/*.md',
    ],
  },
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}

The purging results in my site having a gzipped CSS payload of around 3KB. The full Tailwind CSS without the purge totals at about 290KB. Quite a savings!

Unsplash Extension

I like using Unsplash for adding pretty pictures to my posts. I used to go to Unsplash, download an image, resize it for the different sizes I needed, and the store somewhere that I can reference in an image tag. All that was tedious to do. When I saw Unsplash had an API, I decided to automate this process, so I only needed to include an Unsplash ID in my post meta section.

Here is how it works. I find the picture I want on Unsplash and then put the ID (copy from the URL) into my posts meta section like so:

---
title: How to Blog with Gridsome, Tailwind CSS, and Netlify
slug: how-to-blog-gridsome-tailwind-netlify
date: 2021-09-05
author: Patrick Altman
section: Technical
markup: markdown
description: "For a simple blog, having a database backend is too much overhead for little to no gain."
unsplashId: jLwVAUtLOAQ
featured: true
---

I then have a module, unsplash.js, that exports an imageUrl function:

const imageUrl = (post, width = 900, height = 400) => {
  if (post.unsplashId) {
    return `https://source.unsplash.com/${post.unsplashId}/${width}x${height}/`;
  } else if (post.image) {
    return post.image;
  }
  return null;
};

export default imageUrl;

I import this function into anywhere I have a post and want to display an image and use it within a computed property:

    // Post.vue
    computed: {
      imageUrl() {
        return imageUrl(this.$page.post);
      },
    },

or

    // FeaturedPost.vue
    computed: {
      imageUrl() {
        return imageUrl(this.post, 300, 200);
      },
    },

Now I can use the <g-image> tag that comes with Gridsome:

  <g-image :src="imageUrl" class="w-full" />

Deploying your Gridsome Site

Deployments couldn't be easier with Netlify. You create a new site from your Github repo. After the typical OAuth exchange, you have a site, and it will automatically do the right thing most of the time. You can then tweak things like adding your custom domain, control what branches get deployed, and how "deploy previews" work (you can get auto deploys of your PRs if you want to test an idea out).

It's been a while since I set mine up, but I think the only thing I customized was adding my domain and pinning the node version it uses to 14 by setting NODE_VERSION to 14 under Environment Variables section of my site's settings.