Gatsby is a great tool that lets you build awesome applications! In fact I use Gatsby for my own site (hopefully you're reading this on there 😃), but I ran into an issue with loading externally hosted images. The issue was that since the images were externally hosted I had to fetch them on each page load and some images were optimized and thus it would take longer and affect the user experience.
I heard great things about the Gatsby Image library specifically for solving image optimization issues but didn't know how to use it for externally hosted images since my blog is powered by Ghost CMS. Luckily I managed to figure it out so this is a guide to walk you through what I did.
You're only going to need 3 dependencies, most of which you should already have, but just in case you don't, you're going to need the following:
Img
component that will be used in our React codeMost of the work will be done in the gatsby-node.js
file, you can choose to do this in the createPages
or createNode
exported functions, I did it in the createPages
just because I was running into some issues with my pagination plugin when attempting to do this in the createNode
.
The createPages
function is passed a param which has multiple functions, if destructring the param make sure to destructure the following. You can also further destructure from the actions param:
exports.createPages = async ({ actions, getCache, createNodeId, cache, reporter }) => {
const { createPage, createNode } = actions;
...
I'm going to assume that you already have the URL(s) for the image(s) stored in some variable that you will pass to a function that will generate all of these images for you.
Firstly you'll have to create a fileNode which is essentially downloading the file (image) from a remore url and storing that as an object. That would look like this:
const fileNode = await createRemoteFileNode({
url: image_url,
parentNodeId: id,
getCache,
createNode,
createNodeId,
});
Now that you have "downloaded" the remote file (image) you'll now need to generate an image object from it using gatsby-plugin-sharp
. That would look like this:
const generatedImage = await fluid({
file: fileNode,
reporter,
cache,
});
Now you have your generated image, and you can pass that to whatever page you want. Below you'll find a snippet from my implementation, and you'll see how that is passed to my posts pages. I'm using a map to store each generated image and to prevent duplicates, plus it makes retrieval of each image object easier for me. I then only pass the generated image for each specific post.
// This is the function that does all the work
const generateImages = async (pages) => {
const featureImages = new Map();
for (const page of pages) {
const { node } = page;
if (featureImages.has(node.slug)) {
return;
}
const fileNode = await createRemoteFileNode({
url: node.image_url,
parentNodeId: node.id,
getCache,
createNode,
createNodeId,
});
const generatedImage = await fluid({
file: fileNode,
reporter,
cache,
});
featureImages.set(node.slug, generatedImage);
}
return featureImages;
};
const fluidImages = await generateImages(posts);
// Create post pages
posts.forEach(({ node }) => {
createPage({
path: node.url,
component: postTemplate,
context: {
slug: node.slug,
fluidImage: fluidImages.get(node.slug),
},
});
});
So now that we have the gatsby-plugin-sharp
fluid images and have them passed to the postTemplate
page the usage is quite simple. Note that the fluidImage
is accessible via the props specfically under props.pageContext.fluidImage
.
Firstly you want to import the following at the top of your postTemplate
or whatever component page.
import Img from 'gatsby-image';
Now in your JSX simple use the Img
component and access the passed fluidImage
, it would look something like the following:
<Img fluid={props.pageContext.fluidImage} />
Yay you're all done, now that you know how to generate the image and use it, you can now go back and read the docs for the various libraries to figure out how to configure them for optimal performance for your use case!
Live Long and Program 🖖👨💻