How I rebuilt this site

I’m increasingly convinced that “niching down” is the best writing strategy, and that if you come across a technical post, it is helpful if it is truly in depth.

Although it’s been a few years since I used Hugo, when I came across Julia Evans’ post I bookmarked it:

Warning: this is a post about very boring yakshaving, probably only of interest to people who are trying to upgrade Hugo from a very old version to a new version. But what are blogs for if not documenting one’s very boring yakshaves from time to time?

So here is my contribution to the genre. For this site nickromney.com, I had been using Eleventy with the Eleventy Excellent theme by Lene Saile.

Looking at the package.json, I was still using version 1.6.0 which required Node version 16 or above, whereas the most recent version is 4.1.7, and uses Node above version 20

I had last seriously updated my blog in January 2024, and missed out on 3 sets of updates:

Approach

  • Get version 4.0 working locally
  • Create your own copy of the code
  • Apply customisations and port previous content
  • Deploy with a Cloudflare Pages CI/CD workflow

Get version 4.0 working locally

Note that this is a “belt and braces” approach, of first proving that the code works locally, before creating a copy of the code. If you are happy to take my word on it, you can skip to the next section

Set up the dependencies

You can see from my dotfiles the various tools I use. Especially as we might be hopping back and forth between Node versions 16 and 20, I am grateful for nvm - Node Version Manager

npm (Node Package Manager) is bundled with nvm. If we want a newer version, then

nvm install 20
nvm use 20
npm install -g npm@latest

Set up a local area in which to work

I like to create a ~/Developer directory, as on MacOS it gets a handy icon.

mkdir -p "$HOME/Developer"
cd "$HOME/Developer"

And then further I differentiate between personal and work.

mkdir -p personal
cd personal

Clone the repository

Clone the repository. On my cicdpipelines.com website, I go through how to clone with https or SSH. If you follow that post, you know that I much prefer SSH for working with Git, and being able to sign commits.

git clone [email protected]:madrilene/eleventy-excellent.git

Build locally

cd eleventy-excellent
npm install

If we look at the scripts block in package.json we see:

  "scripts": {
    "clean": "rimraf dist src/_includes/css src/_includes/scripts",
    "clean:og": "rimraf src/assets/og-images",
    "favicons": "node ./src/_config/setup/generate-favicons.js",
    "colors": "node ./src/_config/setup/create-colors.js",
    "screenshots": "node ./src/_config/setup/generate-screenshots.js",
    "dev:11ty": "cross-env ELEVENTY_ENV=development eleventy --serve",
    "build:11ty": "cross-env ELEVENTY_ENV=production eleventy",
    "start": "npm run dev:11ty",
    "build": "npm run clean && npm run build:11ty"
  },

So run:

npm run build

We should then see lots of output, concluding with

[11ty/eleventy-img] Processing ./src/assets/images/gallery/asturias-1.jpg (transform)
[11ty] Writing ./dist/blog/post-with-an-image/index.html from ./src/posts/2025/2025-01-09-post-with-image/post-with-image.md (njk)
[11ty/eleventy-img] 82 images optimized (13 cached)
[11ty] Copied 28 Wrote 67 files in 32.30 seconds (482.1ms each, v3.0.0)

At which point we can run:

npm run start

The output should conclude:

[11ty/eleventy-img] Processing ./dist/assets/og-images/what-is-tailwind-css-doing-here-preview.svg
[11ty] Watching…
[11ty] Server at http://localhost:8080/

If we open the link http://localhost:8080/ we should see the same site as the Eleventy Excellent Netlify site.

If we edit the file src/posts/2025/2025-01-11-v-4.md, we can update the description in line 3:

description: "My local edit. Time for a new version with a lot of breaking changes! Have fun everybody."

Then in the terminal output, we should see

[11ty] Watching…
[11ty] File changed: src/posts/2025/2025-01-11-v-4.md

And in the browser the homepage will have updated

In the terminal, use Ctrl+C to stop serving the local website

Create your own copy of the code

Now that we know the code works, we can create a copy of the code in our GitHub.

Use template

In this screenshot we can see that 88 people have already Forked the repository, and 467 have Starred it.

Lene (the author) has marked the repository as a template, so we can follow the GitHub instructions on creating a repository from a template

Create repository

I’ve chosen to create a private repository called nickromney-com-eleventy-excellent in my personal account.

Repeat the earlier steps of cloning, installation and building

Note as my repository is marked private, you will have to replace nickromney/nickromney-com-eleventy-excellent.git with your copy of the template.

cd ~/Developer/personal
git clone [email protected]:nickromney/nickromney-com-eleventy-excellent.git
cd nickromney-com-eleventy-excellent
npm install
npm run build
npm run start

Ctrl+C to exit out of serving locally

Apply customisations and port previous content

We are almost ready to follow the instructions in get started.

Create a short-lived feature branch

