nodejs esm module output bundling lacks module prototype for externals · Issue #7446 · webpack/webpack.js.org (original) (raw)

Bug report

What is the current behavior?

For my electron app I want to bundle the nodejs code of my main thread because of a) typescript and b) performance optimizations. That means I have "type": "module", regular node 20+ esm style code and want to bundle my dependencies into a final bundle (as I ship this bundle with my electron executable and not as part of a backend that has a node_modules dir).

To achieve a clean esm bundle (without createRequire and with support for dynamic imports) I use:

I now want to bundle in the jimp library that has the pngjs dependency, which uses an util.inherits() call onto node-native stream in their chunkstream.js file:
https://github.com/pngjs/pngjs/blob/c565210c602527eb459f857eeb78183997482d5b/lib/chunkstream.js#L18

It looks like this in the bundle:

let Stream = webpack_require(/*! stream */ "stream"); util.inherits(ChunkStream, Stream);

Now the issue is that util.inherits expects stream to have a prototype and errors like so when run:

node:util:290 throw new ERR_INVALID_ARG_TYPE('superCtor.prototype', ^

TypeError [ERR_INVALID_ARG_TYPE]: The "superCtor.prototype" property must be of type object. Received undefined at Module.inherits (node:util:290:11) at ./node_modules/pngjs/lib/chunkstream.js (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:15981:6) at webpack_require (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:45536:41) at ./node_modules/pngjs/lib/parser-async.js (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:17191:19) at webpack_require (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:45536:41) at ./node_modules/pngjs/lib/png.js (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:17814:14) at webpack_require (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:45536:41) at ./node_modules/@jimp/js-png/dist/esm/index.js (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:31862:63) at webpack_require (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:45536:41) at ./node_modules/jimp/dist/esm/index.js (file:///Users/myname/dev/jimp-nodenext/main.bundle.dev.js:39797:70) { code: 'ERR_INVALID_ARG_TYPE' }

When I edit the bundle, manually logging Stream.prototype yields undefined, and logging Stream yields:

[Module: null prototype] {
  Duplex: [Function: Duplex] {
    fromWeb: [Function (anonymous)],
    toWeb: [Function (anonymous)],
    from: [Function (anonymous)]
  },
  PassThrough: [Function: PassThrough],
  Readable: [Function: Readable] {
    ReadableState: [Function: ReadableState],
    _fromList: [Function: fromList],
    from: [Function (anonymous)],
    fromWeb: [Function (anonymous)],
    toWeb: [Function (anonymous)],
    wrap: [Function (anonymous)]
  },
  ...

I'm assuming the prototype that util.inherit expects got lost during webpacks bundling.

If the current behavior is a bug, please provide the steps to reproduce.

Here's a minimal repo for reproduction: https://github.com/tom2strobl/webpack-jimp-nodenext

See for additional comments regarding the webpack configuration: https://github.com/tom2strobl/webpack-jimp-nodenext/blob/main/webpack.config.js

What is the expected behavior?

webpack to bundle in a way that standard node modules that are defined as external retain their original prototypes for util.inherits compatibility.

Other relevant information:
webpack version: 5.95
Node.js version: 20.17
Operating System: macOS 15.0.1
Additional tools: jimp 1.6.0 / pngjs 7.0.0