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.