Package Exports
- import-in-the-middle
- import-in-the-middle/hook.mjs
- import-in-the-middle/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (import-in-the-middle) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
import-in-the-middle
import-in-the-middle is an module loading interceptor inspired by
require-in-the-middle, but
specifically for ESM modules. In fact, it can even modify modules after loading
time.
Usage
The API for
require-in-the-middle is followed as closely as possible as the default
export. There are lower-level addHook and removeHook exports available which
don't do any filtering of modules, and present the full file URL as a parameter
to the hook. See the Typescript definition file for detailed API docs.
You can modify anything exported from any given ESM or CJS module that's imported in ESM files, regardless of whether they're imported statically or dynamically.
import { Hook } from 'import-in-the-middle'
import { foo } from 'package-i-want-to-modify'
console.log(foo) // whatever that module exported
Hook(['package-i-want-to-modify'], (exported, name, baseDir) => {
// `exported` is effectively `import * as exported from ${url}`
exported.foo += 1
})
console.log(foo) // 1 more than whatever that module exportedThis requires the use of an ESM loader hook, which can be added with the following command-line option.
node --loader=import-in-the-middle/hook.mjs my-app.mjsSince --loader has been deprecated you can also register the loader hook programmatically via the Node
module.register()
API. However, for this to be able to hook non-dynamic imports, it needs to be
registered before your app code is evaluated via the --import command-line option.
my-loader.mjs
import * as module from 'module'
module.register('import-in-the-middle/hook.mjs', import.meta.url)node --import=./my-loader.mjs ./my-code.mjsWhen registering the loader hook programmatically, it's possible to pass a list
of modules, file URLs or regular expressions to either exclude or specifically
include which modules are intercepted. This is useful if a module is not
compatible with the loader hook.
Note: This feature is incompatible with the
{internals: true}Hook option
import * as module from 'module'
// Exclude intercepting a specific module by name
module.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { exclude: ['package-i-want-to-exclude'] }
})
// Only intercept a specific module by name
module.register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { include: ['package-i-want-to-include'] }
})Only Intercepting Hooked modules
Note: This feature is experimental and is incompatible with the
{internals: true}Hook option
If you are Hook'ing all modules before they are imported, for example in a
module loaded via the Node.js --import CLI argument, you can configure the
loader to intercept only modules that were specifically hooked.
instrument.mjs
import { register } from 'module'
import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
Hook(['fs'], (exported, name, baseDir) => {
// Instrument the fs module
})
// Ensure that the loader has acknowledged all the modules
// before we allow execution to continue
await waitForAllMessagesAcknowledged()my-app.mjs
import * as fs from 'fs'
// fs will be instrumented!
fs.readFileSync('file.txt')node --import=./instrument.mjs ./my-app.mjsExperimental experimentalPatchInternals option
It was found that import-in-the-middle didn't match the hooking behavior of require-in-the-middle in some cases:
https://github.com/nodejs/import-in-the-middle/issues/185
The experimentalPatchInternals option forces the loader to match the behavior of require-in-the-middle in these cases.
This option is experimental and may be removed or made the default in the future.
import { register } from 'module'
register('import-in-the-middle/hook.mjs', import.meta.url, {
data: { experimentalPatchInternals: true }
})Limitations
- You cannot add new exports to a module. You can only modify existing ones.
- While bindings to module exports end up being "re-bound" when modified in a hook, dynamically imported modules cannot be altered after they're loaded.
- Modules loaded via
requireare not affected at all.