JavaScript로 브라우저에서 Word 문서를 HTML로 변환

2026-09-30 09:25:56 Allen Yang
AI Summarize:
ChatGPT
ChatGPT ✓
Claude ✓
Grok ✓
Perplexity ✓
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

Convert Word to HTML in the browser

Word 문서는 종종 웹 콘텐츠의 출발점입니다 — 기사, 제품 사양, 규정 준수 문서 등은 결국 웹사이트에 있어야 합니다. 백엔드 변환 서비스 없이 .docx에서 깔끔한 HTML로 변환하는 것이 과제입니다. Spire.Doc for JavaScript는 WebAssembly에서 전체 문서 처리 엔진을 실행하고, 가상 파일 시스템(VFS)을 통해 Word 파일을 읽고, 로컬에서 변환을 수행하며, 결과 HTML을 다운로드할 수 있게 함으로써 이를 가능하게 합니다 — 모두 클라이언트 측에서 서버 왕복 없이 이루어집니다.

워크플로우를 지배하는 두 가지 내보내기 전략이 있으며, 이 중에서 선택하는 것이 실제 결정입니다:

  • 내장 모드는 CSS와 이미지를 HTML 파일에 직접 묶어 어디서나 열리는 단일 자체 포함 문서를 생성합니다.
  • 외부 모드는 CSS와 이미지를 별도 파일에 기록하여 더 작은 HTML, 재사용 가능한 스타일시트, 독립적으로 관리할 수 있는 개별 이미지 자산을 제공합니다.

이 문서에서는 React 프로젝트에서 두 접근 방식을 모두 살펴보고 나란히 비교합니다. 설정에 대해서는 React 프로젝트에 Spire.Doc for JavaScript 통합을 참조하세요. 아래 예제는 Spire.Doc이 설치되어 있고 WebAssembly 모듈이 초기화되었다고 가정합니다.


기본 변환: 모든 것을 하나의 파일에 포함

Word 문서를 웹 페이지로 게시하는 가장 간단한 방법은 마크업, 스타일, 이미지 등 모든 것을 하나의 자체 포함 패키지로 포함하는 단일 HTML 파일을 생성하는 것입니다. 이는 파일 누락 참조나 깨진 링크 없이 어디서든 올바르게 렌더링되는 휴대용 아티팩트가 필요할 때 이상적입니다.

변환은 세 단계를 따릅니다. 먼저, FetchFileToVFS를 사용하여 글꼴 파일과 원본 Word 문서를 WASM 가상 파일 시스템에 로드합니다. 둘째, 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;

SaveToFile을 통해 Word 문서에서 생성된 HTML 페이지

HTML page generated from a Word document via SaveToFile


내보내기 옵션: CSS와 이미지 분리

모든 것을 하나의 파일에 포함하는 것은 편리하지만 장단점이 있습니다. 이미지가 많은 큰 문서는 매우 큰 HTML 파일을 생성하며, 동일한 스타일을 공유하는 모든 페이지는 자체 CSS 복사본을 중복으로 포함합니다. 스타일을 중앙에서 유지 관리하거나, 여러 페이지에서 이미지 자산을 재사용하거나, 초기 렌더링 속도를 위해 HTML 페이로드를 작게 유지하려면 CSS와 이미지를 별도 파일로 내보내야 합니다.

HtmlExportOptions는 각 리소스 유형이 작성되는 방식을 세밀하게 제어할 수 있습니다. CSS를 명명된 스타일시트 파일로 보내고, 이미지를 전용 디렉터리로 보내고, 양식 필드가 직렬화되는 방식까지 제어할 수 있습니다. 결과는 더 이상 단일 파일이 아니라 HTML, 스타일시트 및 이미지 파일을 포함하는 디렉터리 구조입니다.

워크플로우는 내장 접근 방식을 따르며 두 가지가 추가됩니다. 변환 전에 VFS에 출력 디렉터리를 생성하고 CssStyleSheetFileName 및 ImagesPath를 사용하여 각 리소스 유형을 어디에 작성할지 Spire.Doc에 알립니다. 변환 후에는 전체 출력 디렉터리를 재귀적으로 읽고 JSZip을 사용하여 모든 것을 zip 아카이브로 패키징한 다음 한 번의 작업으로 다운로드합니다.

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 및 이미지 파일

HTML, CSS, and image files generated after configuring the export options

