dom-docx: HTML 转原生可编辑 Word 文档

dom-docx: HTML 转原生可编辑 Word 文档

概述

dom-docx 是一个 TypeScript 库,旨在将语义化 HTML 片段转换为原生、可编辑的 Word 文档 (OOXML)。与生成截图或布局技巧的工具不同,dom-docx 生成真正的 Word 结构——段落、运行、列表和表格——确保生成的文档在 Microsoft Word 和 LibreOffice 中完全可编辑。

核心能力

支持的 HTML 元素

在其默认的 inline 模式下,该库支持广泛的语义化 HTML:

  • 文本与结构:标题、段落、列表 (<ul>, <ol>) 和引用块。
  • 格式化:行内格式 (<strong>, <em>)、链接和水平线 (<hr>)。
  • 引用与布局:数据表格、阴影提示框和简单的 flex 行(最多 4 个项目)。
  • 视觉效果data: 图像和低复杂度的行内 SVG(特别是条形图和文本)。

高级渲染选项

根据对样式和复杂度的不同需求,dom-docx 提供三种不同的转换路径:

  1. 行内样式解析 (styleSource: "inline"):默认的纯 JavaScript 路径。它直接解析 style="" 属性,且不需要浏览器环境。
  2. 计算样式解析 (styleSource: "computed"):使用 getComputedStyle 解析 <style> 块、类和 ID 选择器。
    • 在 Node.js 中:需要 Playwright 和 Chromium 来进行无头渲染。
    • 在浏览器中:使用用户标签页的实时 DOM,无需额外安装。
  3. 光栅化 (rasterizeInPlace):在转换前将 <canvas> 和复杂的 <svg>(例如 Highcharts)转换为 PNG 图像。对于复杂的图表,建议使用 scale: 2 以获得高密度输出。

技术架构

转换流水线

该库通过三个阶段将 HTML 映射到 OOXML:

  1. 样式解析:通过行内属性或浏览器计算样式确定最终样式。
  2. 访问者模式 (Visitor Pattern):通过 Cheerio 遍历,将 HTML 元素转换为 docx 段落、表格、编号和超链接。
  3. 打包与修补 (Pack & Patch):生成 OOXML 并应用修补程序,以确保列表编号和阴影块对齐在 Word 和 LibreOffice PDF 导出时保持一致。

通过视觉回归进行质量保证

作者使用“Autoresearch”模式开发 dom-docx——这是一个通过迭代不断提高保真度的自主循环。该过程包括:

  • 在 Chromium 中渲染 HTML。
  • 通过 dom-docx 将 HTML 转换为 .docx
  • 使用 LibreOffice 将 .docx 文件光栅化。
  • 将浏览器截图与 LibreOffice 截图进行对比,从而为布局保真度、可编辑性和速度评分。

该循环针对 37 种真实的 HTML 模式运行,以确保与人类质量评分具有高度一致性。

集成与使用

安装

npm install dom-docx

注意:需要 Node.js ≥ 20。Playwright 是一个可选的同级依赖,仅在 Node 中用于计算样式或光栅化。

快速入门示例

浏览器使用 (纯 JS,无需 Playwright):

import { convertHtmlToDocx } from "dom-docx/browser";

const html = `<h1 style="color:#1a1a2e">Quarterly Report</h1><p>Revenue grew <strong>12%</strong> year over year.</p>`;
const blob = await convertHtmlToDocx(html);
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "output.docx";
a.click();

Node.js 使用:

import { writeFile } from "node:fs/promises";
import { convertHtmlToDocx } from "dom-docx";

const html = `<h1 style="color:#1a1a2e">Quarterly Report</h1><p>Revenue grew <strong>12%</strong> year over year`;
const docx = await convertHtmlToDocx(html);
await writeFile("output.docx", docx);

命令行工具 (CLI)

无需编写代码即可进行快速转换,该库提供了一个 CLI:

npx dom-docx input.html -o output.docx

局限性

在 0.1.x 版本中,以下功能暂不支持

  • inline 路径下的外部样式表。
  • Web 字体、CSS grid、浮动布局和绝对定位。
  • 表单、<dl> 和表格 rowspan
  • 复杂的 SVG 路径和渐变(除非使用 rasterizeInPlace)。
  • 无法保证多页布局保真度,或针对首页/偶数页的特定页眉/页脚变体。

Sources