'Can't require remark and rehype plugins for gatsby-plugin-mdx

I was trying to follow the documentation on including rehype plugins for gatsby-plugin-mdx. Specifically I was trying to use the rehype-slug plugin. I installed the packaged with npm and set my gatsby.config.js file to

module.exports = {
  siteMetadata: {
    siteUrl: "https://www.yourdomain.tld",
    title: "test Website",
  },
  plugins: [
    {
      resolve: "gatsby-plugin-mdx",
      options:{
        rehypePlugins: [
          require("rehype-slug")
        ]
      }
    }
  ],
};
However upon running gatsby develop I encouter the following error: Error: [ERR_REQUIRE_ESM]: Must use import to load ES Module: C:\Users\User\Documents\test-site\node_modules\rehype-slug\index.js require() of ES modules is not supported.

I encouter similar problems when trying to use the remark-math and rehype-katex plugins. I'm using version 3.13.0 of the Gatsby CLI. The problem persists even with a completely new website. Any help with this issue would be much appreciated.



Solution 1:[1]

There is a simpler and more elegant solution in the same GitHub discussion

Create require-esm.js in the root folder (same place as package.json):

// Source: https://stackoverflow.com/a/71344589/2078908

const esm = require('esm')
const fs = require('fs')
const Module = require('module')

// Node: bypass [ERR_REQUIRE_ESM]
const orig = Module._extensions['.js']
Module._extensions['.js'] = function (module, filename) {
  try {
    return orig(module, filename)
  } catch (e) {
    const content = fs.readFileSync(filename, 'utf8')
    module._compile(content, filename)
  }
}

const _esmRequire = esm(module, {
  cjs: true,
  mode: 'all',
})

// don't pollute Module
Module._extensions['.js'] = orig

module.exports = function esmRequire(id) {
  return _esmRequire(id).default
}

Then use it in gatsby-config.js like this:

require.esm = require('./require-esm')

module.exports = {
        .......
        {
            resolve: `gatsby-plugin-mdx`,
            options: {
                extensions: ['.mdx', '.md'],
                rehypePlugins: [
                    // Generate heading ids for rehype-autolink-headings
                    [require.esm('rehype-slug')],
                    // To pass options, use a 2-element array with the
                    // configuration in an object in the second element
                    [require.esm('rehype-autolink-headings'), { behavior: "wrap" }],
                ],
            }
        },
        .......
}

Update

After some testing I've simplified code above to couple lines. It still works in my setup.

Use require.esm(...) in gatsby-config.js like this:

const requireEsm = require('esm')(module)
require.esm = id => requireEsm(id).default

module.exports = {
                .......
                rehypePlugins: [
                    // Generate heading ids for rehype-autolink-headings
                    [require.esm('rehype-slug')],
                    .......
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1