A Signal in the Static

Moving from Craft CMS to Hugo and Netlify

About a year ago I set out to rebuild my site, and being reared on PHP I opted to go for Craft CMS while it was in beta. I figured it’d be interesting to learn it while it was still in development, and maybe create my own plugins.

Haha. Jokes. I did not. I tried, though, but never really needed anything extra.

I was also using Laravel Forge to automatically deploy whenever I pushed any changes to the master branch. To this day it’s still a nice approach, but there’s a lot of moving parts. I have a repo, a server that needs to be looked after (like when I updated PHP and broke everything), a database that needs to be backed up, and a CMS with some plugins that need to be kept up to date. Granted, I could not have touched it after day 1 and it would still work just the same, but that’s not me. If it ain’t broke, go fix it.

That’s where the allure of a static site generator comes in. As far as the site goes, everything is in one place. Content lives in Markdown files which makes things pretty portable. I landed on using Hugo after seeing some recommendations for it, and in about a day I had my entire site copied over, including CSS and JS. To copy the content I took advantage of the Element API plugin for Craft to get a JSON object of all my posts. The config file for the plugin looked like this:

<?php

use craft\elements\Entry;
use craft\helpers\UrlHelper;

return [
  'endpoints' => [
    'posts.json' => [
      'elementType' => Entry::class,
      'criteria' => ['section' => 'posts'],
      'transformer' => function(Entry $entry) {
        return [
          'title' => $entry->title,
          'url' => $entry->url,
          'date_published' => $entry->postDate->format(\DateTime::ATOM),
          'slug' => $entry->slug,
          'body' => $entry->postContent,
          'categories' => $entry->categories->all()
        ];
      },
    ]
  ]
];

So when it hit https://my-site.com/posts.json it returned everything I needed. I saved this to a file to quickly generate markdown versions like so:

const posts = require('./data.json')
const fs = require('fs')

function buildCategory({ title }) {
  return `- ${title}`
}

function buildFrontMatter(post) {
  return `---
title: "${post.title.replace(/"/g, '\'')}"
date: ${post.date_published}
draft: false
categories: \n${post.categories.map(buildCategory).join(`\n`)}
---`
}

posts.data.forEach(post => {
  let content = `${buildFrontMatter(post)}\n${post.body}`

  fs.writeFile(`../path/to/final/content/posts/${post.slug}.md`, content, err => {
    if(err) {
      return console.log(err);
    }

    console.log("The file was saved!");
  });
})

I needed to run sudo node index.js on that as it needed to create files, but I didn’t have to touch the generated markdown files once they were in the right folder.

Once that was done, I skipped on over to Netlify and hooked it up. I needed to do some configuration before everything would work. Mainly this was down to my assets living in a theme which was in a subfolder. To let Netlify know about it, I had to create a new package.json in the root with a build command that did the following:

[build]
publish = "public"
command = "hugo --minify && npm run build"

Then the build command in my root package.json dug into the folder it needed and ran some more commands:

"scripts": {
  "build": "cd ./themes/nua && npm install && npm run production"
}

After that, it was smooth sailing. Limerick just won the All-Ireland senior hurling final so I’m gonna grab a beer. That makes two victories today. Cheers, agus Luimneach Abú!!!