DEV Community

Julien Prugne for Webeleon

Posted on • Updated on

Adding react to a ghost blog theme

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Create a navbar using Bulma

Let's install the basic libraries:

npm i -D react react-dom bulma
Enter fullscreen mode Exit fullscreen mode

We will build our react app in a folder called react

mkdir react
Enter fullscreen mode Exit fullscreen mode

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
);
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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>
);

Enter fullscreen mode Exit fullscreen mode

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 --}
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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"),
    },
};
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 ...
Enter fullscreen mode Exit fullscreen mode

Oh yeah! we can now build everything the "right way".

npm run zip
Enter fullscreen mode Exit fullscreen mode

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 --}}
Enter fullscreen mode Exit fullscreen mode

Let's rebuild and upload the built theme in the blog...

And voila, look at your blog and you have a bulma navbar.

Full sources in github

Top comments (3)

Collapse
 
drwilkins profile image
Matthew Wilkins, PhD

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...

Collapse
 
bassochette profile image
Julien Prugne

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?

Collapse
 
devinschumacher profile image
Devin

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