Time for a makeover

Two years ago, when I introduced my custom theme, I said I was still considering using another theme. I didn’t find anything that fit my taste for a while, but the time has finally come!

As a refresher, since I started this blog I have been running my fork of the default Ghost theme. It is open-source an available on GitHub. The default theme is great and well maintained.

Since 2018, the theme has evolved quite a lot, so I updated the original post with an addition screenshot I took yesterday, if you’re curious.

An efficient workflow

While I have made customisations to this theme, I made the effort to keep it in sync with the upstream Casper theme and merge the two regularly.

As explained in my last post, the theme is now deployed automatically from GitHub.

The need for a change

The default theme looks good, is fast, responsive, reliable, maintained, etc. What bothers me now is namely the fact it is the default theme.

I do think content prevails on looks as long as the looks are good enough. However I am a bit bothered seeing so many Ghost websites looking the same.

After more than two years of writing here, I consider being serious enough about this blog to give it a well-deserved lift.

The change

To be honest, I wasn’t really planning on doing this anytime soon, since I already have so many ongoing projects.

I accidently ended up on the Ghost Themes Marketplace and scrolled through- which I did dozens of times over the years already.

Some themes did catch my eye once or twice before, but they were either not good enough or expensive. I don’t have anything against paid themes, but I wasn’t in the place of spending that kind of money. (I started blogging in high school).

This time, the theme that catched my eye was Dawn, by IVEEL. It has been released in february of this year, so it’s very recent.

After clicking around the preview I realised… “Hold on… This is was I was looking for”. The design was really matching with what I had in mind.

After some thinking and a question or two to the support, I ended up buying the theme the next day. It’s an expensive theme, at $70.

Making the theme my own

I really love the look and feel of this theme. The experience on mobile is great too!

I already have some experience developing, or should I say thinkering, a Ghost theme. Once I downloaded the theme, I immediately added it to a git repository and started hacking around.

I can’t make this repository public, for obvious reasons.

Sad surprises

Unfortunately, IVEEL does not provide the full sources of theme. I had to add a Gulpfile to concatenate/uglify/minify/mapify assets and generate a usable zip file. I also had to add some dependencies and yarn scripts to fix the tests.

While the CSS file was lightly minified and still readable, the JS file was completely minified and obfuscated, so it was impossible for me to do any changes there. The support agreed to give me the original JS file and vendored dependencies, which I added to my Gulp workflow.

Some bad surprises kept coming though, which I was not expecting for a product I paid such a price. While running a Lighthouse audit in Chrome, I noticed the jQuery version used was 3.3.1, a version released in January 2018, with a CVE assigned in April 2019.

I updated to the latest version of Jquery, 3.5.0. That took my about two minutes, without any breaking change. On the same note, I made sure to update all the NPM dev dependencies and added Dependabot to my GitHub repo.

Another bad surprise I had was the JS and CSS injected for lazy loading images. It was honestly not great. First, it applied mainly to featured images, the images at the top of articles, which don’t benefit from lazy-loading at all since they are in the viewport all the time. On the other hand, images in posts are not affected even though they could benefit from this. Thirdly, even when images were cached by the browser, there was an animation that took like a second to fade the image in. Fourthly, the images depended on the JS, which meant they loaded after it. Finally, when disabling Javascript, my images were not displayed.

I removed this custom lazy-loading implementation because I was better off without it. FYI, native lazy-loading is now a thing! I enabled it with the help of a Cloudflare Worker, which I will detail in a future post.

I ran some lighthouse audits and there were quite a lot of improvements opportunities in terms of performance, accessibility and SEO.

All in all, while I don’t regret spending money on this, I would have liked more thoroughness from the developers considering it’s a paid theme.


I have vastly modified the theme for my usage over the last few days. Here are some of the changes:

  • Self-host and update jQuery
  • Enable defer on JS files
  • Add Gulp for building the theme
  • Optimise search - details below
  • Use content API v3 for search
  • Add font-display: swap to the custom fonts so that it can fallback until they’re loaded
  • Removed dark theme because I didn’t want to maintain it (also I don’t like it)
  • Improve support for disabled Javascript
  • Use real RSS feed and not Feedly
  • Adapt styling for the comments (Isso)
  • More than 200 lines of custom CSS
  • Some optimisation for performance/SEO/accessibility

It’s still a work in progress but most of the work is done and I’m really happy with what I have now!

This is so dope! Ghost doesn’t provide search, and the only solutions are either using a 3rd party service, and separate software like Elasticsearch, or client side solutions.

My new theme includes its own implementation of the latest and it works surprisingly well.

Basically, the browser will fetch a JSON payload containing all posts from Ghost’s content API and save it to local storage. Then, some JS code powered by elasticlunr.js will create an index in RAM using that JSON upon each page load. It will also check with the API if any new post has been published between the last local storage update and update the local data if needed.

devtools local storage containing the elasticlunr index

That’s all, we now have full-text-search on the client! You can try it on the top right-hand-corner of the page. Neat, right?

By default, the fetch was done for every single page of the website. Which meant every single visitor would do a SELECT * FROM posts through the API and then a SELECT ... WHERE for each page view. This isn’t a big deal at my scale, but it bothers me a little bit.

I have done two changes that optimise this by a large factor.

First, I updated my Varnish and Cloudflare configuration so that the the specific API call is cached.

Secondly, I tweaked the event listeners in the JS so that the JSON isn’t fetched on every page load, but only when the search icon is clicked, and that only once until the page is reloaded.

With these two simple tweaks, the API will be called a significantly lower amount of times and when it does, it will probably be served from some cache. I lowered the page views/API fetch ratio from 1:1 to… well, ∞:1 because technically I could fetch and cache the API call once for an infinite number of page views.

Anyway, the search feature is great, and I’m especially glad to have one so that I don’t have to search myself in Google anymore. It’s well thought-out so congrats to theme developers for putting that together.


This new look makes this blog stand out a little more from all the Casper-themed websites, and it’s very good at doing it. I find it pleasant and appealing to read. Moreover if performs really well.

The home page is certainly the most major shift between the two themes, and although both have their benefits, I’m quite fond of the current one. It’s not an endless stream of posts cards anymore. It’s composed of three parts: a little something about me, so readers know whose words they’re reading. Then some featured posts, the one I am the most proud of. And finally a simple and tidy list of my latest posts.

So far, I’m very pleased with the result, but I’m all ears - I’ll gladly read some feedback from my readers.