サーバ側でReactMarkdownを実行しmarkdownをhtmlに変換する

# はじめに

今回はサーバ側でreact-markdownを実行しmarkdownをhtmlに変換してファイルとして保存する方法を説明します。

- ブラウザ側でreact-markdownを実行させたくない
- サーバ側で実行した結果を配信したい  

という人は見て頂ければと思います。

## 何をすればよいか？

まず、ブラウザ側で実行していた処理を示します。  

- Markdown_to_html.jsx  

```javascript
import ReactMarkdown from 'react-markdown';
import Typography from '@mui/material/Typography';

const H1Heading = ({ node, children }) => {
  return (
    <>
      <Typography id={node.position.start.line.toString()} gutterBottom variant="h4" component="h1" sx={{ borderBottom:"double 5px #00BB00" }} >
          {children}
      </Typography>
    </>
  )
}

export default function Markdown(props) {
  return (
    <div style={{lineHeight: 1.8}}>
      <!-- h1要素(マークダウンの#で始まる箇所)はH1Headingに変換するようcomponentsで指定している -->
      <ReactMarkdown components={{ h1: H1Heading }} {...props} />
    </div>
  );
}
```

上記のコードでは、渡されたmarkdownテキスト（props）をReactMarkdownを用いてhtmlに変換しています。本記事で説明するのは、ReactMarkdownで変換した後に得られるhtmlをファイルとして保存するための手順となります。  
\
では、具体的に何をすればよいか？必要な手順は下記の通りです。  

1. 実行したいファイル（Markdown_to_html.jsx）のコードを修正する
2. Babelをインストール、config設定
3. Babelでjsxファイルをjsファイルに変換する
4. Node.js上でjsファイルを実行する

ブラウザ側で実行されていたreact-markdownの処理をサーバ側で実行するためには、<color color="red">**JavaScriptの実行環境であるNode.js上でjsファイルを直接実行すれば良い**</color>、ということになります。以降、そのために必要な各手順の詳細を解説していきます。  
また、Node.jsは既にインストール済み（v20.10.0）として進めていきます。  

## コードの修正

まずは、`Markdown_to_html.jsx`のコードをjsファイルに変換したあと実行できるように修正します。修正後のコードを示します。

```javascript
import ReactMarkdown from 'react-markdown';
import { Typography } from '@mui/material';  // 変更点１

const H1Heading = ({ node, children }) => {
  return (
    <>
      <Typography id={node.position.start.line.toString()} gutterBottom variant="h4" component="h1" sx={{ borderBottom:"double 5px #00BB00" }} >
          {children}
      </Typography>
    </>
  )
}

// 変更点２
const require = createRequire(import.meta.url);
const fs = require('fs');
const ReactDOMServer = require('react-dom/server');
const markdownContent = fs.readFileSync('path/to/your_markdown.md', 'utf-8');
const htmlContent = ReactDOMServer.renderToStaticMarkup(
  React.createElement(ReactMarkdown, { astPlugins: [ReactMarkdown.parseHtml], components:{ h1: H1Heading } }, markdownContent)
);

// 変更点３
fs.writeFileSync('converted.html', htmlContent, 'utf-8');
```

- 変更点１  
  importの方法を変えないとNode.js上での実行時にエラーが発生するので変更します。
- 変更点２  
  マークダウンを読み込んでhtml要素に変換するためのコードを追加しています。
  `React.createElement`で`ReactMarkdown.parseHtml`を指定してマークダウンをhtmlに変換した結果を`htmlContent`に格納しています。
- 変更点３  
  ファイルとして保存するためのコードを追加しています。

## Babelのインストール、config設定

jsxはReactのコンポーネントを記述するための構文であり、<color color="red">**Node.jsで直接実行することはできません。**</color>そのため、jsxファイルをJavaScriptに変換する必要があります。今回、jsxをJavaScriptに変換するために<color color="red">**Babel**</color>というツールを使います。  
\
Babelは、フリーかつオープンソースのJavaScriptトランスコンパイラであり、主にECMAScript 2015+（ES6+）コードを古いJavaScriptエンジンで実行できる下位互換バージョンのJavaScriptに変換するために使用されます。（Wikipediaより抜粋）  
要するに、新しいバージョンのコードを古いバージョンに書き換えてくれるのがBabelです。JavaScript以外の言語やフレームワークでもバージョンが変わると記法が変わるのはご存知だと思います。そのバージョン差による違いを吸収してくれるツールと考えればよりイメージしやすいかも知れません。また、Babelは今回の主目的である<color color="red">**jsxからJavaScriptへの変換にも対応**</color>しています。  
Babelの説明はここまでにして、次はBabelのインストール方法とconfig設定を解説していきます。  
\
まず、npmを使ってBabelと関連パッケージをインストールします。  

```npm
npm install @babel/core @babel/cli @babel/preset-react
 ```

- @babel/core
  Babelの中核部分でコード変換のエンジンです。
- @babel/cli
  Babelをコマンドラインから実行するためのパッケージです。
- @babel/preset-react
  ReactのJSXを変換するためのプリセットです。

次に、config設定です。  
何度も言っていますが、今回はReactのjsxをJavaScriptに変換しますので先ほどインストールしたReact用のプリセットであるpreset-reactを使用するように設定します。  
具体的には`.babelrc`ファイルを作成し、下記の記述を追加するだけでOKです。  

```text
{
  "presets": ["@babel/preset-react"],
}
```

以上で、Babelを利用してjsxをJavaScriptに変換するための準備は完了です。

## Babelでjsxファイルをjsファイルに変換する

準備は済んでいるので、基本的には下記のコマンドを実行するだけで変換できます。  
ファイル名などは適宜設定してください。

```bash
npx babel Markdown_to_html.jsx --out-file Markdown_to_html.js
```

実行後、`Markdown_to_html.js`というファイルが作成されていれば完了です。

## Node.jsで実行

最後に、作成したJavaScriptファイルをNode.jsで直接実行します。  

```node
node Markdown_to_html.js
```

コードに問題がなければ`converted.html`というファイルが作成されているはずです。htmlファイルの中を見てみると、マークダウンがulやli、spanなど対応するhtmlに変換されていることが確認できます。  
\
ちなみに、ReactMarkdownでマークダウンがどのようにhtmlに変換されるかは下記のサイトで確認できます。  
\
[【参考】react-markdown変換例](https://spec.commonmark.org/0.30/#html-blocks)

## 最後に

本記事では、サーバ側でreact-markdownを実行しmarkdownをhtmlに変換してファイルとして保存する方法を説明しました。  
あまり需要無いような気はしますがそれ故に情報が少なかったので誰かの役に立てば幸いです。  

[webサイト](https://mochinochikimchi.com/)公開してますので、良かったら見ていってください～