My blog was built a long time ago using Gatsby. I vaguely remember cloning it from a template, but I can’t recall the exact name.
Over the years, I have added various features, such as the talks page, as I started giving talks.
The blog was initially built with Gatsby 1 and has been upgraded to Gatsby 2, where it has remained ever since. Although Gatsby 2’s support ended in 2021, I have procrastinated upgrading to the latest version, Gatsby 5. Since my blog is still functional and allows me to add new articles and talks, I haven’t felt a strong urge to perform a complete revamp or refactoring. It has become somewhat of a legacy system that continues to serve its purpose.
Here is the current package.json:
"dependencies": {
"@sentry/gatsby": "^5.29.2",
+ "gatsby": "2.32.13",
"gatsby-plugin-canonical-urls": "2.9.0",
"gatsby-plugin-catch-links": "^2.0.4",
"gatsby-plugin-feed": "^2.0.8",
"gatsby-plugin-google-analytics": "^2.0.6",
"gatsby-plugin-google-fonts": "latest",
"gatsby-plugin-next-seo": "^1.6.1",
"gatsby-plugin-offline": "^2.0.6",
"gatsby-plugin-react-helmet": "^3.0.0",
"gatsby-plugin-sass": "^2.0.1",
"gatsby-plugin-sharp": "^3.15.0",
"gatsby-plugin-sitemap": "^2.0.1",
"gatsby-remark-autolink-headers": "^2.1.17",
"gatsby-remark-copy-linked-files": "^2.0.5",
+ "gatsby-remark-images": "^6.12.1",
"gatsby-remark-prismjs": "^3.0.2",Perhaps one day, I will migrate the blog to Astro, but that remains a future endeavor. As a first step, I plan to migrate all my markdown files to a Notion database and connect my blog to fetch content from Notion instead of using the current markdown files. This change alone would be quite helpful. So, what’s the issue at hand?
In a recent article, I highlighted the awesomeness of the loading='lazy' property for images. I want to ensure that my blog also benefits from this feature. I recall adding the loading: 'lazy' option to gatsby-remark-images, which should apply the loading='lazy' attribute to all images by default.
{
resolve: 'gatsby-transformer-remark',
options: {
tableOfContents: {
maxDepth: 4,
},
plugins: [
'gatsby-remark-autolink-headers',
'gatsby-remark-lazy-gif',
{
resolve: 'gatsby-remark-images',
options: {
maxWidth: 960,
+ loading: 'lazy',
linkImagesToOriginal: true,
},However, upon reviewing my latest article, I noticed that the GIF files do not have the loading='lazy' property. Consequently, when visiting the page, the GIF files load immediately, resulting in a significant amount of data being loaded, especially for larger GIF files. Since many of my blog posts include GIF files to showcase visual content, this issue needs to be addressed. For example, the Angular v17’s View Transitions: Navigate in Elegance contains several GIF files and at the moment, when you enter the page, all 12 GIF files are loaded immediately, costing about 70mb of data.
While I have configured gatsby-remark-images to include the loading='lazy' property by default for most images, GIF files are not processed by this plugin. For example, the following JPG file has the loading='lazy' property:
But the GIF file does not have the loading='lazy' property. The img tag below only has the src and alt attributes:
<img src="/0a94a1f59b4ffa9c061154716bd42de2/angular-view-transitions-07.gif" alt="Customised Transition">The reason why GIFs are excluded can be found in the gatsby-remark-images documentation and some related issues:
What I want is simple: adding the loading='lazy' property to GIF files. Since gatsby-remark-images doesn’t support GIFs, I need to find an alternative solution.
- <img src="/0a94a1f59b4ffa9c061154716bd42de2/angular-view-transitions-07.gif" alt="Customised Transition">
+ <img src="/0a94a1f59b4ffa9c061154716bd42de2/angular-view-transitions-07.gif" alt="Customised Transition" loading="lazy">Searching Google doesn’t yield any straightforward solutions.
Thus, I decided to ask ChatGPT for help. Here is the conversation:
See the full conversation here.
gatsby-config.js for gatsby-remark-imagesBasically, ChatGPT suggested updating the gatsby-config.js that utilise wrapperStyle from gatsby-remark-images. This custom transformer will add the loading="lazy" attribute to .gif images.
// gatsby-config.js
module.exports = {
siteMetadata: {
// Your site metadata
},
plugins: [
{
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
{
resolve: 'gatsby-remark-images',
options: {
maxWidth: 800,
loading: 'lazy', // Default loading for images
+ wrapperStyle: (fluidResult) =>
+ fluidResult.src.endsWith('.gif') ? 'loading="lazy"' : '',
+ },
},
],
},
},
// Other plugins
],
}However, as gatsby-remark-images doesn’t support GIFs, this approach won’t work because the wrapperStyle function is only applied to images processed by gatsby-remark-images. GIFs are not processed by this plugin.
So I asked for a follow-up, and ChatGPT suggested writing a custom plugin to handle GIFs.
Below are the steps suggested by ChatGPT:
If gatsby-remark-images is filtering out .gif images and you need to add loading="lazy" to them, you can use a custom plugin to directly modify the markdown AST before gatsby-remark-images processes it. Here’s how you can achieve this:
mkdir -p plugins/gatsby-remark-lazy-gifgatsby-remark-lazy-gif, create an index.js file with the following content:// plugins/gatsby-remark-lazy-gif/index.js
const visit = require('unist-util-visit');
module.exports = ({ markdownAST }) => {
visit(markdownAST, 'image', node => {
if (node.url.endsWith('.gif')) {
node.data = node.data || {};
node.data.hProperties = node.data.hProperties || {};
node.data.hProperties.loading = 'lazy';
}
});
return markdownAST;
};
gatsby-config.js to use the custom plugin before gatsby-remark-images:// gatsby-config.js
module.exports = {
siteMetadata: {
// Your site metadata
},
plugins: [
{
resolve: 'gatsby-transformer-remark',
options: {
plugins: [
+ 'gatsby-remark-lazy-gif', // Add the custom plugin here
{
resolve: 'gatsby-remark-images',
options: {
maxWidth: 800,
},
},I followed the instructions and created the custom plugin. Then, I updated the gatsby-config.js to include the custom plugin before gatsby-remark-images. However, it threw an error:
Plugin gatsby-remark-lazy-gif requires a package.json fileI asked for further guidance, and ChatGPT suggested creating a package.json file for the plugin, as seen in the conversation below:
And voila! It works! Now all my GIF files have the loading='lazy' property. As you scroll down the page, the GIF files are loaded dynamically, reducing the initial data load.

To boost website performance, add loading='lazy' to the img tag. While Gatsby’s default image transformer, gatsby-remark-images, doesn’t support GIFs, we can create a custom plugin to handle them.
ChatGPT has been super helpful in creating the plugin and solving this problem. I am a daily use of AI tools such as Copilot, ChatGPT and others and I really appreciate the value they bring to my work. This article was also written with ChatGPT’s help for grammar and suggestions.