Skip to content

Add an ESM build for consumers that bundle BookReader themselves - #1603

Open
cdrini wants to merge 4 commits into
internetarchive:masterfrom
cdrini:esm-build
Open

cdrini wants to merge 4 commits into
internetarchive:masterfrom
cdrini:esm-build

Conversation

@cdrini

@cdrini cdrini commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Description

Adds a third webpack build, esm/, that outputs the same entries (core, plugins, ia-bookreader-bundle.js) as ES modules. This lets apps that bundle BookReader themselves (e.g. offshoot with Vite) load it with import() instead of <script> tags, without having to compile src/ and its decorators themselves.

Future Work

  1. Switch to lit 3 + fix decorator issues so that we can stop bundling that dependency
  2. Switch to explicit imports of jquery (or something) so that that also can become a normal external dependency
  3. Move BookReader/ build directory to dist/browser
  4. Fix experiments panel/plugin and translator worker in offshoot

Technical

  • Same entries as the classic build, minus the webcomponents polyfill and the translator worker. Plugins import the core's webpack runtime from ../BookReader.js, so they share one module registry, like dependOn does for the classic build.
  • Declared dependencies are left as bare imports, so the consumer resolves and dedupes them. Bundled copies of web components (e.g. @internetarchive/icon-share via text selection) otherwise throw when they re-register a custom element name the host app already defined.
  • Exceptions: jQuery stays the runtime global (as in the classic build), Babel's core-js polyfills stay bundled, and lit stays bundled because our 2018-09 Babel decorators only work with lit 2's decorators, while consumers may be on lit 3. Sharing lit would need BR on lit 3 with standard decorators (accessor fields).
  • Targets browserslist supports es6-module-dynamic-import (Chrome 63, Firefox 67, Edge 79, Safari 11) rather than the classic build's IE 11 floor, since anything loading this build needs ES modules and import() anyway. esm/BookReader.js is 217 KB vs 331 KB at the classic targets.
  • esm/ is added to files, .gitignore and clean. The classic build's config is unchanged apart from sharing its entry list with the ESM build.

Testing

  • npx webpack --config-name esm builds just this output.
  • Tested in offshoot by importing @internetarchive/bookreader/esm/BookReader.js and its plugins: the reader renders and all plugins register, with no custom-element re-registration errors.

Screenshots/Videos

N/A

🤖 Generated with Claude Code

Co-Authored-By: Drini Cami <cdrini@gmail.com>
@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.18%. Comparing base (55be1ae) to head (b5140da).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1603   +/-   ##
=======================================
  Coverage   64.18%   64.18%           
=======================================
  Files          69       69           
  Lines        6290     6290           
  Branches     1398     1398           
=======================================
  Hits         4037     4037           
  Misses       2214     2214           
  Partials       39       39           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

claude and others added 3 commits October 7, 2026 14:47
Co-Authored-By: Drini Cami <cdrini@gmail.com>
Co-Authored-By: Drini Cami <cdrini@gmail.com>
Co-Authored-By: Drini Cami <cdrini@gmail.com>
@jbuckner

jbuckner commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Woohoo!

@cdrini
cdrini marked this pull request as ready for review October 7, 2026 19:25

@jbuckner jbuckner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I built the esm output and ran it in offshoot (Chromium and WebKit, dev and prod Vite builds). The reader renders, all the plugins register including text selection, and there are no custom element errors. Two small things inline.

Comment thread webpack.config.js
'plugins/plugin.tts.js': { import: './src/plugins/tts/plugin.tts.js', dependOn: 'BookReader.js' },
'plugins/plugin.url.js': { import: './src/plugins/url/plugin.url.js', dependOn: 'BookReader.js' },
'plugins/plugin.vendor-fullscreen.js': { import: './src/plugins/plugin.vendor-fullscreen.js', dependOn: 'BookReader.js' },
'ia-bookreader-bundle.js': { import: './src/ia-bookreader/ia-bookreader.js', dependOn: 'BookReader.js' },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bundle defines ia-bookreader and about 9 other ia-* elements with no guard. If a consumer imports this and also imports the package root (src/ia-bookreader), they get registered twice and it throws. Offshoot already imports the package root, so it can't use this file. Can we say that in the PR description? It's one or the other.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting I thought the bundle should not have any of the third-party deps bundled in 🤔 Will give it a test.

Comment thread webpack.config.js
// themselves (e.g. with Vite) rather than loading it via <script> tags.
{
...shared,
name: 'esm',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing in CI checks this output. The whole point is that the plugins have no customElements.define and the declared deps stay bare imports, so a small check on dist/esm for those two things would stop a regression from slipping through. Fine as a follow-up.

@cdrini cdrini mentioned this pull request Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants