You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
defineProperty is a supported syntax, but a get() method can't be a require() call or a call to any other function, it can only return a simple 'identifier or member expression.'
To avoid matching getters that have side effects, any getter for an export name that does not support the forms above will opt-out of the getter matching:
@UlisesGascon This is not an issue on the Node.js side. As I understand it, this behavior is intentional and already documented. As @dynst mentioned, Node.js explicitly opts out of matching getters that may have side effects:
To avoid matching getters that have side effects, any getter for an export name that does not support the forms above will opt-out of the getter matching
Raising an issue on the Node.js side will not help as the cjs-module-lexer readme clearly states that
Detection patterns for this project are frozen. This is because adding any new export detection patterns would result in fragmented backwards-compatibility. Specifically, it would be very difficult to figure out why an ES module named export for CommonJS might work in newer Node.js versions but not older versions. This problem would only be discovered downstream of module authors, with the fix for module authors being to then have to understand which patterns in this project provide full backwards-compatibily. Rather, by fully freezing the detected patterns, if it works in any Node.js version it will work in any other. Build tools can also reliably treat the supported syntax for this project as a part of their output target for ensuring syntax support.
What can we do?
We can fix this by directly exporting the individual parsers, but we would lose the benefit of lazy-loading them. Here's what the change would look like (without jsdoc):
'use strict'exports=module.exports=bodyParserexports.json=require('./lib/types/json')exports.raw=require('./lib/types/raw')exports.text=require('./lib/types/text')exports.urlencoded=require('./lib/types/urlencoded')functionbodyParser(){thrownewError('The bodyParser() generic has been split into individual middleware to use instead.')}
Trade-offs
The current implementation uses Object.defineProperty with getters to support lazy-loading, which may help in reducing memory usage and startup time (I have no numbers on the impact). However, this pattern is incompatible with Node.js's cjs-module-lexer, which only detects getters that return a simple identifier or member expression not function calls like require().
Why this change makes sense
Minimal performance impact:
All parsers share the same utilities (lib/read.js, lib/utils.js), so most code is loaded anyway
Only the urlencoded parser has a significant external dependency (qs). In typical express apps, qs is already in the require cache since Express uses it for query string parsing so it should not be a problem
Node.js's require cache makes subsequent loads essentially free
ESM interop: Direct exports enable named imports: import { json } from 'body-parser'
Tree-shaking: Bundlers can now perform module-level pruning, ensuring unused parsers are not included in the bundle.
The lazy-loading optimization is more valuable when body-parser is used standalone, but in a typical express app, the benefits of static analysis outweigh the minimal startup time savings in my opinion.
Other Option
We could also add the exports field to our package.json and export each parser as subpath:
This change is fully backward compatible and could also be combined with the change mentioned above. This way the main import trades lazy loading for better static analysis while users who care about startup time can rely on subpath exports to load only the parsers they need.
Activity
bjohansebas commentedon Nov 25, 2025
I was able to confirm the bug. My question is: is there anything we can do on our side, or is this already an issue for Node.js to handle?
UlisesGascon commentedon Nov 25, 2025
Not ideal, but as a workaround maybe changing the import statement might solve the issue:
Probably we can report this to Node... @dynst do you want to open an issue in https://github.com/nodejs/node/issues/new/choose and mention our current discussion for context?
Phillip9587 commentedon Dec 16, 2025
@UlisesGascon This is not an issue on the Node.js side. As I understand it, this behavior is intentional and already documented. As @dynst mentioned, Node.js explicitly opts out of matching getters that may have side effects:
Raising an issue on the Node.js side will not help as the cjs-module-lexer readme clearly states that
What can we do?
We can fix this by directly exporting the individual parsers, but we would lose the benefit of lazy-loading them. Here's what the change would look like (without jsdoc):
Trade-offs
The current implementation uses
Object.definePropertywith getters to support lazy-loading, which may help in reducing memory usage and startup time (I have no numbers on the impact). However, this pattern is incompatible with Node.js's cjs-module-lexer, which only detects getters that return a simple identifier or member expression not function calls likerequire().Why this change makes sense
lib/read.js,lib/utils.js), so most code is loaded anywayurlencodedparser has a significant external dependency (qs). In typical express apps,qsis already in the require cache since Express uses it for query string parsing so it should not be a problemimport { json } from 'body-parser'The lazy-loading optimization is more valuable when body-parser is used standalone, but in a typical express app, the benefits of static analysis outweigh the minimal startup time savings in my opinion.
Other Option
We could also add the
exportsfield to ourpackage.jsonand export each parser as subpath:{ "exports": { ".": "./index.js", "./json": "./lib/types/json.js", "./raw": "./lib/types/raw.js", "./text": "./lib/types/text.js", "./urlencoded": "./lib/types/urlencoded.js" } }This would allow users to import individual parsers from subpaths:
This change is fully backward compatible and could also be combined with the change mentioned above. This way the main import trades lazy loading for better static analysis while users who care about startup time can rely on subpath exports to load only the parsers they need.
What do you think @UlisesGascon @jonchurch?