
Документы Word часто являются отправной точкой для веб-контента — статьи, спецификации продуктов и нормативные документы рано или поздно должны быть размещены на веб-сайте. Задача — преобразовать .docx в чистый HTML без серверной службы конвертации. Spire.Doc for JavaScript делает это возможным, запуская полноценный движок обработки документов на WebAssembly, читая файл Word через виртуальную файловую систему (VFS), выполняя преобразование локально и позволяя скачать полученный HTML — всё на стороне клиента, без обращения к серверу.
В рабочем процессе преобладают две стратегии экспорта, и выбор между ними — это главное решение:
- Встроенный режим объединяет CSS и изображения непосредственно в HTML-файле, создавая единый самодостаточный документ, который открывается где угодно.
- Внешний режим записывает CSS и изображения в отдельные файлы, что даёт меньший размер HTML, переиспользуемые таблицы стилей и отдельные графические ресурсы, которыми можно управлять независимо.
В этой статье рассматриваются оба подхода в проекте React и проводится их сравнение. Для настройки обратитесь к разделу Интеграция Spire.Doc for JavaScript в проект React. Примеры ниже предполагают, что Spire.Doc установлен, а модуль WebAssembly инициализирован.
Базовое преобразование: встраивание всего в один файл
Самый простой способ опубликовать документ Word как веб-страницу — создать один HTML-файл, который содержит всё — разметку, стили и изображения — в одном самодостаточном пакете. Это идеально подходит, когда нужен переносимый артефакт, который корректно отображается независимо от того, где он открыт, без ссылок на отсутствующие файлы или неработающих ссылок.
Преобразование состоит из трёх шагов. Во-первых, загрузите файл шрифта и исходный документ Word в виртуальную файловую систему WASM с помощью FetchFileToVFS. Во-вторых, создайте экземпляр Document, загрузите файл, настройте HtmlExportOptions для встраивания как CSS, так и изображений, и вызовите SaveToFile для записи HTML. В-третьих, прочитайте созданный файл из VFS, оберните его в Blob и инициируйте загрузку в браузере.
function App() {
const wordToHtml = async () => {
// Get the Spire.Doc WASM module
const docModule = window.wasmModule?.spiredoc;
// Check if the module is ready
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// Load fonts and the Word file into VFS
await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
const inputFileName = 'ToHtml.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Load the Word document
const wordDocument = new docModule.Document();
wordDocument.LoadFromFile(inputFileName);
// Embed the CSS styles into the HTML and embed images as Base64
wordDocument.HtmlExportOptions.CssStyleSheetType = docModule.CssStyleSheetType.Internal;
wordDocument.HtmlExportOptions.ImageEmbedded = true;
// Convert the document to HTML
const outputFileName = 'ToHtml-result.html';
wordDocument.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Html });
// Read the converted file from VFS and trigger download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/html;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = window.document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
// Release resources
wordDocument.Dispose();
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Convert Word To HTML</h1>
<button onClick={wordToHtml}>
Generate
</button>
</div>
);
}
export default App;
HTML-страница, созданная из документа Word с помощью SaveToFile

