将段落节点替换为 HTML 个节点

Replacing paragraph nodes with HTML nodes

问题

如何将“段落”节点替换为 MDX 的“html”节点?

背景

将每个“twitter.com”链接替换为扩展的 Twitter 嵌入 HTML 到 MDX 内容中。

可重现的 CodeSandboxhttps://codesandbox.io/s/dazzling-curran-2bcwe?file=/src/index.mjs:2024-3439

问题

我有一个 MDX 内容,其中包含一个 Twitter 链接列表(例如 https://twitter.com/BrendanEich/status/1151317825908166656),替换段落节点会导致以下错误

../node_modules/esbuild/lib/main.js:869:27: error: [plugin: esbuild-xdm] Cannot read property 'line' of undefined at failureErrorWithLog (/sandbox/node_modules/esbuild/lib/main.js:1449:15) at /sandbox/node_modules/esbuild/lib/main.js:1131:28 at runOnEndCallbacks (/sandbox/node_modules/esbuild/lib/main.js:921:63) at buildResponseToResult (/sandbox/node_modules/esbuild/lib/main.js:1129:7) at /sandbox/node_modules/esbuild/lib/main.js:1236:14 at /sandbox/node_modules/esbuild/lib/main.js:609:9 at handleIncomingPacket (/sandbox/node_modules/esbuild/lib/main.js:706:9) at Socket.readFromStdout (/sandbox/node_modules/esbuild/lib/main.js:576:7) at Socket.emit (events.js:315:20) at addChunk (internal/streams/readable.js:309:12)

有问题的代码

const remarkTwitter = (options) => {
  return transformer;

  async function transformer(tree) {

    // gather Twitter links
    visit(tree, "paragraph", (node) => {
      if (isTwitterLink(node)) {
        const tweetLink = node.children[0].value;
        tweetNodeList.push([node, tweetLink]);
      }
    });

    // Build Tweet embed HTML
    // and replace the current node
    for (let i = 0; i < tweetNodeList.length; i++) {
      const twitterNode = tweetNodeList[i];
      const node = twitterNode[0];
      const tweetLink = twitterNode[1];

      try {
        const embedData = await getEmbeddedTweet(tweetLink, options);

        node.type = "html";
        node.value = embedData.html;

        return node;
      } catch (err) {
        console.error(err);
      }
    }
  }
};

我使用的不是我的自定义插件,而是 @remark-embedder/core 插件

这是使用插件的部分代码。

import remarkEmbedder from "@remark-embedder/core";
// other imports...

const getMDXOptions = (year: number, slug: string) => {
  const cwd = `${getBlogRoot(year, slug)}`;
  const imagesUrl = `/images/blog/${year}/${slug}`;

  return {
    cwd,
    xdmOptions: (options: any) => {
      options.format = "mdx";
      options.allowDangerousRemoteMdx = true;
      options.rehypePlugins = [twitterWidgetScriptPlugin];
      options.remarkPlugins = [
        remarkMdxImages,
        [
          remarkEmbedder,
          {
            transformers: [
              githubGistTransformer,
              codeSandboxTransformer,
              [oembedTransformer, oembedConfig],
            ],
            handleHTML,
          },
        ],
      ];

      return options;
    },
    esbuildOptions: (options: BuildOptions) => {
      options.outdir = path.join(process.cwd(), "public", imagesUrl);
      options.loader = {
        ...options.loader,
        ".png": "file",
        ".jpg": "file",
        ".gif": "file",
        ".svg": "file",
      };
      options.publicPath = imagesUrl;
      options.write = true;

      return options;
    },
  };
};