Skip to content

feat(publisher): implement ESM for publisher.js - #4166

Merged
binaryscales merged 5 commits into
subscriptions-project:mainfrom
everyplace:feature/publisher-esm
Aug 5, 2026
Merged

feat(publisher): implement ESM for publisher.js#4166
binaryscales merged 5 commits into
subscriptions-project:mainfrom
everyplace:feature/publisher-esm

Conversation

@everyplace

@everyplace everyplace commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

This PR adds a new export to the build script for esm bundles, enabling modern import syntax as a module.

  • 100% of existing tests pass, plus some new ones
  • Type safety additions
  • Export preferredSource instance directly from publisher-main.ts entry point.
  • Configure Vite multi-format bundling (IIFE and ES) exclusively for the publisher target without impacting legacy bundles, and opens the door for future splits
  • Add unit tests for API return types, .ready() resolution, and autoStart suppression.

@everyplace
everyplace force-pushed the feature/publisher-esm branch from b3ae6e0 to 3f16115 Compare August 5, 2026 00:49
@everyplace everyplace changed the title feat(publisher): implement ESM exports and .ready() promise for publi… feat(publisher): implement ESM for publisher.js Aug 5, 2026

@everyplace everyplace left a comment

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.

Commented on the bigger changes to help explain the overall narrative.

Comment thread build_binaries.sh
# Copy files.
cp dist/$basename.template.js dist/$basename$target.js
cp dist/$basename.template.js.map dist/$basename$target.js.map
for ext in "js" "mjs"; do

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.

Content below isn't changed, just indented because of the extra loop above.

Comment thread vite.config.js
publisher: {
output: args.minifiedPublisherName || 'publisher.js',
input: './src/publisher-main.ts',
esm: true,

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.

Only when esm is present and true do mjs versions of the code also get output.

Comment thread vite.config.js
const target = args.target || 'classic';
const {input, output, esm} = builds[target];
const outputs = [
{

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.

This used to be inlined below, but is now higher up to allow for contextually adding the esm version only when relevant.

}

export function installPublisherRuntime(win: Window) {
interface PublisherWindow extends Window {

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.

Adds an internal PublisherWindow interface for safer type checking against existing runtime installations, and introduces an optional autoStart configuration so ESM imports can avoid running immediate DOM side-effects upon evaluation.

if (existingProp && !Array.isArray(existingProp)) {
return;
return (
existingProp.api ?? {

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.

Returns the existing .api singleton reference on duplicate script invocations so module exports do not evaluate to undefined, with a defensive no-op fallback to prevent TypeError runtime exceptions if the namespace was improperly initialized.

if (script.getAttribute('preferred-sources-control') === 'manual') {
autoInit = false;
break;
if (options?.autoStart !== false) {

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.

The DOM scanning logic below is unchanged from the original implementation—it is simply indented inside the new options?.autoStart check to bypass automatic DOM queries during passive ESM imports.

Comment thread src/publisher-main.ts

installPublisherRuntime(self);
export const preferredSource = installPublisherRuntime(self, {
autoStart: !IS_ESM_BUILD,

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.

Only defaults autoStart to true if the build is not ESM. If it is ESM, auto-start is disabled in favor of manual initialization.

Comment thread build_binaries.sh

# Remove template binaries.
rm dist/*template.js*
rm -f dist/*template.*js*

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.

Allows for .js and .mjs

@everyplace
everyplace marked this pull request as ready for review August 5, 2026 15:12
@everyplace
everyplace force-pushed the feature/publisher-esm branch 2 times, most recently from ef68ddb to 8c8dbbf Compare August 5, 2026 19:09
…sher bundle

- Refactor installPublisherRuntime to return PreferredSourceApi and attach .ready() promise to win.PREFERRED_SOURCE.
- Support passive-by-default initialization via autoStart option to prevent side effects when importing publisher as an ES module.
- Export preferredSource instance directly from publisher-main.ts entry point.
- Configure Vite multi-format bundling (IIFE and ES) exclusively for the publisher target without impacting legacy bundles.
- Add unit tests for API return types, .ready() resolution, and autoStart suppression.
@everyplace
everyplace force-pushed the feature/publisher-esm branch from 8c8dbbf to 1e0bf8a Compare August 5, 2026 19:21
@binaryscales
binaryscales merged commit f9d44fc into subscriptions-project:main Aug 5, 2026
13 checks passed
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.

2 participants