{"_id":"@blade-demon/docx-to-html","name":"@blade-demon/docx-to-html","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@blade-demon/docx-to-html","version":"1.0.0","description":"Convert Word .docx to mobile H5 HTML — mammoth + style map + anchor fix + MCP server","type":"module","exports":{".":"./src/convert.js"},"bin":{"docx-to-html":"src/cli.js","docx-to-html-mcp":"src/mcp.js"},"scripts":{"build":"node src/cli.js samples/input.docx dist/output.html","build:sample":"node src/build-sample-docx.js && npm run build"},"dependencies":{"@modelcontextprotocol/sdk":"^1.0.0","cheerio":"^1.0.0","mammoth":"^1.8.0"},"devDependencies":{"docx":"^9.0.0"},"_id":"@blade-demon/docx-to-html@1.0.0","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-+vJJeOB7hR7T03C2Hq8Zt2ay09q9T5A/OXwnCrHTyVwpMmLj3SNR1so7LF9YocMhZbrtZWTz1yFtg7Mt6/j1QA==","shasum":"72780f3310cf6820466ca5c60d95ae362a72738c","tarball":"https://registry.npmjs.org/@blade-demon/docx-to-html/-/docx-to-html-1.0.0.tgz","fileCount":12,"unpackedSize":58104,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDOnqjy8ywuFYIXCvWYDUM14j7YOvawOzTfraQk0bPpSQIgSeVQlyeP+Jo6IM6sxOxNCMpGh2s6u9wU3TlnAQcfBIg="}]},"_npmUser":{"name":"blade-demon","email":"xuziwei89@gmail.com"},"directories":{},"maintainers":[{"name":"blade-demon","email":"xuziwei89@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/docx-to-html_1.0.0_1778920807076_0.6456728257772577"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-16T08:40:07.017Z","1.0.0":"2026-05-16T08:40:07.215Z","modified":"2026-05-16T08:40:07.389Z"},"maintainers":[{"name":"blade-demon","email":"xuziwei89@gmail.com"}],"description":"Convert Word .docx to mobile H5 HTML — mammoth + style map + anchor fix + MCP server","readme":"# docx-to-h5\n\n把 Word `.docx` 文档转成移动端可直接渲染的 H5 页面。\n基于 **mammoth + 自定义 style map + 锚点修复 + DOM 后处理 + 移动端 CSS** 的完整管线。\n\n适用场景：内容运营、隐私政策、用户协议、长说明文档等\"语义化为主、不要求像素级保真\"的转换。\n\n---\n\n## 工程结构\n\n```\ndocx-to-h5/\n├─ package.json\n├─ src/\n│  ├─ cli.js              # CLI 入口\n│  ├─ convert.js          # 主转换管线：mammoth -> 锚点修复 -> 后处理 -> 套模板\n│  ├─ style-map.js        # Word 样式 -> 带 class 的 HTML 标签映射表\n│  ├─ fix-anchors.js      # 锚点修复：补齐缺失的 heading id\n│  ├─ post-process.js     # DOM 后处理：外链 target/rel、表格滚动、空段去除\n│  ├─ build-sample-docx.py# 生成测试样张 docx（Python，避开容器 npm 限制）\n│  └─ _shims.js           # ⚠️ 仅 demo 用，生产环境删掉，改用真实 mammoth/cheerio\n├─ styles/\n│  └─ mobile.css          # 移动端 CSS（mobile-first，含强调块/表格滚动/锚点偏移）\n├─ samples/\n│  └─ input.docx          # 样张\n└─ dist/\n   └─ output.html         # 转换产物\n```\n\n---\n\n## 快速开始（生产）\n\n```bash\nnpm install mammoth cheerio\nnode src/cli.js path/to/doc.docx dist/output.html --title \"你的标题\"\n```\n\nCLI 选项：\n- `--css <path>`：使用自定义 CSS 文件（默认 `styles/mobile.css`）\n- `--title <title>`：HTML 页面 `<title>` 标签内容\n\n---\n\n## 容器内 demo（无 npm 环境）\n\n`src/_shims.js` 是 mammoth 和 cheerio 的**最小子集实现**，用 Node 内置能力实现，\n仅用于在没有 npm 的环境里证明管线跑得通。它不完整，**生产环境必须替换**。\n\n```bash\npython3 src/build-sample-docx.py   # 用 python-docx 造样张\nnode src/cli.js samples/input.docx dist/output.html\n```\n\n迁回生产时：\n1. `npm install mammoth cheerio`\n2. 删除 `src/_shims.js`\n3. 把 `convert.js`、`fix-anchors.js`、`post-process.js` 里的 import 改回 `'mammoth'` / `'cheerio'`\n   （文件里都用 `🚀 生产环境：` 注释标记了原版语句）\n4. `convert.js` 里被注释掉的 `convertImage` 块需要恢复，用于处理图片\n\n---\n\n## 四个核心模块\n\n### 1. style-map.js — 样式映射的契约\n\nmammoth 的核心能力是**把 Word 样式名（如 \"Heading 1\"、\"Emphasis Block\"）映射到带 class 的 HTML 标签**。\n关键约束：**Word 文档里必须真的用了这些命名样式**，不是手工调字号字色拼出来的\"视觉假标题\"。\n\n```js\n\"p[style-name='Heading 1'] => h1.doc-h1:fresh\"\n\"p[style-name='Emphasis Block'] => p.emphasis-block:fresh\"\n\"table => table.doc-table\"\n```\n\n`:fresh` 表示\"不要把连续同样式段落合并成一个标签\"，列表/标题尤其需要。\n\n### 2. fix-anchors.js — 锚点修复\n\n文档内跳转（如目录里的\"#一\"跳到\"一、定义\"章节）有两种实现：\n- **正规做法**：Word 里插 bookmark，mammoth 自动输出 `<a id=\"...\">`\n- **偷懒做法**：直接打字写\"#一\"，对应正文里没有 bookmark，跳转就死链\n\n我们的兜底策略：扫描所有 `<a href=\"#xxx\">`，对缺失的 id，用文字匹配从 heading 里反向查找并补上。\n匹配规则：归一化标点和空格后，比较 heading 文本是否以 anchor id 开头。\n\n### 3. post-process.js — DOM 后处理\n\nstyle map 解决不了的 DOM 层调整：\n\n- 外链统一加 `target=\"_blank\" rel=\"noopener noreferrer\"`（H5 webview 必备）\n- 表格外层包 `<div class=\"table-scroll\">`（移动端横向滚动）\n- 去除 mammoth 偶尔产出的空段落\n- 图片加 `loading=\"lazy\"` 和默认 `alt`\n\n### 4. mobile.css — 视觉规范\n\nmobile-first，rem 排版，对齐主流金融类 H5 隐私政策页的视觉风格。\n通过 CSS 变量定义颜色 token，便于主题化。\n`scroll-margin-top` 解决锚点跳转在固定 header 下的偏移问题。\n\n---\n\n## 工程化建议\n\n1. **构建期转换，不要运行时**：隐私政策更新频率低，CI 跑一次输出静态 HTML，\n   前端只负责套壳渲染。性能最优，且转换问题在 CI 阶段就发现。\n\n2. **图片单独处理**：生产里把 `convertImage` 改成上传 OSS，返回 URL 而不是 base64。\n   长文档全 base64 会让 HTML 暴涨到几 MB。\n\n3. **样式审计契约**：和内容方约定 Word 样式白名单（H1-H4、List、Quote、Emphasis Block、\n   Warning Block），加到 style-map.js 里。文档作者必须用样式而非手工字号。\n\n4. **mammoth messages 接到 CI**：mammoth 转换会输出 `messages` 数组，\n   含 unrecognized style 警告。CI 里把这些 message 输出当 lint 看，\n   出现新样式名就要么加映射要么修文档。\n\n5. **回归测试**：固定一批典型样张作 snapshot，每次升级 mammoth 或改 style-map 都跑一遍 diff。\n\n---\n\n## 已知限制（mammoth 通用）\n\nmammoth 是语义化方案，下列内容不能很好支持：\n- 文本框、文字方向、艺术字\n- 公式（可用 MathJax 后处理）\n- 页眉页脚、分栏布局\n- 表格合并单元格的边框样式\n\n如果这些是核心需求，考虑 LibreOffice headless 或 Aspose.Words（见前置方案对比）。\n","readmeFilename":"README.md","_rev":"1-849dd907213ddcd88abbb7745d5d4f60"}