Joona Viertola

Learning journal

Optimize Ghost post cover images in Gatsby

Couple weeks ago I started to transform my Ghost blog into JAM stack with Gatsby. There was a great starter template from Ghost team, Gatsby Starter Ghost. After about a week, I finallygot my transformation complete. Check out my result from repository Humble JAM.

After the theme looks complete, I noticed how slow first time rendeting was. Reason was the big images which were oversized, at least for mobile usage. Sadly starting template and googling didn't help a lot. After reading a lot of documentation I found a way to make fluid feature image for Ghost posts.

The problem

For optimizing images, those are need to be downloaded from host CMS. Starter template didn't have code for this.

Solution

Check and install plugins

When I did the the configuration these packages already were in the repository, but here's a checklist:

  • gatsby-source-filesystem
  • gatsby-plugin-sharp
  • gatsby-transformer-sharp

Here's the command to install them:

yarn add gatsby-source-filesystem gatsby-plugin-sharp gatsby-transformer-sharp

Check plugin configurations in /gatsby-config.js. These were also in their place, but double checking saves time.

const pluginConfig = [

    ...

    {
        resolve: `gatsby-source-filesystem`,
        options: {
            path: path.join(__dirname, `src`, `images`),
            name: `images`
        }
    },
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    
    ...

];

Fetching images

Let's start the changes. Next work is done in /gatsby-node.js file. First require gatsby-source-filesystem package.

const { createRemoteFileNode } = require(`gatsby-source-filesystem`);

Export onCreateNode function from file. Here we use feature_image property (thish is a working URL) to fetch right images to local cache. Then we create a link from file node to the original post. We give this link field a name localFeatureImage.

exports.onCreateNode = async ({
    node,
    actions,
    store,
    createNodeId,
    cache
}) => {
    // Check that we are modifying right node types.
    const nodeTypes = [`GhostPost`, `GhostPage`];
    if (!nodeTypes.includes(node.internal.type)) {
        return;
    }

    const { createNode } = actions;

    // Download image and create a File node with gatsby-transformer-sharp.
    const fileNode = await createRemoteFileNode({
        url: node.feature_image,
        store,
        cache,
        createNode,
        parentNodeId: node.id,
        createNodeId
    });

    if (fileNode) {
        // Link File node to GhostPost node at field image.
        node.localFeatureImage___NODE = fileNode.id;
    }
};

Check images in GraphiQL IDE

Now images are attached into GraphQL. Sadly for some reason GraphiQL IDE doesn't autocomplete with our homemade field, so you need to write it by hand. This was confusing and time taking for me but now you know.

query PostFeedContainer {
    allGhostPost(sort: { order: DESC, fields: [published_at] }) {
        edges {
            node {
                localFeatureImage {
                    childImageSharp {
                        fluid(
                            maxWidth: 750
                            maxHeight: 70
                            cropFocus: CENTER
                        ) {
                            aspectRatio
                            src
                            srcSet
                            sizes
                        }
                    }
                }
            }
        }
    }
}

Congratulations, if you're getting image nodes out. Check URLs and change maxHeight and maxWidth to test out that images are actually smaller. Sharp image processor's arguments are pretty well documentated in plugin's own repository gatsby-plugin-sharp.

Using images in templates

Include previous GraphQL field localFeatureImage, into your template's GraphQL section. Fluid parameters aspectRatio, src, srcSet and sizes are needed for fluid image to work with next component.

Gatsby provides nice module to use fluid images, laxy loading and placeholding. Actually it was working for me perfectly out of the box! Check gatsby-image package is installed and import it into template, where you're using optimized images.

import Img from 'gatsby-image';

Replace HTML img tags now with Img component. Notice that component takes fluid parameter, which is fluid object, and not the src parameter inside it. Path is edges.node.localFeatureImage.childImageSharp.fluid..

<Img fluid={image} alt={'Alternative text'} />

Now you should have working optimized and lazyloading images on your Gatsby site!

Other coolios...

Sharp processor has also other cool image types than fluid. Read more about them in plugin's repository gatsby-plugin-sharp.