Skip to content

fix: bundle ESM-only deps into CJS output with Rollup#1409

Merged
remarkablemark merged 1 commit intoremarkablemark:masterfrom
athenabriana:fix/cjs-esm-compat
Apr 7, 2026
Merged

fix: bundle ESM-only deps into CJS output with Rollup#1409
remarkablemark merged 1 commit intoremarkablemark:masterfrom
athenabriana:fix/cjs-esm-compat

Conversation

@athenabriana
Copy link
Copy Markdown
Contributor

@athenabriana athenabriana commented Apr 7, 2026

What is the motivation for this pull request?

The CJS build (lib/) shipped in v7.0.0 is broken — it require()s dependencies that are now ESM-only.

The problem

In v7.0.0, both direct dependencies were upgraded:

  • domhandler v5 → v6 (now ESM-only, "type": "module")
  • htmlparser2 v10 → v12 (now ESM-only, also pulls ESM-only domutils@4, domelementtype@3, entities@8)

The CJS build is still compiled with plain tsc --module commonjs, which converts import to require(). Since these dependencies no longer have CJS entry points, this fails:

Error: require() of ES Module .../domhandler/dist/index.js not supported.
ERR_REQUIRE_ESM

Prior to v7, this worked because domhandler@5 and htmlparser2@10 shipped CJS. The package still advertises CJS support via "require": "./lib/index.js" in its exports map.

Affected

  • Node.js < 22.12 (includes Node.js 20 LTS, EOL April 2026)
  • Vitest (jsdom/happy-dom environments resolve CJS)
  • Jest (resolves CJS by default)
  • SSR environments using CJS module resolution

Not affected

  • Node.js >= 22.12 (require(esm) enabled by default)
  • Node.js >= 24
  • Bundlers (Webpack, Vite, esbuild — they resolve ESM natively)

The fix

Switch the CJS build from plain tsc to Rollup (which already handles the ESM and UMD builds). Rollup's @rollup/plugin-node-resolve and @rollup/plugin-commonjs plugins bundle the ESM-only dependencies into the CJS output, eliminating the bare require() calls.

Changes:

  • scripts/build.sh --cjs: generates declaration files with tsc --emitDeclarationOnly, then bundles CJS with Rollup
  • rollup.config.mjs: adds CJS server and client configs (same pattern as the existing ESM configs)

All existing tests pass. No API changes.

Alternative: drop CJS support

If the upgrade to ESM-only dependencies was intentional and CJS support is no longer a goal, this PR can be closed in favor of removing CJS entirely:

  • Remove "require" conditions from the "exports" map in package.json
  • Remove "main": "./lib/index.js"
  • Remove the CJS build step (build:cjs)
  • Add "type": "module" to package.json

The current state — advertising CJS via the exports map but shipping a broken CJS build — should be resolved either way.

The CJS build (`lib/`) was compiled with plain `tsc --module commonjs`,
which converts `import` statements to `require()` calls. Since v7,
the dependencies (domhandler@6, htmlparser2@12, etc.) are ESM-only
(`"type": "module"`), so `require()` fails with `ERR_REQUIRE_ESM`
on Node.js < 22 (which lacks native `require(esm)` support).

This switches the CJS build from plain `tsc` to Rollup (which already
handles the ESM and UMD builds), bundling the ESM-only dependencies
into the CJS output. Declaration files are still generated by `tsc`.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (fda4c22) to head (901f1b4).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #1409   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            6         6           
  Lines          120       120           
  Branches        30        30           
=========================================
  Hits           120       120           

☔ View full report in Codecov by Sentry.
📢 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.

Copy link
Copy Markdown
Owner

@remarkablemark remarkablemark left a comment

Choose a reason for hiding this comment

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

Thanks so much for the fix @athenacfr!

@remarkablemark remarkablemark merged commit e906aaa into remarkablemark:master Apr 7, 2026
13 checks passed
@remarkablemark
Copy link
Copy Markdown
Owner

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants