chore: wire vendored foliate-js into the build
$foliate is a Vite-only alias, deliberately absent from kit.alias and tsconfig paths: TypeScript cannot resolve it, so the ambient declaration in src/lib/reader/foliate.d.ts is the only candidate and svelte-check never walks the ~11k lines of untyped vendored JS. The generated tsconfig includes src/**/*.js and checkJs is on, so src/lib/vendor is excluded as well — `exclude` replaces rather than merges, hence the repeated service-worker entries. optimizeDeps.include for construct-style-sheets-polyfill: it sits behind a dynamic import in fixed-layout.js, so Vite would otherwise discover it mid-session and force a page reload on the first fixed-layout EPUB. Verified with a temporary import that the graph resolves: view.js and paginator.js are emitted as chunks, and the bundled pdf.js is our stub rather than upstream's bare `import '@pdfjs/pdf.min.mjs'`.
This commit is contained in:
Vendored
+90
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Hand-written types for the vendored foliate-js (src/lib/vendor/foliate-js).
|
||||
*
|
||||
* `$foliate` is a Vite-only alias, so TypeScript cannot resolve it and this
|
||||
* ambient declaration is the only candidate — which is the point: svelte-check
|
||||
* never walks the untyped vendored JS. Only the surface Chitai calls is typed.
|
||||
* When you start using a new method, add it here rather than casting to `any`.
|
||||
*/
|
||||
declare module '$foliate/view.js' {
|
||||
/** A TOC entry. `id` is assigned by foliate's `assignIDs`, not by the book. */
|
||||
export interface FoliateTocItem {
|
||||
id: number;
|
||||
label: string;
|
||||
href: string;
|
||||
subitems?: FoliateTocItem[];
|
||||
}
|
||||
|
||||
/** `event.detail` of the `relocate` event. Shape from SectionProgress.getProgress. */
|
||||
export interface FoliateRelocateDetail {
|
||||
/** Overall progress through the book, 0–1. Chitai stores this as `percentage`. */
|
||||
fraction: number;
|
||||
section: { current: number; total: number };
|
||||
location: { current: number; next: number; total: number };
|
||||
/** Estimated remaining reading time, in minutes. */
|
||||
time: { section: number; total: number };
|
||||
/** Null when the book has no TOC entry covering this position. */
|
||||
tocItem?: FoliateTocItem | null;
|
||||
pageItem?: { label: string; href: string } | null;
|
||||
cfi: string;
|
||||
range?: Range;
|
||||
}
|
||||
|
||||
/** `event.detail` of the `load` event. `doc` is the section's iframe document. */
|
||||
export interface FoliateLoadDetail {
|
||||
doc: Document;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export interface FoliateRenderer extends HTMLElement {
|
||||
/**
|
||||
* A single string sets the stylesheet appended to <head>, which wins over the
|
||||
* book's own CSS on equal specificity. A [before, after] tuple also sets one
|
||||
* prepended to <head>, which the book's CSS overrides. Re-applied by the
|
||||
* paginator on every section load. Absent on the fixed-layout renderer.
|
||||
*/
|
||||
setStyles?(styles: string | [before: string, after: string]): void;
|
||||
getContents(): { doc: Document; index: number }[];
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
export interface FoliateBook {
|
||||
toc?: FoliateTocItem[];
|
||||
/** 'rtl' for right-to-left books; drives goLeft/goRight. */
|
||||
dir?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
rendition?: { layout?: string };
|
||||
}
|
||||
|
||||
/** Accepted by goTo/select/init: a CFI or href, a spine index, or a fraction. */
|
||||
export type FoliateTarget = string | number | { fraction: number };
|
||||
|
||||
export class View extends HTMLElement {
|
||||
book: FoliateBook;
|
||||
renderer: FoliateRenderer;
|
||||
/** True when the book is pre-paginated; the renderer is then foliate-fxl. */
|
||||
isFixedLayout: boolean;
|
||||
lastLocation: FoliateRelocateDetail | null;
|
||||
|
||||
open(book: File | string | FoliateBook): Promise<void>;
|
||||
close(): void;
|
||||
init(opts: { lastLocation?: FoliateTarget | null; showTextStart?: boolean }): Promise<void>;
|
||||
|
||||
/** Returns undefined on failure — it logs and swallows. Check before relying on it. */
|
||||
resolveNavigation(target: FoliateTarget): { index: number; anchor?: unknown } | undefined;
|
||||
goTo(target: FoliateTarget): Promise<{ index: number } | undefined>;
|
||||
goToFraction(fraction: number): Promise<void>;
|
||||
|
||||
prev(distance?: number): Promise<void>;
|
||||
next(distance?: number): Promise<void>;
|
||||
/** Direction-aware: inverts against prev/next for rtl books. */
|
||||
goLeft(): Promise<void>;
|
||||
goRight(): Promise<void>;
|
||||
}
|
||||
|
||||
export function makeBook(file: File | string): Promise<FoliateBook>;
|
||||
|
||||
export class ResponseError extends Error {}
|
||||
export class NotFoundError extends Error {}
|
||||
export class UnsupportedTypeError extends Error {}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { View } from '$foliate/view.js';
|
||||
|
||||
let pending: Promise<void> | undefined;
|
||||
|
||||
/**
|
||||
* Loads foliate-js and registers its custom elements.
|
||||
*
|
||||
* view.js calls customElements.define() at module scope and subclasses
|
||||
* HTMLElement, and its class fields construct DOM helpers eagerly — so importing
|
||||
* it on the server throws. This module is safe to import anywhere because it
|
||||
* touches nothing at module scope; the vendored code is only pulled in when
|
||||
* loadFoliate() is called, which must be from onMount or a browser guard.
|
||||
*
|
||||
* The promise is cached so concurrent callers share one load. ESM already dedupes
|
||||
* module evaluation; this mainly makes the "define runs once" contract explicit.
|
||||
* Editing a file under src/lib/vendor invalidates the module and re-runs
|
||||
* customElements.define, which throws — hard-refresh after re-vendoring.
|
||||
*/
|
||||
export function loadFoliate(): Promise<void> {
|
||||
return (pending ??= import('$foliate/view.js').then(() => undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <foliate-view>. Call only after loadFoliate() has resolved.
|
||||
*
|
||||
* Built imperatively rather than written in markup so SSR never emits an unknown
|
||||
* element for Svelte to hydrate, and so svelte-check has no unknown attributes to
|
||||
* complain about.
|
||||
*/
|
||||
export function createFoliateView(): View {
|
||||
return document.createElement('foliate-view') as View;
|
||||
}
|
||||
Reference in New Issue
Block a user