Skip to content

feat: add native ESM entrypoint and exports map - #1044

Merged
anttiviljami merged 7 commits into
mainfrom
feat/native-esm-entry
Oct 28, 2026
Merged

anttiviljami merged 7 commits into
mainfrom
feat/native-esm-entry

Conversation

@anttiviljami

@anttiviljami anttiviljami commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #1043 (#1042).

Problem

From native ESM, import OpenAPIBackend from 'openapi-backend' returns the CommonJS module.exports object, not the class, so new OpenAPIBackend() throws. The TypeScript types for ESM consumers (node16 / nodenext) describe the same wrong shape.

Changes

  • src/index.mts: builds to index.mjs + index.d.mts. It re-exports the CommonJS build and sets the default export to OpenAPIBackend. Because it wraps the CJS build instead of shipping a second copy, ESM and CJS share one class (instanceof keeps working, no dual-package hazard).
  • package.json: an exports map with import / require conditions, each with its own types. Deep imports still resolve (openapi-backend/router and openapi-backend/router.js), as does openapi-backend/package.json. files includes the new outputs.
  • .gitignore: ignores the new build outputs.
  • src/module-compat.test.ts: adds an ESM test (default import, named imports, a deep import, and the same class as CJS). The CJS test now imports by package name.

Verification

  • Runs on Node 20, 22 and 24, both ESM and CJS, with and without --no-experimental-require-module.
  • Consumer type checks pass with node16, nodenext, bundler and node10 module resolution. The default import is typed as the class.
  • npm run lint is clean and npm test passes (371 tests).

Compatibility

Adding exports blocks deep imports of paths the map doesn't cover. Top-level .js files are still covered, with or without the extension; uncommon paths like *.map files no longer resolve. Suggest releasing as a minor (5.23.0).

🤖 Generated with Claude Code

https://claude.ai/code/session_014SmjJ8wtCmDwhFrLMSsHrH

@apidevtools/json-schema-ref-parser is ESM-only, so the top-level require()
in refparser.js crashed on runtimes with require(esm) disabled, such as AWS
Lambda nodejs20.x-24.x (ERR_REQUIRE_ESM). Load it lazily with a cached
dynamic import() instead. Compile with module node16 so tsc emits a real
import() in the CommonJS output and flags any future require of an ESM package.

Fixes #1042

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SmjJ8wtCmDwhFrLMSsHrH
Add index.mjs that re-exports the CommonJS build, so
`import OpenAPIBackend from 'openapi-backend'` returns the class rather than
the module namespace, without a dual package hazard (ESM and CJS share one
class instance). Add an exports map with import/require conditions and types
(index.d.mts for ESM consumers); deep imports like `openapi-backend/router`
keep working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SmjJ8wtCmDwhFrLMSsHrH
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014SmjJ8wtCmDwhFrLMSsHrH
Base automatically changed from fix/refparser-dynamic-import to main October 28, 2026 09:48
@anttiviljami
anttiviljami merged commit f937c4e into main Oct 28, 2026
17 checks passed
@anttiviljami
anttiviljami deleted the feat/native-esm-entry branch October 28, 2026 09:51
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