nodejs / import-in-the-middle

Like `require-in-the-middle`, but for ESM import
https://www.npmjs.com/package/import-in-the-middle
Apache License 2.0
72 stars 27 forks source link

Hooking a Module that Exports a Function Does not Hook a Callable Function #18

Closed astorm closed 11 months ago

astorm commented 2 years ago

Expected Behavior

When hooking a module that exports a function, the exported object passed to the hook will also be a function.

Actual Behavior

When hooking a module that exports a function, the exported object passed to the hook is not a function.

Steps to Reproduce the Problem

We've noticed that, unlike require-in-the-middle, if you're trying to import a module that exports a function object by default that the function won't be callable.

That is -- if we install fastify and import-in-the-middle in a type="module" project

% npm install import-in-the-middle
% npm install fastify

and have a simple sample program that looks like this

% cat index.js 
import Fastify from 'fastify'
import Hook from 'import-in-the-middle'

Hook(['fastify'], (exported, name, baseDir) => {
  const fastifyInstance = exported()
})

const fastifyInstance = Fastify({
  logger:true
})
console.log(fastifyInstance)

We get an error when running the program.

% node --loader=import-in-the-middle/hook.mjs index.js
//...
  const fastifyInstance = exported()
                          ^

TypeError: exported is not a function

With a require-in-the-middle hook, the exported variable is the callable function exported by the fastify module.

Is this something we could get import-in-the-middle doing? Or are there :wave: reasons :wave: this isn't possible with either ESM modules or loader hooks?

For context -- This is a small isolated example of a larger problem we're trying to solve. We have a piece of software with a large number of require-in-the-middle hooks. We'd like to be able to provide our users with the same functionality if they happen to be using import statements while still supporting folks who are sticking with CommondJS modules at the same time. The closer import-in-the-middle's behavior is to require-in-the-middle the less we need branching code or refactoring of our existing hooks.

Specifications

rochdev commented 2 years ago

I'm not 100% sure if this is related, but I think the issue is that the code handling this has not yet been moved to iitm: https://github.com/DataDog/dd-trace-js/blob/6eeb958b5638281a89f4e7d7e03d5f66aebe8547/packages/datadog-instrumentations/src/helpers/hook.js#L25-L34

bengl commented 11 months ago

The exported object corresponds to the result of import * as exported from 'module-name' (i.e. a namespace import), and so if a module has default exports (as fastify does), then that can be accessed with exported.default.

I'll close this since it's just a matter of using that .default property. Please feel free to comment here again if this doesn't resolve it for you.