如何使用组件将 MDX2 编译为静态 HTML

问题描述 投票:0回答:0

我正在尝试编写一个 MDX2 到 HTML 的编译器。我已经完成了大部分工作(也就是说,我可以将一个简单的

.mdx
文件编译为HTML),但没有可导入的组件。

我已经通读了整个 MDX2 网站,但它对我来说并不是很吸引人。我有一堆成功的实验,做了不同的部分,但我还没有完全看到。

目标

我想将一组 MDX2 字符串(一个主要片段和一组组件)编译成静态 HTML 组件——最好不访问磁盘.

(这不是绝对要求,但我想在 AWS lambda 中运行它,并且我无法在部署时访问所有文件。我可以使用 lambda 的

/tmp
目录,但宁愿不是因为各种原因。)

我试过的

这是我目前所拥有的。 这行得通;它在不接触磁盘的情况下将 MDX2 编译为 HTML(除了在此示例中加载入口点,但它可以很容易地是来自其他地方的字符串)。但它不允许我做诸如导入 MDX 组件之类的事情,而且我正在做的字符串操作感觉真的很脏。

首先是我的

.mdx
档案:

//example.mdx

# Title

export const Thing = ({foo}) => <>{foo}</>

# Hello, <Thing foo="bar"/>!

This is the content.

然后我有一个

.js
文件:

// example.js
import fs from 'node:fs/promises'
import { compile } from '@mdx-js/mdx'
import { renderToString } from 'react-dom/server';
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";

/**
 * Using a vm to compile the mdx.  Why?  It seems like a way I can add
 * components accessible to the entry markdown file.  Is there a better way?
 *
 * This is the only way I could figure out how to _use_ the compiled module
 * without touching the filesystem.  Is a vfile a better choice?  I haven't
 * used them yet.
 */
import {NodeVM} from 'vm2';

/**
 * Load and compile the ./example.mdx file.  For reasons I don't quite
 * understand, I have to remove any import statements and the default
 * export.  If I don't do this, it throws an error (this could be a VM
 * issue and a reason not to use it).
 */
let compiled = String(await compile(await fs.readFile('example.mdx')))
  .replace(/import .*;/, '')
  .replace(/export default MDXContent;/, '')
;

/**
 * Here, grab the named export from the module.
 */
let namedExport = compiled.match(/export const (\w+)/);
if (namedExport) {
  namedExport = namedExport[1];
}

// Get the compiled version and remove the `export const`
compiled = compiled.replace(/export const (\w+)/, "$1");

/**
 * The compild version of this module needs to export MDXContent and the
 * named export (if there is one). We do that here.
 */
compiled += `
module.exports = {
  MDXContent,
  ${namedExport || "_void: ''"},
}
`;

/**
 * Set up our NodeVM.
 */
const vm = new NodeVM({
  console: 'inherit',
  sandbox: {
    // React resources needed by the module.
    _Fragment,
    _jsx,
    _jsxs,
  },
  require: {
    external : true,
    builtin  : ['fs','path'],
    root     : './',
    external : true,
    mock: {},
  },
});

// Now we've got a component.
let component = vm.run(compiled);

/**
 * For reasons I don't understand, when I render this I get empty HTML
 * comments. This removes them.
 */
console.log(
  renderToString(component.MDXContent())
  .replace(/<!-- -->/igsm,'')
);

这是我的

package.json

{
  "name": "mdx",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@mdx-js/loader": "^2.3.0",
    "@mdx-js/mdx": "^2.3.0",
    "@mdx-js/node-loader": "^2.3.0",
    "@mdx-js/react": "^2.3.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-jsx": "^1.0.0",
    "vm2": "^3.9.17"
  }
}

这行得通——但感觉太老套了。由于我们在后台使用统一,我当然可以只呈现为静态 HTML 吗?据我了解,MDX2(通过

@mdx-js/mdx
)基本上做了类似的事情:

mdx → hast → esast

从 MDX2 到编译组件。我知道

esast
步骤是解决进口等问题。我觉得我应该能够从那里back
hast
并只渲染片段,但我不完全明白它。

下一步...?

我很乐意使用一组 MDX2(也许还有 MD)strings 并将所有内容编译成片段而无需访问磁盘。我看到了 mdx-bundler(链接自 mdx 文档中的here),但我无法让它工作。不过,它看起来很有希望。

这是我想要开始工作的一个例子:

组件A

Component A says: {props.data}

组件B

<ul>{props.items.map(item => (<li>{item}</li>))}</ul>

入口点降价

# Entrypoint

<ComponentA data="foo"/>
<ComponentB items={1,2,3}/>

输出:

<h1>Entrypoint</h1>

<p>Component A says: foo</p>
<ul><li>1</li><li>2</li><li>3</li></ul>

使用一些看起来像这样的 javascript:

...
const ComponentA = 'Component A says: {foo}';
const ComponentB = componentBFromSomewhere;
const entrypoint = entrypointFromSomewhere;

function mdxToHtml (e, opt) {
  // ... magic!
}

console.log(mdxToHtml(entrypoint, {components: {ComponentA, ComponentB}}));

或类似的东西。帮忙吗?

javascript html node.js transformation mdxjs
© www.soinside.com 2019 - 2024. All rights reserved.