From several years of having to work this way professionally, even if I’m the only one working on a project, I default to creating a short-lived feature branch, and as far as possible, to using Conventional Commits

Create the branch with

git switch -c chore/20250424-initial-customisation

Edit the files mentioned, plus also src/_data/github.js

At the end of src/_data/meta.js, I turned off the GitHub link and Easter Egg confetti:

export const viewRepo = {
  // this is for the view/edit on github link. The value in the package.json will be pulled in.
  allow: false,
  infoText: 'View this page on GitHub'
};
export const easteregg = false;

At this point, if you run git status you should see something like

On branch chore/20250424-initial-customisation
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   src/_data/github.js
        modified:   src/_data/meta.js
        modified:   src/_data/personal.yaml
        modified:   src/assets/css/global/blocks/external-link.css

no changes added to commit (use "git add" and/or "git commit -a")

Run

git add .
git commit -m "chore: initial customisation"
git push

My output is:

Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 8 threads
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 1.38 KiB | 1.38 MiB/s, done.
Total 12 (delta 9), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (9/9), completed with 9 local objects.
remote:
remote: Create a pull request for 'chore/20250424-initial-customisation' on GitHub by visiting:
remote:      https://github.com/nickromney/nickromney-com-eleventy-excellent/pull/new/chore/20250424-initial-customisation
remote:
To github.com:nickromney/nickromney-com-eleventy-excellent.git
 * [new branch]      chore/20250424-initial-customisation -> chore/20250424-initial-customisation
branch 'chore/20250424-initial-customisation' set up to track 'origin/chore/20250424-initial-customisation'.

And from my terminal I can click the suggested link to create a Pull Request

At that point, I can Merge the Pull Request, then Delete the branch

Back on the local terminal

git switch main
git switch pull

Yes, this is exactly what I do, even when no-one is watching.

Remove unneeded posts

From what can be deleted we read

If you want to keep the defaults, but get rid of the example content, delete the following files and archives:

  • github.js in src/_data/
  • builtwith.json in src/_data/
  • all files in src/posts
  • the directory and all files in src/docs
  • all pages in src/pages, though you might want to keep index.njk as a starting point
  • You can delete screenshots, blog and gallery in src/assets/images.
  • Keep the favicon and template folders though.

I want to later edit builtwith.json to profile my own projects

My git commands were:

