JavaScriptによるReactでのWord文書とMarkdownの相互変換

現代のWeb開発の世界では、Reactはユーザーインターフェース構築のための主要なライブラリとして、さまざまなデータの変換や表示タスクを扱う必要があります。Word文書とMarkdownファイルを相互に変換する能力は、ユーザー体験を向上させるだけでなく、コンテンツ管理の効率を大幅に高めます。この変換機能は、コンテンツの頻繁な更新や共同編集が求められるプラットフォームにとって特に重要です。例えば、ブログ、技術文書サイト、オンライン教育プラットフォームなどが挙げられます。Reactアプリケーション内でこの機能を直接実現することで、開発者はユーザーに対してよりシームレスな編集体験を提供できます。これにより、可視化された編集ツールを使用するユーザーも、純粋なテキストエディタを好むユーザーも、簡単にコンテンツを投稿できるようになります。

本記事では、**ReactでJavaScriptを使用してWord文書とMarkdownの相互変換を実現する方法**について紹介します。

- JavaScriptでWord文書をMarkdownに変換
- JavaScriptでMarkdownをWord文書に変換

本記事で使用する方法には、[Spire.Doc for JavaScript](https://www.e-iceblue.com/Introduce/doc-for-javascript.html)を使用します。npmパッケージは`npm i spire.doc`です。

## JavaScriptでWord文書をMarkdownに変換
Spire.Doc for JavaScriptは、WebAssemblyモジュールを提供しており、このモジュールを使用するとVFS（仮想ファイルシステム）からWord文書をロードし、それをMarkdown形式に変換できます。文書をVFSに取得し、`Document.LoadFromFile()`メソッドを使用してロードし、`Document.SaveToFile()`メソッドでMarkdownとして保存することで、この変換を実現できます。具体的な手順は以下の通りです：

1. `Spire.Doc.Base.js`ファイルを読み込んでWebAssemblyモジュールを初期化します。
2. `wasmModule.FetchFileToVFS()`メソッドを使って、Word文書を仮想ファイルシステムにロードします。
3. `wasmModule.Document.Create()`メソッドを使って、WebAssemblyモジュール内で`Document`インスタンスを作成します。
4. `Document.LoadFromFile()`メソッドを使用して、Word文書を`Document`インスタンスに読み込みます。
5. 文書をMarkdown形式に変換し、`Document.SaveToFile()`メソッドを使って、VFSに保存します。
6. ファイルを読み込んでダウンロードするか、必要に応じてファイルを使用します。

**コード例**
```js
import React, { useState, useEffect } from 'react';

function App() {

  // ロードされたWASMモジュールを保存するための状態
  const [wasmModule, setWasmModule] = useState(null);

  // コンポーネントがマウントされたときにWASMモジュールをロードするuseEffectフック
  useEffect(() => {
    const loadWasm = async () => {
      try {
        // グローバルなwindowオブジェクトからModuleとspiredocを取得
        const { Module, spiredoc } = window;

        // ランタイムが初期化されたときにwasmModule状態を設定
        Module.onRuntimeInitialized = () => {
          setWasmModule(spiredoc);
        };
      } catch (err) {
        // モジュールのロード中に発生したエラーをログに出力
        console.error('WASMモジュールのロードに失敗しました:', err);
      }
    };

    // WASM JavaScriptファイルをロードするためのscript要素を作成
    const script = document.createElement('script');
    script.src = `${process.env.PUBLIC_URL}/Spire.Doc.Base.js`;
    script.onload = loadWasm;

    // スクリプトをドキュメントのボディに追加
    document.body.appendChild(script);

    // コンポーネントがアンマウントされたときにスクリプトを削除するクリーンアップ関数
    return () => {
      document.body.removeChild(script);
    };
  }, []);

  // Word文書をMarkdownに変換する関数
  const ConvertHTMLStringToPDF = async () => {
    if (wasmModule) {
      // 出力ファイル名を指定
      const inputFileName = 'Sample.docx';
      const outputFileName = 'WordToMarkdown.md';

      // フォントファイルを取得してVFSに追加
      await wasmModule.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/`);

      // Documentクラスのインスタンスを作成
      const doc = wasmModule.Document.Create();

      // Word文書をロード
      doc.LoadFromFile(inputFileName);

      // 文書をMarkdownファイルとして保存
      doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Markdown });

      // リソースを解放
      doc.Dispose();

      // Markdownファイルを読み取る
      const mdContent = await wasmModule.FS.readFile(outputFileName);

      // MarkdownファイルからBlobを生成し、ダウンロードをトリガー
      const blob = new Blob([mdContent], { type: 'text/plain' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = outputFileName;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }
  };

  return (
      <div style={{ textAlign: 'center', height: '300px' }}>
        <h1>ReactでJavaScriptを使用してWord文書をMarkdownに変換する</h1>
        <button onClick={ConvertHTMLStringToPDF} disabled={!wasmModule}>
          変換してダウンロード
        </button>
      </div>
  );
}

