Last week a client come to me and ask for a custom npm package with a standardized react component he can use in his three sites. No issue, I build the thing and start the integration.
- main website: ok
- documentation site: ok
- ghost blog: ... The problems start with the blog... Ghost blog theming is mainly editing handlebar files, zipping them, and uploading them to the blog.
First let's install
The company behind ghost blog provides a sass solution for blogging, this means you won't be able to find how to install a local version easily but it is indeed quite easy.
npm install ghost-cli@latest -g
# create a local copy and start
mkdir someLocalBlogFolder
cd someLocalBlogFolder
ghost install local
ghost start
You can now connect to http://localhost:2368/ghost/#/site and set up a user.
And voila, first step done. We have a local copy!
little voice: that's not what you had to do! none will pay for a local install!
Clone a Casper theme
Ok, to gain a little time we'll clone and edit the Casper theme which is the default ghost theme.
git clone git@github.com:TryGhost/Casper.git customCasper
cd customCasper
Create a navbar using Bulma
Let's install the basic libraries:
npm i -D react react-dom bulma
We will build our react app in a folder called react
mkdir react
Inside the react folder, we will create the react app entry point react/src/app.jsx
.
import React from 'react';
import ReactDOM from 'react-dom';
import './app.scss';
import { NavbarContainer } from "./containers/NavbarContainer.jsx";
const navbarDomContainer = document.querySelector('#navbar');
ReactDOM.render(
(<NavbarContainer />),
navbarDomContainer
);
add main sass styling file react/src/app.scss
Ok, technically we can just import bulma sass in the app.jsx
file, but this way we will have an entry point to edit (if we want).
@charset "utf-8";
@import "bulma/bulma";
div#navbar {
z-index: 10000
}
create the navbar component react/src/components/Navbar.jsx
I know this is just the basic Bulma navbar example, it does not include the js to handle the burger menu (it will be covered in another post)
import React from 'react';
export const Navbar = () => (
<nav className="navbar" role="navigation" aria-label="main navigation">
<div className="navbar-brand">
<a className="navbar-item" href="https://bulma.io">
<img src="https://bulma.io/images/bulma-logo.png" width="112" height="28" />
</a>
<a role="button" className="navbar-burger burger" aria-label="menu" aria-expanded="false"
data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" className="navbar-menu">
<div className="navbar-start">
<a className="navbar-item">
Home
</a>
<a className="navbar-item">
Documentation
</a>
<div className="navbar-item has-dropdown is-hoverable">
<a className="navbar-link">
More
</a>
<div className="navbar-dropdown">
<a className="navbar-item">
About
</a>
<a className="navbar-item">
Jobs
</a>
<a className="navbar-item">
Contact
</a>
<hr className="navbar-divider" />
<a className="navbar-item">
Report an issue
</a>
</div>
</div>
</div>
<div className="navbar-end">
<div className="navbar-item">
<div className="buttons">
<a className="button is-primary">
<strong>Sign up</strong>
</a>
<a className="button is-light">
Log in
</a>
</div>
</div>
</div>
</div>
</nav>
);
add an HTML tag with the id navbar
in the main handlebar file default.hbs
{<!-- more in the file --}
<body class="{{body_class}}">
<div class="site-wrapper">
<div id="navbar"></div>
{{!-- All the main content gets inserted here, index.hbs, post.hbs, etc --}}
{{{body}}}
{<!-- ... more in the file --}
build system to bundle the react app
Install webpack tooling with all the loaders we will need.
npm i -D webpack webpack-cli @babel/core babel-loader @babel/preset-env @babel/preset-react node-sass style-loader css-loader sass-loader
At the theme root, we need to add a webpack configuration webpack.config.js
file just like this one:
const path = require('path');
module.exports = {
entry: {
main: "./react/src/app.jsx",
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/env', '@babel/preset-react']
}
}
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "assets/built"),
},
};
Cool, we can now bundle the react app using webpack.
little voice: but when i run npm run zip
the react app is not built...
Ok then, we will need to install one last dependency.
npm i -D webpack-stream
Add a new webpack
task in the file gulpfile.js
and add the function to the build definition.
// ... more gulpfile ...
const webpackStream = require('webpack-stream');
// ... more gulpfile ...
function webpack(done) {
pump([
src('assets/built'),
webpackStream(require('./webpack.config.js')),
dest('assets/built')
], handleError(done));
}
// ... more gulpfile ...
// add the
const build = series(css, js, webpack);
// ... more gulpfile ...
Oh yeah! we can now build everything the "right way".
npm run zip
Wait a second... We wrote a react app, we built the app.
Oh damned, we forgot to load the bundle in the main template.
Let's add the bundle to the main template: default.hbs
{{<!-- more handlebar template, close to the end of the body --}}
<script src="{{asset "built/main.bundle.js"}}"></script>
{{<!-- more handlebar template, close to the end of the body --}}
Let's rebuild and upload the built theme in the blog...
And voila, look at your blog and you have a bulma navbar.
Top comments (3)
so...following these steps, are you able to embed ghost theming, authoring and publishing within your react app? Our web developer was struggling with this and concluded that you couldn't adapt the themes without sending queries to Ghost's servers and receiving formatted html from them...
These steps will allow you (or your web developer) to add a react app in a Ghost blog theme.
It's just a navbar in this example, I did not have to fiddle with the article theming.
Documentation and articles on the subject are kind of scarce making it a bit of a difficult issue.
What exactly are you looking for? How much of react do you want to use in the theme?
nice! im looking for some help getting a little reacty in my current ghost theme. you looking for some extra work @bassochette ?
plz DM if on twitter/discord if so! @dvnschmchr/@devinschumacher