Параметры экспорта: отдельные CSS и изображения
Встраивание всего в один файл удобно, но у него есть компромиссы. Большой документ с множеством изображений создаёт очень большой HTML-файл, и каждая страница, использующая одинаковое оформление, несёт собственную дублирующую копию CSS. Если вы хотите централизованно управлять стилями, повторно использовать графические ресурсы на разных страницах или уменьшить размер HTML для более быстрой первоначальной отрисовки, вместо этого следует экспортировать CSS и изображения в отдельные файлы.
HtmlExportOptions предоставляет детальный контроль над тем, как записывается каждый тип ресурсов. Вы можете направить CSS в именованный файл таблицы стилей, отправлять изображения в выделенный каталог и даже управлять сериализацией полей форм. Результатом становится уже не один файл, а структура каталогов, содержащая HTML, таблицу стилей и файлы изображений.
Рабочий процесс повторяет встроенный подход с двумя дополнениями. Перед преобразованием создайте выходной каталог в VFS и используйте CssStyleSheetFileName и ImagesPath, чтобы указать Spire.Doc, куда записывать каждый тип ресурсов. После преобразования рекурсивно прочитайте весь выходной каталог, упакуйте всё в zip-архив с помощью JSZip и скачайте его одной операцией.
import JSZip from 'jszip';
function App() {
const wordToHtmlWithOptions = async () => {
// Get the Spire.Doc WASM module
const docModule = window.wasmModule?.spiredoc;
// Check if the module is ready
if (!docModule) {
alert('Spire.Doc is not ready yet');
return;
}
// Load fonts and the Word file into VFS
await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);
const inputFileName = 'ToHtml.docx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Create the output directory in VFS
const outputDirectoryName = 'ToHTMLFolder/';
window.dotnetRuntime.Module.FS.mkdirTree(outputDirectoryName);
// Load the Word document
const wordDocument = new docModule.Document();
wordDocument.LoadFromFile(inputFileName);
// Export the CSS styles to a separate file
wordDocument.HtmlExportOptions.CssStyleSheetFileName = outputDirectoryName + 'sample.css';
wordDocument.HtmlExportOptions.CssStyleSheetType = docModule.CssStyleSheetType.External;
// Export images to a separate directory
wordDocument.HtmlExportOptions.ImageEmbedded = false;
wordDocument.HtmlExportOptions.ImagesPath = outputDirectoryName + 'Demo/';
// Export form fields as plain text
wordDocument.HtmlExportOptions.IsTextInputFormFieldAsText = true;
// Convert the document to HTML
const outputFileName = 'ToHtmlExportOption-out.html';
wordDocument.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Html });
// Release resources
wordDocument.Dispose();
// Read the output directory recursively and write each level of files into the zip
const zip = new JSZip();
const addFilesToZip = async (folderPath, zipFolder) => {
let items = await window.dotnetRuntime.Module.FS.readdir(folderPath);
items = items.filter((item) => item !== '.' && item !== '..');
for (const item of items) {
const itemPath = `${folderPath}/${item}`;
try {
const fileData = await window.dotnetRuntime.Module.FS.readFile(itemPath);
zipFolder.file(item, fileData);
} catch (error) {
const zipSubFolder = zipFolder.folder(item);
await addFilesToZip(itemPath, zipSubFolder);
}
}
};
// Package the HTML file together with the resource directory
zip.file(outputFileName, window.dotnetRuntime.Module.FS.readFile(outputFileName));
await addFilesToZip(outputDirectoryName, zip);
const zipBlob = await zip.generateAsync({ type: 'blob' });
const url = URL.createObjectURL(zipBlob);
// Trigger download
const a = window.document.createElement('a');
a.href = url;
a.download = 'ToHTMLFolder.zip';
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Convert Word To HTML With Export Options</h1>
<button onClick={wordToHtmlWithOptions}>
Generate
</button>
</div>
);
}
export default App;
HTML, CSS и файлы изображений, созданные после настройки параметров экспорта

