How to use Cloudinary with Ghost.js

defite

Nikita Makhov

Posted on July 29, 2021

How to use Cloudinary with Ghost.js

Introduction

Ghost.js - is an open-sourced blog publishing platform built with Node.js (with great help of Handlebars, of course). It has amazing Medium-like inline editor, which is simple and inspiring for writing new content without any hastle.

Cloudinary is "a cloud-based SaaS that provides an end-to-end image and video management solution including uploads, storage, manipulations, optimizations and delivery. All your media resources are optimized and delivered through a fast CDN using industry best practices."

Alt Text

Cloudinary in Ghost.js

Why bothering with another post if everything is in the docs? That's because of specifity of my current task: I want to Ghost.js be on my local machine, uploading all images to Cloudinary and build static front with Nuxt.js.

Well, there is adapter solution which will allow us/me/you to automatically fetch ALL (that's the pit) uploaded images to Cloudinary. It's a good solution except lack of control for my images at the front.

My solution

I've dig Internet a bit/a lot and found my way to fetch images to Cloudinary. First of all, I've modified Ghost config. As it is my local installation, I've used dev config.

"imageOptimization": {
    "cloudinary": {
      "baseUrl": "https://res.cloudinary.com/summertimesadness/image/fetch/f_auto,q_auto"
    }
}
Enter fullscreen mode Exit fullscreen mode

This config is using default imageOptimization object, so there is no need to double-check it's presence in the guts of Ghost.js. Cloudinary settings object is WIP, but it's working fine already.

The second step is to modify/fork/make pr into several Ghost packages, responsible for image set generation. This is not the best way to deal with this problem, but certainly it gives you more control over image content in your blog then using adapter (correct me, if I'm wrong).

So, you'll need to find this package: @tryghost/kg-default-cards/lib/cards/image.js. Then you'll need to change render method a bit:

const { cloudinary } = options.imageOptimization;

const payloadSrc = cloudinary ? `${cloudinary.baseUrl}/${payload.src}` : payload.src;
img.setAttribute('src', payloadSrc);
Enter fullscreen mode Exit fullscreen mode

This will prefix every image src inside your post with Cloudinary fetch url with chosen params.

Next step, you will change the way srcset is generated. Find @tryghost/kg-default-cards/lib/utils/set-srcset-attribute.js module.

srcsetWidths.forEach((width) => {
  if (width === image.width) {
     // use original image path if width matches exactly (avoids 302s from size->original)
     srcs.push(`${image.src} ${width}w`);
  } else if (width <= image.width) {
     // avoid creating srcset sizes larger than intrinsic image width
     if (options.imageOptimization.cloudinary) {
        srcs.push(`${options.imageOptimization.cloudinary.baseUrl},w_${width}/${imagesPath}/${filename} ${width}w`);
     } else {
        srcs.push(`${imagesPath}/size/w${width}/${filename} ${width}w`);
     }
   }
});
Enter fullscreen mode Exit fullscreen mode

After making this code modifications you'll need to ghost restart and reupload images in your posts. Then you'll get (in your static site front) such piece of code in api response:

...
<figure class="kg-card kg-image-card">
  <img src="https://res.cloudinary.com/summertimesadness/image/fetch/f_auto,q_auto/http://localhost:2368/content/images/2021/07/aspect-ratio-3.png" class="kg-image" alt="" loading="lazy" width="944" height="444"
    srcset="https://res.cloudinary.com/summertimesadness/image/fetch/f_auto,q_auto,w_600/http://localhost:2368/content/images/2021/07/aspect-ratio-3.png 600w, https://res.cloudinary.com/summertimesadness/image/fetch/f_auto,q_auto,w_944/http://localhost:2368/content/images/2021/07/aspect-ratio-3.png 944w"
    sizes="(min-width: 720px) 720px">
</figure>
...
Enter fullscreen mode Exit fullscreen mode

PS

This is proof of concept and I'm still searching for ways to achieve my result in better ways. Every ghost update will destroy your code changes (or better say, it will stay in older versions folder). But if you want better PageSpeed Insights metrics, free static site hosting and amazing post editor hosted locally on your laptop - may be this is the way.

Also I hope to read in comments if you had anything related with your static site generator and Ghost.js and how you've solved it. May be together we'll find better way to integrate Cloudinary (or such) service with Ghost.js.

💖 💪 🙅 🚩
defite
Nikita Makhov

Posted on July 29, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related