chore: vendor foliate-js

foliate-js has no npm release and no build step; upstream recommends a git
submodule. Copy it instead: this repo has no submodules and already vendors
pdf.js the same way under static/pdfjs, and a submodule would pull in 231
files / 13 MB of which 191 files / 12 MB is a bundled pdf.js build that
Chitai does not use.

Only the import closure reachable from view.js is vendored — 15 files, 584K.
pdf.js is replaced by a stub that throws: view.js reaches it through a
static-string dynamic import inside makeBook, which Rollup resolves at build
time even though Chitai serves PDFs from static/pdfjs/web/viewer.html, and
upstream's version opens with a bare `import '@pdfjs/pdf.min.mjs'` that does
not resolve here.

scripts/vendor-foliate.sh pins the commit and makes the next update a one-line
change. fixed-layout.js needs construct-style-sheets-polyfill, so add it.
This commit is contained in:
2026-08-11 21:59:33 -04:00
parent a1281f129c
commit dd65e34869
24 changed files with 11543 additions and 1 deletions
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env bash
#
# Vendors foliate-js into src/lib/vendor/foliate-js/.
#
# foliate-js has no npm release and no build step; upstream recommends a git
# submodule. We copy instead, because this repo has no submodules (pdf.js is
# vendored the same way under static/pdfjs) and because a submodule would drag
# in 231 files / 13 MB, of which 191 files / 12 MB is a bundled pdf.js build we
# deliberately do not use — Chitai serves PDFs through static/pdfjs/web/viewer.html.
#
# Only the files reachable from view.js are copied: 15 upstream files, ~656 KB.
# pdf.js is NOT copied; a stub is written in its place (see below).
#
# To update: bump FOLIATE_SHA, re-run, review the diff, then smoke-test the
# reader — paginator.js is ~3800 lines of gesture and animation code and this
# fork is pushed to frequently.
#
# Usage: ./scripts/vendor-foliate.sh
set -euo pipefail
FOLIATE_REPO="https://github.com/readest/foliate-js.git"
FOLIATE_SHA="63a2eb1fc1e4813c4e849ccdb3d4be2c54a35869"
DEST="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/src/lib/vendor/foliate-js"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
# The reachable closure from view.js. Everything else upstream ships is either
# unreachable (dict.js, opds.js, footnotes.js, quote-image.js, uri-template.js),
# a demo (reader.js), or build tooling (rollup.config.js, eslint.config.js).
FILES=(
view.js
epub.js
epubcfi.js
paginator.js
fixed-layout.js
overlayer.js
progress.js
search.js
text-walker.js
tts.js
mobi.js
comic-book.js
fb2.js
vendor/zip.js
vendor/fflate.js
)
echo "Cloning $FOLIATE_REPO @ ${FOLIATE_SHA:0:7} ..."
git clone --quiet --filter=blob:none --no-checkout "$FOLIATE_REPO" "$TMP/foliate"
git -C "$TMP/foliate" checkout --quiet "$FOLIATE_SHA"
rm -rf "$DEST"
mkdir -p "$DEST/vendor"
for f in "${FILES[@]}"; do
if [ ! -f "$TMP/foliate/$f" ]; then
echo "ERROR: $f is missing upstream at ${FOLIATE_SHA:0:7}." >&2
echo "The file list in this script is stale; re-check the import graph." >&2
exit 1
fi
cp "$TMP/foliate/$f" "$DEST/$f"
done
cp "$TMP/foliate/LICENSE" "$DEST/LICENSE"
# view.js does `await import('./pdf.js')` inside makeBook. That is a static-string
# dynamic import, so Rollup resolves it at build time whether or not the code path
# ever runs — and upstream's pdf.js opens with `import '@pdfjs/pdf.min.mjs'`, a bare
# specifier that does not resolve here. Shipping this stub at that path keeps the
# build working without a Vite alias, and without vendoring 12 MB of pdf.js.
cat > "$DEST/pdf.js" <<'STUB'
// NOT upstream foliate-js. See README.chitai.md.
//
// Chitai renders PDFs with the pdf.js viewer vendored at static/pdfjs/, so
// foliate's PDF backend is not vendored. view.js still references this module
// from makeBook via a static-string dynamic import, which Rollup resolves at
// build time regardless of whether it executes — so the file has to exist.
//
// Throwing at module scope surfaces a legible message in the reader's error
// card if a PDF is ever routed to the EPUB reader by mistake, rather than a
// TypeError from `globalThis.pdfjsLib` being undefined.
throw new Error('foliate-js PDF rendering is not enabled in Chitai');
STUB
cat > "$DEST/README.chitai.md" <<EOF
# Vendored foliate-js
Do not edit these files. They are copied verbatim from upstream by
\`frontend/scripts/vendor-foliate.sh\`; local changes are lost on the next run.
| | |
| --- | --- |
| Upstream | <https://github.com/readest/foliate-js> (Readest's fork of johnfactotum/foliate-js) |
| Pinned commit | \`$FOLIATE_SHA\` |
| Licence | MIT — see \`LICENSE\` |
Readest's fork is used rather than upstream for its paginator work: touch/swipe
turn handling, fixed-layout spread centring, and a malformed-XHTML fallback in
\`loadDocument\`.
## What is here
Only the import closure reachable from \`view.js\`. Not vendored, because nothing
reaches them: \`dict.js\`, \`opds.js\`, \`footnotes.js\`, \`quote-image.js\`,
\`uri-template.js\`, \`reader.js\` (upstream's demo), and the build configs.
## pdf.js is ours, not upstream's
\`pdf.js\` in this directory is a **stub that throws**. Upstream's version imports
\`@pdfjs/pdf.min.mjs\` — a bare specifier backed by a 12 MB vendored pdf.js build —
and \`view.js\` reaches it through \`await import('./pdf.js')\`, which Rollup resolves
at build time even though Chitai never takes that path. Chitai serves PDFs from
\`static/pdfjs/web/viewer.html\` instead.
To enable foliate's PDF backend, add \`pdf.js\` and \`vendor/pdfjs/\` to the file list
in the vendor script and drop the stub.
## Updating
Bump \`FOLIATE_SHA\` in \`frontend/scripts/vendor-foliate.sh\`, re-run it, review the
diff, and smoke-test the reader — \`paginator.js\` is ~3800 lines of gesture and
animation code and this fork is pushed to frequently.
EOF
echo
echo "Vendored ${#FILES[@]} files + LICENSE + pdf.js stub + README.chitai.md to:"
echo " $DEST"
du -sh "$DEST" | sed 's/^/ /'