By Paul Scanlon

MDX 2 Breaking changes and gatsby-plugin-mdx v4 (Slug)

  • Gatsby
  • MDX

If you’re upgrading to v4 of gatsby-plugin-mdx you’ll likely run into errors. Both MDX 2 and v4 of the plugin are major releases and inline with semantic versioning guidelines, breaking changes are to be expected.

Both Gatsby and MDX have documented the changes and you can find more information about the changes on the following links.

Breaking Changes to Slug

In this post I’ll only be covering the changes to the slug field. This change may only be relevant if you’re using mdx.slug to form routes using either createPage or collection routes with File System Route API.

The Error

ERROR #85923  GRAPHQL

There was an error in your GraphQL query:

Cannot query field "slug" on type "Mdx".

If you don't expect "slug" to exist on the type "Mdx" it is most likely a typo. However, if you expect "slug" to exist there are a
couple of solutions to common problems:

This happens because mdx.slug has been removed from v4 of the plugin.

Adding a slug field

If you’d like to keep using a slug with MDX 2 and v4 of the plugin it’s necessary to create the slug field yourself. One way you can achieve this is using onCreateNode, createNodeField and the createFilePath Helper Function from gatsby-source-filesystem.

This approach relies on local file names broadly conforming to Semantic URLs / Clean URL guidelines.

For example:

|-- src
    |-- pages
        |-- ✅ this-is-fine.mdx
        |-- ⚠️ this-/-could-/-be-/-problematic.mdx

In any case, if you’ve named your local .mdx files sensibly you should be able to use them to form a slug.

// gatsby-node.js
const { createFilePath } = require('gatsby-source-filesystem');

exports.onCreateNode = ({ node, getNode, actions: { createNodeField } }) => {
  if (node.internal.type === 'Mdx') {
    createNodeField({
      node,
      name: 'slug',
      value: createFilePath({ node, getNode })
    });
  }
 ;

createPages

You can then use this new field in createPages like this.

exports.createPages = async ({ graphql, actions: { createPage, createRedirect } }) => {
  const {
    data: { allMdx }
  } = await graphql(`
    query {
      allMdx {
        nodes {
          id
+         fields {
+           slug
+         }
-         slug
        }
      }
    }
  `);

  allMdx.nodes.forEach((node) => {
    const {
      id,
+     fields: { slug },
-     slug
    } = node;

    createPage({
      path: slug,
      ...
    });
  });
};

File System Route API

And if you’re creating pages using collection routes you can use the new field like this.

|-- src
    |-- pages
-        {mdx.slug}.js
+        {mdx.fields__slug}.js

Querying fields.slug

In any GraphQL queries where you might have been using mdx.slug, perhaps when creating a navigation using a useStaticQuery hook, they will now becomes the following.

// src/components/navigation.js

  const {
    allMdx: { nodes }
  } = useStaticQuery(graphql`
    {
      allMdx {
        nodes {
+         fields {
+           slug
+         }
-         slug
          frontmatter {
            title
          }
        }
      }
    }
  `);

It’s a small thing but having upgraded a few sites now I feel like this is the least manual way to work round the missing mdx.slug field.

Further Reading

Hey!

Leave a reaction and let me know how I'm doing.

  • 0
  • 0
  • 0
  • 0
  • 0
Powered byNeon