node-newrelic: ESM loader in v11 does not work with got package, after installing the latest import-in-the-middle

Description

Attempting to use v11 in an ESM project that includes got causes the node process to crash.

In Node v18 you will get a silent exit code 13. In Node v20, it will throw a SyntaxError before exit code 1.

app-1  | (node:8) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
app-1  | --import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("newrelic/esm-loader.mjs", pathToFileURL("./"));'
app-1  | (Use `node --trace-warnings ...` to show where the warning was created)
app-1  | file:///app/node_modules/@payzen/got-commons/node_modules/got/dist/source/index.js?iitm=true:39
app-1  |     let $default = _.default
app-1  |         ^
app-1  |
app-1  | SyntaxError: Identifier '$default' has already been declared
app-1  |     at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:155:18)
app-1  |     at callTranslator (node:internal/modules/esm/loader:285:14)
app-1  |     at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:291:30)
app-1  |
app-1  | Node.js v20.10.0
app-1 exited with code 1

Expected Behavior

Running node --loader newrelic/esm-loader.mjs should work without crashing node. NOTE: # ( Tell us what you expected to happen. )

Troubleshooting or NR Diag results

Steps to Reproduce

  1. run npm init -y
  2. run npm i --save got newrelic
  3. create the file index.mjs with the contents
import got from 'got'
  1. run node --loader newrelic/esm-loader.mjs index.mjs
  2. crash

Your Environment

  • ex: Browser name and version: not relevant
  • ex: Node version: 20.10.0
  • ex: Operating System and version: Linux

Additional context

About this issue

  • Original URL
  • State: closed
  • Created 6 months ago
  • Comments: 24 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I’ve tried your fix and the error is now different, it looks like the module loading is okay, but not all the exports are re-exported correctly, it looks like the exported object is got’s Request rather than the got object itself, I’m using got@14.0.0 which is a native ESM module.

TypeError: got.extend is not a function
    at file:///app/node_modules/@payzen/got-commons/build/got-commons.js:185:29
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:329:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:120:12)

Printing the default exports yields

[class Request extends Duplex]

Thank you @ljharb. It’s a problem with IITM. I wrote a test for core and it passes:

Core Test
diff --git a/test/es-module/test-esm-initialization.mjs b/test/es-module/test-esm-initialization.mjs
index f03a47d5d3..e7882e0839 100644
--- a/test/es-module/test-esm-initialization.mjs
+++ b/test/es-module/test-esm-initialization.mjs
@@ -28,3 +28,19 @@ describe('ESM: ensure initialization happens only once', { concurrency: true },
     assert.strictEqual(code, 0);
   });
 });
+
+describe('ESM: nested default exports are handled correctly', () => {
+  it(async() => {
+    const { code, stderr, stdout } = await spawnPromisified(execPath, [
+      '--experimental-import-meta-resolve',
+      '--loader',
+      fixtures.fileURL('es-module-loaders', 'loader-resolve-passthru.mjs'),
+      '--no-warnings',
+      fixtures.path('es-modules', 'nested-default', 'index.mjs'),
+    ]);
+
+    assert.strictEqual(stderr, '');
+    assert.strictEqual(stdout.match(/resolve passthru/g)?.length, 3);
+    assert.strictEqual(code, 0);
+  });
+});
diff --git a/test/fixtures/es-modules/nested-default/a.mjs b/test/fixtures/es-modules/nested-default/a.mjs
new file mode 100644
index 0000000000..dc07e2033d
--- /dev/null
+++ b/test/fixtures/es-modules/nested-default/a.mjs
@@ -0,0 +1,3 @@
+const a = 'a'
+export default a
+export * from './b.mjs'
diff --git a/test/fixtures/es-modules/nested-default/b.mjs b/test/fixtures/es-modules/nested-default/b.mjs
new file mode 100644
index 0000000000..7f5dadf656
--- /dev/null
+++ b/test/fixtures/es-modules/nested-default/b.mjs
@@ -0,0 +1,2 @@
+const b = 'b'
+export default b
diff --git a/test/fixtures/es-modules/nested-default/index.mjs b/test/fixtures/es-modules/nested-default/index.mjs
new file mode 100644
index 0000000000..755d201fc8
--- /dev/null
+++ b/test/fixtures/es-modules/nested-default/index.mjs
@@ -0,0 +1 @@
+export * from './a.mjs'

You can’t export default multiple times, so it’s possible this is a node loader bug.