How to make Netlify CMS image paths work on Gridsome
Gridsome and Netlify CMS are fantastic software projects, which allow you to respectively create a blazingly fast static website and manage your content from a beautiful UI. However they disagree on how to handle file paths of images or blog post covers.
Suppose you created a simple blog with Gridsome and configured Netlify CMS.
Your config.yml
might look something like the following:
media_folder: 'static/uploads'
public_folder: '/uploads'
site_url: https://example.com
collections:
- name: posts
folder: 'posts'
create: true
slug: '{{slug}}'
fields:
- {label: 'Title', name: 'title', widget: 'string'}
- {label: 'Cover', name: 'cover_image', widget: 'image'}
- {label: 'Body', name: 'body', widget: 'markdown'}
Now let us create a simple post with some images by adding the following
markdown file to the posts
directory:
---
title: A post with a cover image
date: 2019-07-09
published: true
cover_image: ./images/cover_image.jpg
---
My first post \o/
![Image](./images/other_image.jpg)
The problem
Gridsome interprets the paths as relative with respect to the
post file location. Assuming the images exist in posts/images
the post would
look perfect on your blog.
Unfortunately though Netlify CMS fails to load the images in its UI. Apparently
it treats paths starting with ./
as absolute. Therefore, it will look
for our images in https://example.com/images/
.
If we manually change our paths and remove the ./
, Netlify CMS will look
for them inside the public_folder
. However, Gridsome still expects them
inside posts/images
.
Finally if we upload a new image from the UI and try to insert it in a post,
Netlify CMS will use an absolute path, i.e.
![Image](/uploads/other_image.jpg)
. At first glance, using absolute paths
seems to work
flawlessly both in the UI and with Gridsome. There is only a minor catch:
the images will not be optimized by Gridsome anymore.
Considering that progressive images are one of the major selling points of Gridsome, I am not satisfied with this solution.
The solution
I tried to look for ways to fix this problem, and found many
related issues but no
convincing solution. So, I tried to roll my own and made
gridsome-plugin-netlify-cms-paths
.
The code is very simple and could certainly be improved a lot. Feel free to head over to the repository and submit a pull request. All contributions are very welcome!
In order to use it, just add it to your project with yarn/npm:
$ yarn add gridsome-plugin-netlify-cms-paths
And configure it in your gridsome.config.js
. For example, assuming you have
this fairly standard configuration:
module.exports = {
// ...
plugins: [
{
use: '@gridsome/source-filesystem',
options: {
typeName: 'Post',
path: 'posts/*.md',
route: '/:slug',
}
},
{ use: 'gridsome-plugin-netlify-cms' },
],
transformers: {
remark: {
plugins: [
'@gridsome/remark-prismjs'
]
}
},
}
You would need to add the following plugin definition:
use: 'gridsome-plugin-netlify-cms-paths',
options: { contentTypes: ['Post'] }
Then you need to move all your images to media_folder
. Assuming your Netlify
CMS config.yml
is set up like shown above, this would be static/uploads
.
The details
The plugin takes care of transforming two kinds of paths by ensuring they start
with media_folder
:
- Relative paths not starting with
./
(i.e.path/to/image1.jpg
) - Absolute paths starting with
public_folder
(i.e./uploads/image2.jpg
)
For example, with the config.yml
we showed above, we would have the following
transformations:
path/to/image1.jpg
to/static/uploads/path/to/image1.jpg
/uploads/image2.jpg
to/static/uploads/image2.jpg
Note that you still need to move all your images to media_folder
in order for
this to work.
Having your images inside static/
enables Netlify CMS
to find them at public_folder
and at the same time does not prevent Gridsome
to optimize them.
The plugin fixes the image paths it finds inside the body of your markdown
files. However, it can be configured to also fix a cover image field inside the
frontmatter of your posts, using the coverField
option:
{
use: 'gridsome-plugin-netlify-cms-paths',
options: {
contentTypes: ['Post'],
coverField: 'cover_image'
}
}
Congrats! You now have images working both on Gridsome and Netlify CMS, without sacrificing any optimization.