git switch -c chore/20250424-initial-deletion
git rm src/pages/get-started.md
git rm src/pages/styleguide.njk
git rm src/posts/2022/*
git rm src/posts/2023/*
git rm src/posts/2024/2024-01-30-gallery.md
git rm src/posts/2024/2024-02-01-v-2.md
git rm src/posts/2024/2024-06-03-v-3.md
git rm src/posts/2024/2024-07-21-draft.md

Add my own posts

I had a couple of posts for 2024, so moved them under src/posts/2024

  • src/posts/2024/2024-01-05-aks-course-launch-1.md
  • src/posts/2024/2024-01-12-do-I-need-a-further-cloud-certification.md

Run

npm run start

Work with Open Graph images

When we run npm run start, we see that two additional images are created, for Open Graph

[11ty/eleventy-img] Processing ./dist/assets/og-images/how-hard-can-it-be-to-write-an-educational-course-preview.svg
[11ty/eleventy-img] Processing ./dist/assets/og-images/open-graph-images-preview.svg

This is determined by src/common/og-images.njk

I took away the SVG representation of the 11ty logo, and updated the beginning to:

fontDisplay: "'Red Hat Display', Ubuntu" # needed created in local development, font must be installed on your system.
fontBody: "'Atkinson Hyperlegible', Ubuntu" # needed created in local development, font must be installed on your system.
background: "#FBBE25"
text: "#161616"
siteUrl: "www.nickromney.com"

For the header, I want to:

  • customise the list of pages
  • change “Blog” to “Writing”
  • remove “Built with”

For the footer, I want to:

  • remove the link to the “Style guide” page we removed with git rm src/pages/styleguide.njk
  • remove the version number from the site - “Nick Romney 4.1.7” makes less intuitive sense than “Eleventy Excellent 4.1.7”

In src/_data/navigation.js, we can update the navigation for the header and the footer, even before the pages exist

export default {
  top: [
    {
      text: 'Now',
      url: '/now/'
    },
    {
      text: 'Building',
      url: '/building/'
    },
    {
      text: 'Certifications',
      url: '/certifications/'
    },
    {
      text: 'Writing',
      url: '/writing/'
    },
    {
      text: 'Hire Me',
      url: '/hire/'
    }
  ],
  bottom: [
    {
      text: 'Imprint',
      url: '/imprint/'
    },
    {
      text: 'Privacy',
      url: '/privacy/'
    }
  ]
};

In src/_includes/partials/footer.njk, update line 7 from

><span class="font-display">{{ meta.siteName }}</span> <small>{{ pkg.version }}</small>

to

><span class="font-display">{{ meta.siteName }}</span>

In src/pages/legal.md and src/pages/privacy.md, remove the line

Edit your details in `_data/personal.yaml`

Replace Blog with Writing

This is my own personal choice, as it includes links to Writing I may have done elsewhere, possibly a book in time.

git mv src/pages/blog.njk src/pages/writing.njk

And making writing.njk


---
layout: base
title: Writing
description: 'All writing'
pagination:
  data: collections.allPosts
  size: 8
permalink: 'writing/{% if pagination.pageNumber >=1 %}page-{{ pagination.pageNumber + 1 }}/{% endif %}index.html'
---

<div class="wrapper">
  <header class="full | section" style="--spot-color: var(--color-secondary)">
    <div class="section__inner flow region" style="--region-space-top: var(--space-xl-2xl)">
      <h1 class="text-center" style="color: var(--color-light);">{{ title }}</h1>
    </div>

    {% svg "divider/edgy", null, "divider" %}
  </header>

  <div class="region flow prose" style="--region-space-top: var(--space-xl-2xl)">
  </div>

  <custom-masonry layout="50-50">
  {% asyncEach item in pagination.items %}
   {% include "partials/card-blog.njk" %}
  {% endeach %}
 </custom-masonry>

  <!-- set collection to paginate -->
  {% set collectionToPaginate = collections.posts %}
  <!-- set target pagination settings in meta.js -->
  {% set metaKey = "blog" %}
  <!-- if the number of items in the collection is greater than the number of items shown on one page -->
  {% if collectionToPaginate.length > pagination.size %}
    <!-- include pagination -->
    {% include 'partials/pagination.njk' %}
  {% endif %}
</div>

Edit the index (home) page

Edit the src/pages/index.njk for the content you want on your home page, especially the title in the YAML frontmatter.

Add and Delete Pages

git rm src/pages/about.md
git rm src/pages/sustainability.md

At this point our pages are a mixture of Nunjucks and Markdown

- built-with.njk
- index.njk
- legal.md
- privacy.md
- writing.njk

We have complete freedom which style to add.

I want building rather than built-with, as for a personal site, it’s what I’m building, rather than how this project is being used by others.

git mv src/pages/built-with.njk src/pages/building.njk

I copied over the pages to match my top navigation, plus /uses, so the full list is

- building.njk
- certifications.md
- hire.md
- index.njk
- legal.md
- now.md
- privacy.md
- uses.md
- writing.njk

Deploy with a Cloudflare Pages CI/CD workflow

This assumes that you have a Cloudflare account.

Once logged in:

  • go to “Compute (Workers)”, then “Workers & Pages”
  • click “Create”
  • choose “Pages”

Cloudflare screen Create an Application - choose the Pages tab

Select from among the GitHub repositories you have authorised Cloudflare to see:

Cloudflare screen - select a GitHub repository

Fill in the build settings

Cloudflare screen - set build settings

Especially:

“build command”

npm run build

and

“build output directory”

dist

We add the variable name URL with the value https://www.nickromney.com

Click “Save and Deploy”

The end of the logs says

20:57:22.199 [11ty] Writing ./dist/tags/writing/index.html from ./src/common/tagList.njk
20:57:22.200 [11ty/eleventy-img] 8 images optimized (2 cached)
20:57:22.201 [11ty] Copied 43 Wrote 112 files in 7.02 seconds (62.7ms each, v3.0.0)
20:57:22.287 Finished
20:57:23.171 Checking for configuration in a Wrangler configuration file (BETA)
20:57:23.171
20:57:24.274 No wrangler.toml file found. Continuing.
20:57:24.275 Note: No functions dir at /functions found. Skipping.
20:57:24.275 Validating asset output directory
20:57:27.086 Deploying your site to Cloudflare's global network...
20:57:29.586 Uploading... (0/176)
20:57:30.673 Uploading... (59/176)
20:57:30.794 Uploading... (117/176)
20:57:31.246 Uploading... (176/176)
20:57:31.246 ✨ Success! Uploaded 176 files (2.44 sec)
20:57:31.246
20:57:31.731 ✨ Upload complete!
20:57:35.258 Success: Assets published!
20:57:36.911 Success: Your site was deployed!

Give it a few minutes for the DNS to resolve, and check the site with its .pages.dev suffix: https://nickromney-com-eleventy-excellent.pages.dev/

Then set (or update) the CNAME with a proxied target of nickromney-com-eleventy-excellent.pages.dev

From the [https://developers.cloudflare.com/pages/configuration/build-image/#supported-languages-and-tools](supported languages and tools page) we see that Node by default is 18.17.1 and we need version 20 or above.

We’ve been working with 20.19.1, so we will add another variable with name NODE_VERSION which should be picked up on the next deployment.

Set the custom domain

Cloudflare screen - add a custom domain

I choose to add two - the “naked” domain, and with a www. prefix.