日常のフロントエンド開発において、Word文書からのテキスト抽出は高い頻度で求められるニーズです。オンライン文書プレビュー、コンテンツ検索、書式検証、データベースへの取り込みなど、多くのシーンでこの機能が活用されます。従来のアプローチでは、ファイルをバックエンドサーバーにアップロードして処理する必要があり、帯域幅の消費やサーバー負荷が増えるだけでなく、データプライバシーの面でもリスクが伴います。
Spire.Doc for JavaScript は、まったく新しい解決策を提供します。ブラウザ上で直接 WebAssembly を利用して Word 文書の読み込みとテキスト抽出を完了し、バックエンドサービスを一切必要としません。
⚛️ 本記事では、React 技術スタックと組み合わせて、Spire.Doc for JavaScript を用いた Word 文書テキストの抽出とダウンロードの実装方法を詳しく紹介します。
1. 中核技術の原理
1.1 WASM 動作メカニズム
Spire.Doc for JavaScript は、高性能なネイティブ文書処理カーネルを WebAssembly にコンパイルし、ブラウザのサンドボックス内で実行する仕組みです。読み込みプロセスは次の 3 ステップに分かれます。
-
JS グルーコードの読み込み:
spire.doc.jsが WASM モジュールの初期化と API 公開を担当 -
WASM バイナリのコンパイル:ブラウザが
.wasmファイルをダウンロードし、ネイティブマシンコードにコンパイル - ランタイムの初期化:仮想ファイルシステム(VFS)を構築し、完全な実行環境を準備
1.2 仮想ファイルシステム(VFS)
WASM はサンドボックス内で動作するため、ローカルファイルシステムに直接アクセスできません。Spire.Doc は Emscripten が提供する FS インターフェースを介して、仮想ファイルシステムをエミュレートします。
-
FS.writeFileを呼び出して、ユーザーがアップロードしたファイルを VFS に書き込む -
FS.unlinkを呼び出して、一時ファイルをクリーンアップする - フォントファイルも VFS にプリロードする必要がある
1.3 テキスト抽出の中核 API
Document.GetText() は、プレーンテキストを抽出するための中心的なメソッドです。文書内のすべてのセクション、段落、テキストボックスを走査し、編集可能なテキストコンテンツを順番に連結し、段落構造を維持するために改行文字を保持します。
2. 環境設定とプロジェクト初期化
2.1 依存関係のインストール
まず、React プロジェクトに複数のコンポーネントを統合した Spire.Office をインストールします。
npm i spire.office
✅ この製品には無償のコミュニティ版が提供されています(利用時の制限にご注意ください)。
2.2 コアランタイムファイルの移行
インストール完了後、node_modules 内の Spire.Doc for JavaScript ランタイムファイルを React プロジェクトの public フォルダーにコピーします。
spire.doc.jsspire.doc.wasmspire.common.jsspire.common.wasm-
_frameworkフォルダー
📌 なぜ
publicディレクトリに配置するのか?
WASM の読み込みは、JavaScript メインスレッドから非同期で.wasmファイルおよび関連リソースをリクエストする必要があるためです。publicディレクトリに配置することで、ビルドツール(Webpack など)がこれらのファイルを誤って処理したりリネームしたりすることを防ぎ、process.env.PUBLIC_URL経由で正確にアクセスできるようになります。
2.3 フォントリソースの準備
ブラウザと WASM 環境にはデフォルトでシステムフォントが含まれていません。処理対象の Word 文書で特殊なフォント(Calibri、Times New Roman、中文字体など)が使用されており、VFS にそのフォントが存在しない場合、抽出されたテキストが文字化けしたり、レイアウトが崩れたりする可能性があります。
プロジェクトでよく使用するフォントファイル(例:Arial.ttf、CALIBRI.ttf、MSYH.TTC など)を public/font/ ディレクトリにまとめて配置することをお勧めします。
3. Word テキスト抽出 - React 完全実装例
以下では、React 関数コンポーネントを用いて、「ファイルアップロード → 解析・抽出 → エクスポート・ダウンロード」の全フローを実装します。
3.1 WASM モジュールの読み込み
import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
const [selectedFile, setSelectedFile] = useState(null);
const [isExtracting, setIsExtracting] = useState(false);
const [error, setError] = useState(null);
const [fontLoaded, setFontLoaded] = useState(false);
// Spire.Doc WASM モジュールを読み込む
useEffect(() => {
(async () => {
try {
const publicUrl = process.env.PUBLIC_URL || '';
const spireModule = await import(
/* webpackIgnore: true */ `${publicUrl}/spire.doc.js`
);
const rawModule = spireModule.default || spireModule;
window.wasmModule = typeof rawModule === 'function'
? await rawModule({
locateFile: (p) =>
p.endsWith('.wasm') ? `${publicUrl}/${p}` : p,
})
: rawModule;
setWasmModule(window.wasmModule);
} catch (err) {
console.error('WASM 読み込み失敗:', err);
setError('文書処理エンジンを読み込めませんでした。ページを更新して再試行してください。');
}
})();
}, []);
💡 ここでのポイントは、動的 import() を使用して spire.doc.js を読み込み、locateFile コールバックで WASM ファイルのパスを指定することです。/* webpackIgnore: true */ コメントにより、Webpack がこの動的インポートモジュールをバンドル対象にしないようにしています。
3.2 ファイル選択と状態管理
const handleFileChange = (event) => {
const file = event.target.files[0];
if (file) {
setSelectedFile(file);
setError(null);
}
};
ファイル選択ロジックはシンプルで、ユーザーがファイルを選択すると状態に格納し、以前のエラーメッセージをクリアします。
3.3 テキスト抽出コア関数
const extractTextFromUploadedFile = async () => {
if (!selectedFile) {
setError('先に Word 文書を選択してください。');
return;
}
const wasmDoc = window.wasmModule?.spiredoc;
if (!wasmDoc) {
setError('文書エンジンがまだ読み込まれていません。しばらくお待ちください。');
return;
}
setIsExtracting(true);
setError(null);
try {
// フォントのプリロード(初回のみ)
if (!fontLoaded) {
await window.spire.FetchFileToVFS(
'Arial.ttf',
'/Library/Fonts/',
`${process.env.PUBLIC_URL}/static/font/`
);
setFontLoaded(true);
}
// アップロードされたファイルを Uint8Array として読み込む
const arrayBuffer = await selectedFile.arrayBuffer();
const uint8Array = new Uint8Array(arrayBuffer);
const fileName = selectedFile.name;
// VFS に書き込む
window.dotnetRuntime.Module.FS.writeFile(fileName, uint8Array);
// Document インスタンスを作成しファイルを読み込む
const doc = new wasmDoc.Document();
doc.LoadFromFile(fileName);
// 全テキストを抽出
const documentText = doc.GetText();
// リソースを解放
doc.Dispose();
// テキストファイルをダウンロード
const blob = new Blob([documentText], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `extracted_${selectedFile.name.replace(/\.[^.]+$/, '')}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
// VFS 内の一時ファイルをクリーンアップ
window.dotnetRuntime.Module.FS.unlink(fileName);
// 状態をリセット
setSelectedFile(null);
document.getElementById('fileInput').value = '';
} catch (err) {
console.error('抽出失敗:', err);
setError(`抽出に失敗しました:${err.message || '不明なエラー'}`);
} finally {
setIsExtracting(false);
}
};
🛠️ コード解説:
-
フォントのプリロード:
FetchFileToVFSメソッドでpublic/static/font/ディレクトリ内のArial.ttfを WASM の仮想ファイルシステムに読み込み、/Library/Fonts/パスにマッピングします。 -
VFS へのファイル書き込み:
File.arrayBuffer()でファイルのバイナリデータを取得し、Uint8Arrayを構築してからFS.writeFileで WASM の仮想ファイルシステムに書き込みます。 -
Document 作成と読み込み:
Documentオブジェクトをインスタンス化し、LoadFromFileメソッドで VFS から Word 文書を読み込みます。 -
テキスト抽出:
Document.GetText()メソッドを呼び出すだけで、文書内の全テキストを取得できます。 -
リソース解放:
Dispose()メソッドを呼び出して、Document オブジェクトが占有する WASM メモリリソースを解放し、メモリリークを防止します。 - ダウンロードとクリーンアップ:抽出されたテキストを Blob オブジェクトにカプセル化し、ダウンロードリンクを作成してブラウザのダウンロードをトリガーします。ダウンロード完了後、作成した一時 URL オブジェクトを解放し、VFS から一時ファイルを削除します。
3.4 UI レンダリング
return (
<div style={{ maxWidth: '600px', margin: '50px auto', textAlign: 'center' }}>
<h1>📄 Word からテキストを抽出</h1>
<p style={{ color: '#666' }}>ローカルの .doc または .docx ファイルを選択し、全テキストコンテンツを抽出します</p>
<div style={{ margin: '30px 0' }}>
<input
id="fileInput"
type="file"
accept=".doc,.docx"
onChange={handleFileChange}
disabled={!wasmModule || isExtracting}
style={{ display: 'none' }}
/>
<label
htmlFor="fileInput"
style={{
display: 'inline-block',
padding: '10px 20px',
background: '#f0f0f0',
borderRadius: '4px',
cursor: 'pointer',
border: '1px solid #ccc',
}}
>
{selectedFile ? `選択中:${selectedFile.name}` : 'Word 文書を選択'}
</label>
</div>
{selectedFile && (
<button
onClick={extractTextFromUploadedFile}
disabled={!wasmModule || isExtracting}
style={{
padding: '12px 30px',
fontSize: '16px',
backgroundColor: '#007bff',
color: '#fff',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
marginTop: '10px',
}}
>
{isExtracting ? '抽出中...' : '抽出してテキストをダウンロード'}
</button>
)}
{error && (
<div style={{ marginTop: '20px', color: '#d32f2f', background: '#ffebee', padding: '10px', borderRadius: '4px' }}>
{error}
</div>
)}
{!wasmModule && !error && (
<div style={{ marginTop: '20px', color: '#888' }}>⏳ 文書エンジンを読み込み中、しばらくお待ちください...</div>
)}
</div>
);
}
export default App;
UI 部分では、ファイル選択、読み込み状態、エラーメッセージ、エンジン読み込み進捗など、ユーザーに対する完全なインタラクションフィードバックを提供します。
3.5 ▶️ 開発サーバーの起動
上記の完全な App コンポーネントコードを src/App.js ファイルにコピーして保存します。プロジェクトルートで次のコマンドを実行します。
npm start
このコマンドで React 開発サーバーが起動し、デフォルトで http://localhost:3000 でアプリケーションが開きます。
4. 応用テクニック - 特定の段落やセクションのテキストを抽出する
文書全体のテキストを抽出する必要がない場合は、より細かい API を使用できます。
const doc = new wasmDoc.Document();
doc.LoadFromFile(fileName);
// 最初のセクションを取得
const section = doc.Sections.get_Item(0);
// そのセクションの最初の段落を取得
const paragraph = section.Paragraphs.get_Item(0);
// その段落のテキストを抽出
const text = paragraph.Text;
5. まとめ
以上の例を通じて、ブラウザ側で Word 文書処理機能を実装し、フロントエンドでのテキスト抽出がバックエンドサービスに依存しないようにすることができました。本記事では、React 環境での実装計画を詳細に分解し、WASM 初期化、仮想ファイルシステム操作、リソース解放、例外処理まで、本番環境で必要となるあらゆる詳細を網羅しています。
Spire.Doc for JavaScript がサポートする Word 文書形式は、Word 97-2003 から Word 2019 までの全バージョンをカバーし、DOC/DOCX ファイルを TXT、HTML、PDF、画像など多様な形式に変換することも可能です。