export default App;
```

結果
![2025-02-12_171253.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/cdd2c7a7-6adc-4eb2-92c3-c466e7885d0f.png)

## JavaScriptでMarkdownをWord文書に変換
`Document.LoadFromFile()`メソッドは、ファイル形式パラメータを`wasmModule.FileFormat.Markdown`に設定することでMarkdownファイルをロードすることができます。その後、`Document.SaveToFile()`メソッドを使用してMarkdownファイルをWord文書としてエクスポートします。
Markdown文字列の場合は、`wasmModule.FS.writeFile()`メソッドを使用してMarkdownコンテンツを仮想ファイルシステムに書き込み、Word文書として変換します。
手順は以下の通りです：

1. `Spire.Doc.Base.js`ファイルを読み込んでWebAssemblyモジュールを初期化します。
2. `wasmModule.FetchFileToVFS()`メソッドを使って、必要なフォントファイルを仮想ファイルシステムにロードします。
3. Markdownコンテンツをインポートします：
    - ファイルの場合：`wasmModule.FetchFileToVFS()`メソッドを使ってMarkdownファイルをVFSにロードします。
    - 文字列の場合：`wasmModule.FS.writeFile()`メソッドを使ってMarkdownコンテンツをVFSに書き込みます。
4. WebAssemblyモジュール内で`wasmModule.Document.Create()`メソッドを使って`Document`インスタンスを作成します。
5. `Document.LoadFromFile({ filename: string, fileFormat: wasmModule.FileFormat.Markdown })`メソッドを使ってMarkdownファイルを`Document`インスタンスにロードします。
6. MarkdownファイルをWord文書に変換し、`Document.SaveToFile({ filename: string, fileFormat: wasmModule.FileFormat.Docx2019 })`メソッドを使ってVFSに保存します。
7. VFSから生成されたWordファイルを取得してダウンロードするか、必要に応じてさらに処理します。

**コード例**
```js
import React, { useState, useEffect } from 'react';

function App() {

  // ロードされたWASMモジュールを保存するための状態
  const [wasmModule, setWasmModule] = useState(null);

  // コンポーネントがマウントされたときにWASMモジュールをロードするuseEffectフック
  useEffect(() => {
    const loadWasm = async () => {
      try {
        // グローバルなwindowオブジェクトからModuleとspiredocを取得
        const { Module, spiredoc } = window;

        // ランタイムが初期化されたときにwasmModule状態を設定
        Module.onRuntimeInitialized = () => {
          setWasmModule(spiredoc);
        };
      } catch (err) {
        // モジュールのロード中に発生したエラーをログに出力
        console.error('WASMモジュールのロードに失敗しました:', err);
      }
    };

    // WASM JavaScriptファイルをロードするためのscript要素を作成
    const script = document.createElement('script');
    script.src = `${process.env.PUBLIC_URL}/Spire.Doc.Base.js`;
    script.onload = loadWasm;

    // スクリプトをドキュメントのボディに追加
    document.body.appendChild(script);

    // コンポーネントがアンマウントされたときにスクリプトを削除するクリーンアップ関数
    return () => {
      document.body.removeChild(script);
    };
  }, []);

  // MarkdownをWordに変換する関数
  const ConvertHTMLStringToPDF = async () => {
    if (wasmModule) {
      // 出力ファイル名を指定
      const outputFileName = 'MarkdownStringToWord.docx';

      // 必要なフォントファイルをVFSに追加
      await wasmModule.FetchFileToVFS('Arial.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/`);

      // 新しいDocumentインスタンスを作成
      const doc = wasmModule.Document.Create();

      // MarkdownファイルをVFSから取得してDocumentインスタンスに読み込む
      // await wasmModule.FetchFileToVFS('MarkdownExample.md', '', `${process.env.PUBLIC_URL}/`);
      // doc.LoadFromFile({ fileName: 'MarkdownExample.md', fileFormat: wasmModule.FileFormat.Markdown });

      // Markdown文字列を定義
      const markdownString = '# Project Aurora: Next-Gen Climate Modeling System *\n' +
          '## Overview\n' +
          'A next-generation climate modeling platform leveraging AI to predict regional climate patterns with 90%+ accuracy. Built for researchers and policymakers.\n' +
          '### Key Features\n' +
          '- * Real-time atmospheric pattern recognition\n' +
          '- * Carbon sequestration impact modeling\n' +
          '- * Custom scenario simulation builder\n' +
          '- * Historical climate data cross-analysis\n' +
          '\n' +
          '## Sample Usage\n' +
          '| Command | Description | Example Output |\n' +
          '|---------|-------------|----------------|\n' +
          '| `region=asia` | Runs climate simulation for Asia | JSON with temperature/precipitation predictions |\n' +
          '| `model=co2` | Generates CO2 impact visualization | Interactive 3D heatmap |\n' +
          '| `year=2050` | Compares scenarios for 2050 | Tabular data with Δ values |\n' +
          '| `format=netcdf` | Exports data in NetCDF format | .nc file with metadata |';

      // Markdown文字列をVFSのファイルに書き込む
      await wasmModule.FS.writeFile('Markdown.md', markdownString, { encoding: 'utf8' });

      // VFSからMarkdownファイルを読み込み
      doc.LoadFromFile({ fileName: 'Markdown.md', fileFormat: wasmModule.FileFormat.Markdown });

      // 文書をWordファイルとして保存
      doc.SaveToFile({ fileName: outputFileName, fileFormat: wasmModule.FileFormat.Docx2019 });

      // リソースを解放
      doc.Dispose();

      // Wordファイルを読み取る
      const outputWordFile = await wasmModule.FS.readFile(outputFileName);

      // WordファイルからBlobを生成し、ダウンロードをトリガー
      const blob = new Blob([outputWordFile], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = outputFileName;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }
  };

  return (
      <div style={{ textAlign: 'center', height: '300px' }}>
        <h1>ReactでJavaScriptを使用してMarkdownをWordに変換する</h1>
        <button onClick={ConvertHTMLStringToPDF} disabled={!wasmModule}>
          変換してダウンロード
        </button>
      </div>
  );
}

export default App;
``
結果
![2025-02-12_180158.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/d8fda630-6010-473b-8a36-0dbcd3fcac66.png)

本記事では、JavaScriptを使用してReact内でWord文書をMarkdownに変換し、またMarkdownをWord文書に変換する方法を紹介しました。