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.
Below, I walk through the template and show how to use it.
📢 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!
This guide assumes you have a local version of Ghost installed. 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.
If you've never built a Ghost theme before, you'll want to read through the docs to understand how the template layer works. You can also look at my custom themes, Smart and Mel, or the default Ghost theme, 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.
Go to my 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
ghost restart so Ghost recognizes your new theme. Activate your theme and you're off to the races.
Styles live in
src/css, and files are organized into a 7-1 architecture. 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.
|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|
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 will lint your CSS, automatically ordering properties according to a recess logic. CSS will be autoprefixed and polyfilled with 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. It's just up to you to ship those styles 🛳️.
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 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.
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.
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, which will automatically deploy your theme whenever you push a change to your repo's main remote branch.