Skip to content

Initialize br.book Before Plugins to Prevent Startup Errors #1474

@Saqib-Nawaab

Description

@Saqib-Nawaab

Description

BookReader can crash during initialization because plugin lifecycle work (plugin construction and/or plugin setup()) runs before br.book is created.

Currently, if a plugin (including downstream integrations’ custom plugins) touches br.book during its constructor(br) or setup() lifecycle, it may dereference undefined and throw. When this happens, BookReader fails to initialize and the UI never renders.

This is particularly noticeable in apps where book metadata or data may load asynchronously — the crash may appear timing-dependent, even if the plugin isn’t doing anything inherently wrong.

Symptoms

  • BookReader initialization aborts with an exception; the reader UI never appears.
  • The error originates in plugin code but is caused by setup ordering (plugins run before br.book exists), making it hard for downstream apps to diagnose.

How to Reproduce

  1. Register/enable a plugin that references br.book during construction or setup. Minimal example:
class TestPlugin extends BookReaderPlugin {
  constructor(br) {
    super(br);
    br.book.pages; // Accessing book too early
  }
}
BookReader.registerPlugin('test_plugin', TestPlugin);
  1. Create a BookReader instance (with or without data loaded yet).
  2. Observe the runtime error during initialization.

Evidence / Screenshot

Console error example:

Uncaught TypeError: Cannot read properties of undefined (reading 'pages')

Location:

  • src/BookReader.jsBookReader.prototype.setup() initialization order (plugins are initialized before this.book is created).

Expected Behavior

  • br.book should exist before plugin construction and before plugin setup() runs.
  • Plugins can safely reference br.book, even if the underlying book data hasn’t loaded yet.

Context

  • OS: Windows 10 (win32 10.0.26100)
  • Browser: (e.g., Chrome 131, Firefox 133)
  • BookReader version / commit: (fill in)

Proposal & Constraints

Proposed fix:

  • Adjust initialization order in BookReader.prototype.setup() so this.book is created before constructing or setting up plugins.

Implementation notes:

  • Assign this.reduceSet, this.pageProgression, this.protected, and this.data early (so BookModel has sane defaults).
  • Create this.book = new BookModel(this) before plugin construction/setup.
  • Keep existing plugin setup logic unchanged, but execute it after this.book exists.

Constraints / Non-goals:

  • Book data does not need to be loaded; this ensures br.book exists during early plugin lifecycle.
  • Does not attempt to make br.book.pages meaningful before data loads — it only prevents crashes.

Verification:

  • Add a regression test that registers a plugin accessing br.book.pages during construction, then assert new BookReader() does not throw.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions