不能要求 gatsby-plugin-mdx 的评论和重新炒作插件

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

我试图按照 documentation 为 gatsby-plugin-mdx 包含 rehype 插件。具体来说,我试图使用 rehype-slug 插件。我用 npm 安装了打包并将我的 gatsby.config.js 文件设置为

module.exports = {
  siteMetadata: {
    siteUrl: "https://www.yourdomain.tld",
    title: "test Website",
  },
  plugins: [
    {
      resolve: "gatsby-plugin-mdx",
      options:{
        rehypePlugins: [
          require("rehype-slug")
        ]
      }
    }
  ],
};
但是在 运行 gatsby develop 我遇到了以下错误: 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.

我在尝试使用 remark-mathrehype-katex 插件时遇到了类似的问题。我使用的是 Gatsby CLI 3.13.0 版。即使使用全新的网站,问题仍然存在。对此问题的任何帮助将不胜感激。

不确定它是否有效,但是,您是否尝试过类似的东西,而不是使用 ES 模块的 require:

import slug from 'rehype-slug'

module.exports = {
  siteMetadata: {
    siteUrl: "https://www.yourdomain.tld",
    title: "test Website",
  },
  plugins: [
    {
      resolve: "gatsby-plugin-mdx",
      options:{
        rehypePlugins: [
          slug 
        ]
      }
    }
  ],
};

基于:https://github.com/rehypejs/rehype-slug

或者直接在rehypePlugins里面导入动态导入。


我做了一些研究,发现不支持动态导入,因为您无法访问回调中的值,所以等待导入不是解决方案,也不是使用 ES module.

但是,可以在此 GitHub discussion:

中找到与您完全相同的用例的最终解决方案(或至少是临时工作的解决方案)

Update: I got the update to rehype-slug@5.0.0 in my gatsby-config.js working by installing esm and patch-package and:

  1. Modifying the gatsby-config.js as follows (to allow require() with the pure ES Modules)

    require = require('esm')(module);
    
    module.exports = {
      plugins: [
        {
          resolve: `gatsby-plugin-mdx`,
          options: {
            rehypePlugins: [
              require('rehype-slug').default,
    
  2. Try running the Gatsby dev server and see what breaks. It will throw an error either like this:

      Error: Must use import to load ES Module: /Users/k/p/project/node_modules/rehype-slug/index.js
      require() of ES modules is not supported.
      require() of /Users/k/p/project/node_modules/rehype-slug/index.js from /Users/k/p/project/gatsby-config.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
      Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/k/p/project/node_modules/rehype-slug/package.json.
    

    ...or like this:

      Error: /Users/k/p/project/gatsby-config.js:1
      Error: Must use import to load ES Module: /Users/k/p/project/node_modules/rehype-slug/index.js
    
  3. Make a note of the location of the pure ES Modules package so that you can locate the package.json file corresponding to the pure ESM package and manually remove the line with "type": "module", like this:

    -  "type": "module",
    
  4. Run yarn patch-package <pkg name> --exclude '^$', which will record the changes that you have made in the package.json file (to be reapplied by patch-package every time that you run yarn or npm install). Examples:

    # For a top-level dependency
    yarn patch-package rehype-slug --exclude '^$'
    
    # For a transitive dependency
    yarn patch-package rehype-slug/unist-util-visit --exclude '^$'
    
  5. Run the Gatsby dev server again, and repeat step 3 and 4 for every pure ESM package.

At that point, I could start the Gatsby dev server with the new pure ESM dependency versions.

cc @Ir1d @kimbaudi @wardpeet @LekoArts

Caveat: In my specific case, I needed to also patch one of the dependencies (hast-util-heading-rank) because I was getting an undefined node.tagName, but I think this is unrelated to this problem - probably related to a different issue.

全部归功于所涉及的魔术师

在同一个GitHub discussion

中还有一个更简单优雅的解决方案

在根文件夹中创建 require-esm.js(与 package.json 相同的位置):

// Source: 

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
}

然后像这样在 gatsby-config.js 中使用它:

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" }],
                ],
            }
        },
        .......
}

更新

经过一些测试后,我将上面的代码简化为几行。它在我的设置中仍然有效。

像这样在 gatsby-config.js 中使用 require.esm(...)

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')],
                    .......
}