주목할 만한 세부 사항: Spire.Doc은 ImagesPath로 지정된 디렉터리에 이미지를 직접 배치하지 않습니다. 대신 해당 디렉터리 안에 external_images 하위 폴더를 만들어 이미지 파일을 보관합니다. 결과 구조는 Demo/external_images/*.png와 같이 되며, 이것이 addFilesToZip이 단순 파일 목록을 읽는 대신 디렉터리 트리를 재귀적으로 순회하는 이유입니다.


내장형 vs. 외부형: 올바른 전략 선택

두 내보내기 모드 모두 동일한 Word 문서에서 유효한 HTML을 생성하지만 서로 다른 게시 요구 사항을 충족합니다. 아래 표는 주요 차이점을 요약하여 워크플로우에 맞는 접근 방식을 결정하는 데 도움을 줍니다.

항목 내장형 (단일 파일) 외부형 (개별 파일)
출력 인라인 CSS와 Base64 이미지를 포함한 하나의 .html 파일 디렉터리에 있는 HTML + .css + 이미지 파일
파일 크기 더 큼 — 모든 자산이 Base64로 인코딩되어 HTML에 포함됨 더 작은 HTML; 전체 크기는 비슷하지만 자산이 개별 파일임
이식성 완전히 독립적; 종속성 없이 어디서나 올바르게 열림 모든 파일이 함께 있어야 함; 상대 경로가 유지되어야 함
다운로드 메커니즘 Blob을 통한 단일 파일 다운로드 Zip 아카이브 다운로드 (예: JSZip 사용)
스타일 재사용 각 문서가 자체 CSS 복사본을 포함 여러 페이지가 하나의 스타일시트 파일을 공유할 수 있음
이미지 관리 이미지는 HTML 내부의 Base64 문자열임; 별도로 참조하거나 캐시할 수 없음 이미지는 캐시, 지연 로드 또는 재사용할 수 있는 개별 파일임
초기 렌더링 속도 대용량 문서의 경우 느림 — 브라우저가 하나의 큰 파일을 구문 분석해야 함 더 빠른 초기 HTML 구문 분석; CSS와 이미지가 병렬로 로드됨
최적 용도 이메일 첨부 파일, 일회성 미리보기, 보관 스냅샷, 단일 문서 공유 CMS 콘텐츠 마이그레이션, 다중 페이지 게시, 지식 기반, 공유 스타일이 있는 사이트
유지보수성 낮음 — 스타일 변경 시 전체 파일을 다시 생성해야 함 높음 — CSS 파일을 한 번 편집하면 연결된 모든 페이지가 업데이트됨

빠른 결정 가이드:

  • 단일하고 휴대 가능한 아티팩트가 필요할 때 내장형을 선택하세요 — 예를 들어 사용자가 다운로드하여 오프라인에서 열 수 있는 미리보기를 생성하거나 변환된 문서를 이메일에 첨부하는 경우입니다.
  • 여러 문서가 동일한 디자인 시스템을 공유하는 웹 플랫폼에 게시하거나, 이미지를 캐시 또는 지연 로드하려는 경우, 또는 HTML 파일 크기가 성능에 중요한 경우 외부형을 선택하세요.

자주 묻는 질문

내보낸 HTML의 글꼴이 원본 문서와 일치하지 않음

변환된 HTML의 글꼴이 원본 Word 파일과 다르게 보이는 경우, 원인은 거의 항상 WASM 가상 파일 시스템에 글꼴 데이터가 없기 때문입니다. Spire.Doc은 변환 중 정확한 레이아웃 계산과 글꼴 이름 확인을 수행하기 위해 VFS에 로드된 글꼴에 의존합니다. 필요한 글꼴을 사용할 수 없으면 엔진이 대체 글꼴을 사용하며, 출력 CSS의 font-family 선언이 원본 문서에서 지정한 것과 일치하지 않습니다. Wingdings와 같은 기호 글꼴을 사용하는 문서의 경우 영향을 받는 문자가 깨진 텍스트로 렌더링될 수도 있습니다.

해결 방법은 간단합니다: 변환을 실행하기 전에 FetchFileToVFS를 통해 필요한 글꼴 파일을 VFS에 미리 로드하세요. 중국어, 일본어 또는 한국어 텍스트가 포함된 문서의 경우 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;

참고 항목