Одна деталь, которую стоит отметить: Spire.Doc не размещает изображения непосредственно в каталоге, указанном в ImagesPath. Вместо этого он создаёт подпапку external_images внутри этого каталога для хранения файлов изображений. Полученная структура выглядит как Demo/external_images/*.png, и именно поэтому addFilesToZip рекурсивно обходит дерево каталогов, а не читает плоский список файлов.
Встроенный или внешний: выбор правильной стратегии
Оба режима экспорта создают корректный HTML из одного и того же документа Word, но служат разным задачам публикации. В таблице ниже приведены ключевые различия, которые помогут вам решить, какой подход подходит для вашего рабочего процесса.
| Аспект | Встроенный (один файл) | Внешний (отдельные файлы) |
|---|---|---|
| Выходные данные | Один файл .html со встроенным CSS и изображениями Base64 |
HTML + .css + файлы изображений в каталоге |
| Размер файла | Больше — все ресурсы кодируются в Base64 и встраиваются в HTML | Меньший HTML; общий размер аналогичен, но ресурсы представлены отдельными файлами |
| Портируемость | Полностью самодостаточен; корректно открывается где угодно без зависимостей | Требует, чтобы все файлы оставались вместе; относительные пути должны быть сохранены |
| Механизм загрузки | Загрузка одного файла через Blob | Загрузка zip-архива (например, с помощью JSZip) |
| Повторное использование стилей | Каждый документ несёт собственную копию CSS | Несколько страниц могут использовать один файл таблицы стилей |
| Управление изображениями | Изображения являются строками Base64 внутри HTML; на них нельзя ссылаться или кэшировать их отдельно | Изображения — отдельные файлы, которые можно кэшировать, лениво загружать или повторно использовать |
| Скорость первоначальной отрисовки | Медленнее для больших документов — браузер должен обработать один большой файл | Быстрее первоначальный разбор HTML; CSS и изображения загружаются параллельно |
| Лучше всего подходит для | Вложений в электронные письма, разовых предпросмотров, архивных снимков, обмена одним документом | Миграции контента CMS, многостраничных публикаций, баз знаний, сайтов с общим оформлением |
| Сопровождаемость | Низкая — изменение стиля означает повторное создание всего файла | Высокая — отредактируйте CSS-файл один раз, и все связанные страницы обновятся |
Краткое руководство по выбору:
- Выбирайте встроенный режим, когда вам нужен единый портируемый артефакт — например, для создания предпросмотра, который пользователь скачивает и открывает офлайн, или для прикрепления преобразованного документа к электронному письму.
- Выбирайте внешний режим, когда вы публикуете на веб-платформе, где несколько документов используют одну и ту же систему дизайна, где вы хотите кэшировать или лениво загружать изображения, или где размер HTML-файла важен для производительности.
Часто задаваемые вопросы
Шрифты в экспортированном HTML не совпадают с исходным документом
Если шрифты в преобразованном HTML выглядят иначе, чем в исходном файле Word, причина почти всегда в отсутствии данных о шрифтах в виртуальной файловой системе WASM. Spire.Doc полагается на шрифты, загруженные в VFS, для точных расчётов макета и разрешения имён шрифтов во время преобразования. Когда требуемый шрифт недоступен, движок подставляет резервный шрифт, и объявления font-family в выходном CSS не будут соответствовать тому, что указано в исходном документе. Для документов, использующих символьные шрифты, такие как Wingdings, затронутые символы также могут отображаться как искажённый текст.
Решение простое: предварительно загрузите необходимые файлы шрифтов в VFS с помощью FetchFileToVFS перед запуском преобразования. Для документов, содержащих текст на китайском, японском или корейском языках, используйте шрифт с широким покрытием Unicode, например ARIALUNI.TTF:
await window.spire.FetchFileToVFS(
'ARIALUNI.TTF', '/Library/Fonts/', '/'
);
Экспортированный HTML теряет стили и изображения при открытии
Когда вы используете внешний режим (CssStyleSheetType.External с ImageEmbedded = false), файлы CSS и изображений записываются в отдельные места, а HTML ссылается на них через относительные пути. Если вы скачаете только HTML-файл без сопутствующих ресурсов, браузер не сможет разрешить эти пути, и страница отобразится как неоформленный простой текст с неработающими изображениями.
Чтобы избежать этого, всегда упаковывайте HTML вместе с его каталогом ресурсов — подход addFilesToZip, показанный в разделе параметров экспорта, делает это, объединяя всё в одну загрузку zip-архива. В качестве альтернативы, если вам действительно не нужны отдельные файлы ресурсов, переключитесь на встроенный режим, чтобы всё оставалось в одном самодостаточном HTML-файле:
wordDocument.HtmlExportOptions.CssStyleSheetType = docModule.CssStyleSheetType.Internal;
wordDocument.HtmlExportOptions.ImageEmbedded = true;