Search code examples
node.jsdependenciesdynamic-import

How are dependecies of dynamically imported node modules managed?


I am using dynamic imports to add modules to a node repl app at runtime. The dynamically imported module however might have its own static imports. In the example I am trying to get to work, the dynamic module (an mjs file with no package.json) imports a library that is installed in the main app. However when await import() is called node cannot find that static dependency.

I had (erroneously?) assumed that dynamic import would resolve dependencies based on what is installed in the hosting app's node_modules tree.

So in my case mmmagic is installed in the hosting app and statically imported in the dynamic module, but cannot be found.

Could not load script helper.mjs
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'mmmagic' imported from C:\Users\don\scripts\helper.mjs
    at new NodeError (node:internal/errors:372:5)
    at packageResolve (node:internal/modules/esm/resolve:954:9)
    at moduleResolve (node:internal/modules/esm/resolve:1003:20)
    at defaultResolve (node:internal/modules/esm/resolve:1218:11)
    at ESMLoader.resolve (node:internal/modules/esm/loader:580:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:294:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:80:40)
    at link (node:internal/modules/esm/module_job:78:36) {
  code: 'ERR_MODULE_NOT_FOUND'

Solution

  • Dependencies (when you don't specify an explicit path for the dependency) for a given module are searched for relative to the module loading them, not relative to the app. So, it looks in the node_modules sub-directory under the module that is trying to load the other module. In this way, each module is supposed to carry with it, its own dependencies. That's the idea behind modularity as each module can be independently loaded by itself without requiring some global environment be in place first. This makes modules independent, but is less efficient for disk space.

    Note, this also allows a module to have a dependency on a specific version of some dependent module (specified in it's own package.json file) that may be different than what some other module in the same project is using.