@bibliotype/exporter-epub
v26.10.25-rc.1
Published
EPUB 3 导出:IR → 语义 XHTML + OPF/nav 打包,可选内嵌子集字体(零后端,浏览器与 Node 同构)- bibliotype 导出包
Readme
@bibliotype/exporter-epub
EPUB 3 导出:IR → 章节规划 → 语义 XHTML + OPF / nav → 打包为完整 .epub 字节。
零后端、浏览器与 Node 同构(不依赖 DOM 与文件系统),产物确定
(mimetype 按 OCF 规范以首条目、STORE 不压缩方式写入)。
设计基准是外部阅读器兼容(京东读书 / 微信读书 / Apple Books):导出链路内置 媒体打包、体积兜底拆分、导出前校验(epubcheck 规则子集)三项机制, 对策「自研阅读器能开、平台打不开」类缺陷。
安装
pnpm add @bibliotype/exporter-epub快速上手
import { exportEpub } from '@bibliotype/exporter-epub';
import { CLASSICAL_LAYOUT_OPTIONS } from '@bibliotype/layout';
const bytes = exportEpub(document, {
layout: CLASSICAL_LAYOUT_OPTIONS, // 缺省 DEFAULT_LAYOUT_OPTIONS
language: 'zh-Hant', // 缺省 metadata.language → 'zh-Hans'
onValidation: (problems) => { // 导出前校验(error 在前,不中断导出)
for (const p of problems) console[p.severity === 'error' ? 'error' : 'warn'](p.code, p.message);
},
});
/* 浏览器:Blob 下载 */
const blob = new Blob([bytes], { type: 'application/epub+zip' });
// const url = URL.createObjectURL(blob); → <a download="book.epub">
/* Node:直接写盘 */
// import { writeFileSync } from 'node:fs';
// writeFileSync('book.epub', bytes);选项(EpubExportOptions)
| 选项 | 说明 |
| --- | --- |
| layout | 布局选项(缺省 DEFAULT_LAYOUT_OPTIONS;古籍传 CLASSICAL_LAYOUT_OPTIONS) |
| tokens | 主题令牌表(缺省 DEFAULT_THEME;古籍传古典覆盖 + 扩展令牌) |
| fontToken | 正文字体令牌键(古籍传 FONT_TOKENS.CLASSICAL_BODY) |
| language | 语言标记(缺省 metadata.language,再缺省 zh-Hans) |
| identifier | 唯一标识符(缺省 metadata.identifiers 首项,再缺省从文档派生的确定性 URN;裸 ISBN 归一 urn:isbn:) |
| modified | dcterms:modified(ISO 8601;缺省 metadata.updatedAt / createdAt) |
| tagOverrides | 节点类型 → 标签覆盖(用于插件节点定制序列化) |
| version | OPF 版本(缺省 '3.0';京东读书等 RMSDK 显式传 '2.0') |
| maxSectionBytes | 单内容文档未压缩字节上限(缺省 256KiB) |
| validate | 导出前校验开关(缺省 true) |
| onValidation | 校验结果回调(ValidationProblem[],error 在前) |
导出链路
BookDocument
└─ planDocument(结构分组 + 锚点)─▶ sections + anchors
├─ MediaCollector(img src:data URI → OEBPS/media/*)─▶ media 条目 + src 改写
├─ splitSections(标题优先断点 + 256KiB 贪心装桶)─▶ 多内容文档
│ └─ serializeNode(layout/html,与阅读器同源)─▶ 语义 XHTML
├─ buildNavItems / buildNavXhtml / buildNcx ──▶ nav.xhtml + toc.ncx
├─ buildBookCss(layout/html,导出路径扁平化变量)─▶ style.css
├─ buildOpf ──────────────────────────────────▶ content.opf
├─ validateEpub(epubcheck 规则子集)──────────▶ onValidation
└─ buildContainerXml ─────────────────────────▶ META-INF/container.xml
fflate ▸ zipSync ──▶ .epub(Uint8Array)底层模块均可单独使用(供深度定制):planDocument / splitSections /
buildNavItems / SECTION_TYPES / DEFAULT_MAX_SECTION_BYTES(章节规划)、
MediaCollector / parseDataImageUri / sniffImageMediaType(媒体)、
validateEpub / checkWellFormedXml(校验)、
buildNavXhtml、buildOpf、renderXhtmlDocument、buildContainerXml、EPUB_MIMETYPE、
buildDefaultIdentifier / fnv1a / resolveIdentifier / normalizeIdentifier / isIsbn /
contributorRoleCode(标识符与元数据)。
古籍元数据与缺字报告(K6 / K7)
OPF 的 dc:* 区按元数据补全,缺字段不输出、不编造:
metadata.classicalCategory→ 四部 / 二级类各一条<dc:subject xml:lang="…">;metadata.classification→ 追加一条<dc:subject>(原书 / 馆藏分类号);metadata.edition→<dc:source>庚辰本,清乾隆五十六年</dc:source>;<dc:type>Text</dc:type>固定输出。
import { collectEpubGlyphProblems } from '@bibliotype/exporter-epub';
const problems = collectEpubGlyphProblems(document, {
families: ['Songti SC', 'SimSun', 'serif'],
probe: (char, family) => document.fonts.check(`12px ${family}`, char),
idsFor: (char) => idsDictionary.get(char),
});
// [{ severity: 'warning', code: 'GLYPH-IDS' | 'GLYPH-MISSING', message: '…', path: '0.2.1' }]缺字报告为 warning 级、不阻断导出;GLYPH-IDS 表示可用 IDS 合成显示,
GLYPH-MISSING 表示阅读器会显示豆腐块。完整 CNMARC / DC JSON 导出在
@bibliotype/core(toCnmarc / toDublinCore / serializeDublinCore)。
相关
- 功能参考:docs/07-export-epub.md
- HTML 序列化:docs/05-layout-and-html.md
- 仓库主页:bibliotype
