Skip to content

Improve ESM compatibility#697

Merged
Phillip9587 merged 2 commits intoexpressjs:masterfrom
Phillip9587:direct-exports
Jan 19, 2026
Merged

Improve ESM compatibility#697
Phillip9587 merged 2 commits intoexpressjs:masterfrom
Phillip9587:direct-exports

Conversation

@Phillip9587
Copy link
Member

Ref: #666 (comment)

This PR contains 2 commits:

fix: use static exports instead of lazy getters
Static exports allow Node.js cjs-module-lexer to detect named
exports correctly, improving ESM interop and bundler behavior.

feat: add subpath exports for individual parsers

Add an exports field to package.json exposing json, raw, text,
and urlencoded parsers as subpath exports.

This allows consumers to import individual parsers directly:

  • CommonJS: require('body-parser/json')
  • ESM: import json from 'body-parser/json'

The change is fully backward compatible and enables users to
opt into loading only the parsers they need.

Closes #666

Copy link
Member

@jonchurch jonchurch left a comment

Choose a reason for hiding this comment

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

Im concerned here that the exports inclusion makes this breaking to a small number of users. I am always wary of packaging changes mid major (ala files, exports), as it can break things unless the paths cover everything that was possible previously.

There are indeed apps in the wild doing silly things like importing from lib which this change would break:
https://github.com/search?q=%22require%28%27body-parser%2F%22&type=code
(I think VSCode's auto-complete for imports often does these deep imports when there's no exports field, i've seen it a lot at a previous job. likely how folks ended up w/ this)

We can split out the index.js change as it's own PR, as that's standalone and won't break anyone. Or we can do an exhaustive exports field inside this same major. But that doesn't seem valuable here.

From the Node docs, we could do this to preserve back compat:

  "exports": {
    ".": "./index.js",
    "./package.json": "./package.json",
    "./json": "./lib/types/json.js",
    "./raw": "./lib/types/raw.js",
    "./text": "./lib/types/text.js",
    "./urlencoded": "./lib/types/urlencoded.js",
    // Back compat entries start here
    "./lib/*": "./lib/*.js", // will include read.js and utils.js, both internal but both still requireable today
    "./lib/*.js": "./lib/*.js",
    "./lib/types/*": "./lib/types/*.js",
    "./lib/types/*.js": "./lib/types/*.js"
  }

@Phillip9587
Copy link
Member Author

@jonchurch I totally agree we should provide these back compat entries until the next major. I pushed the changes please re-review.

@Phillip9587
Copy link
Member Author

@jonchurch @bjohansebas Do we need a HISTORY.md entry?

@bjohansebas
Copy link
Member

@jonchurch @bjohansebas Do we need a HISTORY.md entry?

Yes, it’s a change that enables new things, so I’d say yes

@Phillip9587
Copy link
Member Author

@bjohansebas Should we also document the subpath exports in README.md? It allows to import only a specific parser like require('body-parser/text').

@bjohansebas
Copy link
Member

Yes, also.

Static exports allow Node.js cjs-module-lexer to detect named
exports correctly, improving ESM interop and bundler behavior.
Add an exports field to package.json exposing json, raw, text,
and urlencoded parsers as subpath exports.

This allows consumers to import individual parsers directly:
- CommonJS: require('body-parser/json')
- ESM: import json from 'body-parser/json'

The change is fully backward compatible and enables users to
opt into loading only the parsers they need.
@Phillip9587
Copy link
Member Author

@bjohansebas Can you review the changes please?

@Phillip9587 Phillip9587 merged commit 266e69e into expressjs:master Jan 19, 2026
16 checks passed
@Phillip9587 Phillip9587 deleted the direct-exports branch January 19, 2026 21:23
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.

no named exports for ESM projects

3 participants