The original Upstream provided the Viewer.js integration; fork-specific fixes preserve compatibility with the Quartz 5 YAML plugin loader and SPA router.

Repository

Failure and Root Cause

The original plugin worked on the first page but failed after SPA navigation with:

Uncaught TypeError: Cannot read properties of null (reading 'removeChild')

Quartz runs registered cleanup callbacks before replacing the body, clears its cleanup registry, patches the DOM, and then emits nav. The original plugin registered Viewer cleanup only once. After a later navigation, its stale Viewer still referenced an article that Quartz had detached. Calling currentViewer.destroy() then caused Viewer.js to remove a child from a missing parent, aborting initialization on the new page.

The original dynamically injected Viewer.js script and stylesheet also lacked Quartz’s data-persist marker, so SPA head patching could remove them. Its configurable selector affected hover CSS but did not restrict Viewer eligibility, and its resource-only transformer shape was rejected by the current Quartz YAML loader without a Quartz core compatibility change.

Fork Fixes

  • Destroy Viewer on prenav, before Quartz detaches the old article.
  • Re-register window.addCleanup() every time Viewer is initialized.
  • Treat teardown as defensive and always clear the stale Viewer reference.
  • Reinitialize on every Quartz nav event.
  • Give Viewer.js assets stable IDs and data-persist markers, preventing removal or duplication across SPA navigation.
  • Apply the configured selector through image.matches() as well as CSS.
  • Provide an empty htmlPlugins() method so Quartz accepts the transformer without modifying Quartz core.
  • Generate dist/index.d.ts, include dist/ in package output, and declare the published @quartz-community/types and Node type dependencies.
  • Update the YAML installation instructions for the maintained fork.

Testing and Packaging

The dependency-free Node lifecycle test executes the emitted browser script against a small DOM and Viewer harness. It verifies initial setup and three consecutive Quartz-style prenav, cleanup, DOM replacement, and nav cycles. It also checks selector filtering, persistent assets, duplicate prevention, and successful destruction of each prior Viewer instance.

Validation for 0.1.1 passed:

  • JavaScript and declaration builds;
  • lifecycle regression test;
  • TypeScript compilation;
  • repository-wide Prettier check;
  • whitespace validation; and
  • npm package dry run containing compiled JavaScript, source map, and types.

Current Integration

Digital Mind loads the fork from github:ruhanirabin/quartz-lightbox in quartz.config.yaml.