Skip to content

Repository files navigation

epub.ts (@likecoin/epub-ts)

CI npm License

Drop-in replacement for epubjs — same API, fully typed, 1 runtime dependency, actively maintained.

A complete TypeScript rewrite of epubjs v0.3.93 with strict mode, modern tooling, and ongoing bug fixes — without breaking your existing code.

What you get

  • Same API, zero migration cost — change one import line and everything works
  • Full TypeScript strict mode — generated .d.ts from source, so autocomplete matches runtime
  • 1 runtime dependency (jszip) — smaller bundle, simpler supply chain
  • 970+ tests across 40 files — Vitest with robust coverage
  • Vite build — ESM, CJS, and UMD outputs out of the box
  • Node.js support@likecoin/epub-ts/node parses EPUBs server-side with linkedom
  • Active maintenance20+ bug fixes and counting

Note: Built at 3ook.com and provided as-is. Forked from epubjs v0.3.93 by Fred Chasen / FuturePress.

Performance

Head-to-head numbers on two Project Gutenberg fixtures: a small book (Alice in Wonderland #11, 185 KB) and a large book (War and Peace #2600, 1.7 MB). Apple M4 Pro, macOS 26.4, headless Chrome 146, Node 20, median of 10–15 iterations. Run the bench yourself with npm run bench; see bench/README.md for full methodology and caveats.

Metric epubjs 0.3.93 @likecoin/epub-ts Δ
Bundle size (gzip, KB) 132.8 57.5 −56.7%
Alice (185 KB)
Cold parse (ms) 2.2 2.2 ≈ 0
First display (ms) 96.8 83.4 −13.8%
locations.generate(1000) (ms) 1760.3 10.4 −99.4%
currentLocation() (ms / call) 0.106 0.060 −43.8%
War and Peace (1.7 MB)
Cold parse (ms) 11.7 7.9 −33.1%
First display (ms) 90.1 91.9 ≈ 0
locations.generate(1000) (ms) 42903.3 158.9 −99.6%
currentLocation() (ms / call) 0.196 0.153 −22.1%

43 seconds → 159 ms on locations.generate() for a 1.7 MB book: this is the single biggest user-visible win, and it's what the 0.4.9 locations optimization was aimed at. Both libraries produce the same output count (169 locations for Alice, 429 for War and Peace) — the delta is real work, not a short-circuit.

currentLocation() — the pagination / CFI-range query called on every page turn — exercises the 0.6.0 canvas text measurement and 0.6.1 Mapping.findStart/findEnd binary search and is roughly 2× faster as a result. next-page timings are omitted from the table because both libraries converge on a frame-paced ~33 ms, which doesn't differentiate them.

Get started

Install

npm install @likecoin/epub-ts

Migrate from epubjs

Change one line — everything else stays the same:

- import ePub from "epubjs";
+ import ePub from "@likecoin/epub-ts";

Render an EPUB (browser)

import ePub from "@likecoin/epub-ts";

const book = ePub("/path/to/book.epub");
const rendition = book.renderTo("viewer", { width: 600, height: 400 });
rendition.display();

Load from file input

import ePub from "@likecoin/epub-ts";

const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener("change", async (event) => {
	const file = event.target.files[0];
	const data = await file.arrayBuffer();
	const book = ePub(data);
	const rendition = book.renderTo("viewer", { width: 600, height: 400 });
	rendition.display();
});

Use with a <script> tag (UMD / WebView)

For environments without a bundler — a plain HTML page, or a react-native-webview loading local files — use the UMD build. It exposes a global ePub and expects JSZip to be loaded first, mirroring the classic epubjs drop-in:

<script src="jszip.min.js"></script>
<script src="epub.umd.js"></script>
<script>
	const book = ePub("book.epub");
	const rendition = book.renderTo("viewer", { width: 600, height: 400 });
	rendition.display();
</script>

The bundle lives at dist/epub.umd.js — copy it locally, or load it from a CDN via https://unpkg.com/@likecoin/epub-ts/dist/epub.umd.js. In a bundler, prefer the standard entrypoint instead, which resolves to the ES module build: import ePub from "@likecoin/epub-ts".

Loading a book from a file:// URL (e.g. a local .epub bundled into a WebView) is supported: fetch can't read the file: scheme, so such requests fall back to XMLHttpRequest. The host must grant file access (on Android WebView, enable allowFileAccess / allowFileAccessFromFileURLs). Alternatively, read the file yourself and hand epub.ts an ArrayBufferePub(arrayBuffer) skips the network entirely and works everywhere.

Parse on Node.js (no browser needed)

Extract metadata, table of contents, and chapter HTML server-side. Requires linkedom:

npm install linkedom
import { Book } from "@likecoin/epub-ts/node";
import { readFileSync } from "node:fs";

const data = readFileSync("book.epub");
const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
const book = new Book(arrayBuffer);
await book.opened;

console.log(book.packaging.metadata.title);
console.log(book.navigation.toc.map(item => item.label));

const section = book.spine.first();
const html = await section.render(book.archive.request.bind(book.archive));

Show page numbers in the table of contents

locations.locationFromHref() maps a navigation href to a generated location index, so a table of contents can show approximate page numbers:

await book.locations.generate(1000); // ~1000 characters per page

const toc = book.navigation.toc.map(item => {
	const index = book.locations.locationFromHref(item.href);
	return { ...item, page: index === -1 ? undefined : index + 1 };
});

Notes:

  • The index is 0-based, so add 1 for a page number. It returns -1 when the href cannot be resolved.
  • Page numbers depend on the chars value passed to generate() — they are estimates for navigation, not the publisher's printed pages. When a book ships a real page-list, use book.pageList instead.
  • Entries are resolved per section, so two entries pointing into the same file (chapter.xhtml#a and chapter.xhtml#b) share a page number.
  • Pre-paginated (fixed-layout) books resolve without calling generate() — each section is exactly one page, so the spine index is returned. Once locations exist they take precedence, so the result is always an index into locations.

Named exports

import {
	Book, EpubCFI, Rendition, Contents, Layout,
	Section, Spine, Locations, Navigation, PageList,
	Resources, Packaging, Archive, Store,
	Annotations, Themes, Mapping,
} from "@likecoin/epub-ts";

API reference

Full documentation: likecoin.github.io/epub.ts

Class What it does
Book Load, parse, and manipulate an EPUB
Rendition Render a book into a DOM element
Contents Manage content inside an iframe
EpubCFI Parse EPUB Canonical Fragment Identifiers
Locations Generate and query reading positions
Navigation Table of contents and landmarks
Annotations Highlights, underlines, and marks

Supported environments

Environment Import Notes
Modern browsers @likecoin/epub-ts Chrome 80+, Edge 80+, Firefox 74+, Safari 13.4+ (ES2020, Q1 2020)
Insecure contexts @likecoin/epub-ts http:// intranet and file:// deployments supported — runtime APIs gated behind secure contexts (crypto.randomUUID) are feature-detected with fallbacks
Vite / webpack @likecoin/epub-ts ESM or CJS
<script> tag / WebView dist/epub.umd.js UMD global ePub; load JSZip first. Reads file:// books via XHR fallback
Node.js 18+ @likecoin/epub-ts/node Parsing only (no rendering); requires linkedom peer dep

Development

git clone https://github.com/likecoin/epub.ts.git
cd epub.ts
npm install
Script Description
npm run build Vite library build → dist/
npm test Run tests (Vitest)
npm run test:watch Run tests in watch mode
npm run typecheck tsc --noEmit
npm run lint ESLint
npm run lint:fix ESLint with auto-fix
npm run docs Generate API docs (HTML + Markdown)

Requires Node.js 18+ and npm 9+.

Security

EPUBs are untrusted input. Sections render in a sandboxed iframe with scripts disabled by default; see SECURITY.md for the threat model, the cost of allowScriptedContent: true, and how to report a vulnerability.

Contributing

See PROJECT_STATUS.md for current status and what to work on.

For AI agents contributing to this project, see AGENTS.md.

License

BSD-2-Clause (same as epubjs)

Acknowledgments

Built by 3ook.com

3ook is a Web3 eBook platform where authors publish EPUB ebooks and readers collect them as digital assets.

Related projects

  • epubjs — Original EPUB reader library
  • epubcheck-ts — TypeScript EPUB validator (also by 3ook.com)

About

A TypeScript fork of epubjs — parse and render EPUB documents in the browser.

Topics

Resources

Security policy

Stars

21 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages