How to Set Up a Dev Environment for Creating a Custom Ghost Theme
Tags: ghost, webdev, javascript, css
Published: 2022-01-18 01:48:03

---
title: How to Set Up a Dev Environment for Creating a Custom Ghost Theme
published: true
date: 2022-01-17 15:00:00 UTC
tags: Ghost,WebDev,JS,CSS
canonical_url: https://ryanfeigenbaum.com/ghost-theme-starter/
---

 ![How to Set Up a Dev Environment for Creating a Custom Ghost Theme](https://ryanfeigenbaum.com/content/images/2022/01/develop.webp)

In this guide, I'll show you how I set up my dev environment for creating a custom [Ghost](https://ghost.org) theme. The key part of this environment is [Rollup](https://rollupjs.org/guide/en/), which I use to compile, bundle, and minify my JavaScript and CSS files.

My Rollup config–in addition to some other goodies like a script to start a LiveReload server and one to zip theme files–are available as a template on GitHub. The template includes the basic Handlebars files needed for a Ghost theme, Rollup, PostCSS, basic JS and CSS, along with some explanatory comments. The template builds off of the [official Ghost theme Starter](https://github.com/TryGhost/Starter).

Below, I walk through the template and show how to use it.

[GitHub - royalfig/ghost-theme-starter](https://github.com/royalfig/ghost-theme-starter)

📢 My Ghost theme starter is a work in progress. I'll be updating and adding to it, so check back often. Contributions are also welcome!

## Prerequisites

This guide assumes you have a [local version of Ghost installed](https://ghost.org/docs/install/local/). If you don't, the official documentation should help you get set up. You'll need some basic familiarity with the command line and a code editor like [VS Code](https://code.visualstudio.com/).

If you've never built a Ghost theme before, you'll want to read through [the docs](https://ghost.org/docs/themes/) to understand how the template layer works. You can also look at my custom themes, [Smart](https://github.com/royalfig/smart) and [Mel](https://github.com/royalfig/mel), or the default Ghost theme, [Casper](https://github.com/TryGhost/Casper), to see real-world examples.

If you're brand new to building Ghost themes and would like more articles walking you through the basics–[let me know](https://ryanfeigenbaum.com/contact).

## Get the Template

Go to my [ghost-theme-starter](https://github.com/royalfig/ghost-theme-starter) and click `Use the template`. (You can also just clone the repo directly.) This will create a copy of the template in your GitHub account. You can then clone the repo to your local machine.

Go to the directory where you installed the theme starter and install dependencies with `npm install`. Then, create a symlink from the theme starter to your Ghost's `themes` folder ( `content/themes`). The symlink allows you to work on your theme in a folder that's independent of your Ghost install, yet still links to it directly. This way you can reinstall Ghost without having to worry about your theme files or upload a production version of the theme to your local install without worrying about overwriting your local development copy.

```
# symlink your theme to your local Ghost install
ln -s path-to-ghost-theme-starter ghost-install/content/themes
```

_Create a symlink between your theme and the Ghost themes folder_

Run `ghost restart` so Ghost recognizes your new theme. Activate your theme and you're off to the races.

## Make It Pretty

Styles live in `src/css`, and files are organized into a [7-1 architecture](https://sass-guidelin.es/#the-7-1-pattern). While the 7-1 architecture was originally made popular with SASS, it's used here with several plain CSS files split across seven categories with one main `app.css` file. I find that CSS has evolved enough with custom properties and PostCSS that SASS is now unnecessary and sometimes more of a burden than a convenience.

<!--kg-card-begin: markdown-->

| Folder | Description | Example |
| --- | --- | --- |
| abstracts/ | Variables used across the project | variables.css |
| base/ | Base styles for the project | reset.css |
| layout/ | Elements found on every page | navbar.css |
| pages/ | Styling for particular templates like post.hbs or home.hbs | post.css |
| components/ | Components used frequently like buttons or forms | buttons.css |
| vendor/ | Styling for 3rd party elements | ghost.css |
| themes/ | Multiple color or typography schemes | Not used |

<!--kg-card-end: markdown-->

Use the command `npm run dev` to watch for changes in `src/css`, compile your CSS, and provide a sourcemap, so when you inspect your styles in the dev console, you'll see the exact file and line of code responsible for breaking your design.

In production, initiated with `npm run zip`, [stylelint](https://stylelint.io/) will lint your CSS, automatically ordering properties according to a recess logic. CSS will be [autoprefixed](https://github.com/postcss/autoprefixer) and polyfilled with [postcss-preset-env](https://github.com/csstools/postcss-preset-env) (like a Babel for CSS). One example of this polyfill is automatically writing fallbacks for custom properties. Finally, the CSS is minified and optimized with [cssnano](https://cssnano.co/). It's just up to you to ship those styles 🛳️.

[PostCSS - a tool for transforming CSS with JavaScript](https://postcss.org/)

## Put It to Work

> Every KB counts

For JS, the story's the same. Rollup compiles your JS files in `src/js`. What's different here is that there are two different output bundles: `app.js` and `post.js`. `App.js` is loaded globally on every page, whereas `post.js` is only loaded on posts and pages. The thinking here is that you likely have scripts that are only needed on posts and pages (like responsive embeds) that aren't needed on index pages, so you can reduce your homepage's bundle size by excluding this code from the app's main JS file.

Babel is also active to help compatibility across browsers along with a handful of other Rollup plugins to make it easier to work with next-gen JS and third-party libraries.

## Reload It Like It's Hot

Rollup has a built-in ability to watch your files and compile them when you save edits. The problem is those changes won't show up in your browser without a hard refresh.

The theme starter template uses a custom implementation of LiveReload to automatically refresh your browser whenever you make changes to your CSS or JS. This makes it easy to see your changes in real-time, without having to lift a finger.

This reloading is limited to JS and CSS changes and not to Handlebars files. If you make a change to a template file, you're stuck having to reload the browser. (It may be possible to tell LiveReload to watch for changes to .hbs files, too, but I haven't got it to work yet.) You also need to restart your Ghost instance if you add a new template file altogether.

## Zip, Zip, and Away

The final piece of this puzzle is a custom script for zipping your files up into a file that is suitable to upload to Ghost. If you add new template files, you'll need to adjust `zip.js` to include them.

It's also possible, instead of zipping your files and uploading yourself, to just use [Ghost's Github action](https://github.com/marketplace/actions/deploy-ghost-theme), which will automatically deploy your theme whenever you push a change to your repo's main remote branch.

The [ghost-theme-starter](https://github.com/royalfig/ghost-theme-starter) will set you up with a great working environment to build your next Ghost theme. Try it out and [let me know](https://ryanfeigenbaum.com/.contact) what you think.