How to use Cloudinary with Ghost.js
Nikita Makhov
Posted on July 29, 2021
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."
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"
}
}
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);
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`);
}
}
});
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>
...
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.
Posted on July 29, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.