Module resolution algorithm discrepancy

What I Wanted to Do

I wanted to use require to find the module I required, which could be in the globally installed location

What Happened Instead

module resolution doesn’t actually crawl through the global installation location

I’ve filed this issue against node, but haven’t gotten much traction. Unless I’m missing some historical context on why this is, it seems like at one point node would resolve to globally installed packages, but now it doesn’t because of where global modules are installed by npm.

$ npm --versions
npm: '6.9.0',
  ares: '1.15.0',
  brotli: '1.0.7',
  cldr: '35.1',
  http_parser: '2.8.0',
  icu: '64.2',
  modules: '64',
  napi: '4',
  nghttp2: '1.34.0',
  node: '10.16.0',
  openssl: '1.1.1b',
  tz: '2019a',
  unicode: '12.1',
  uv: '1.28.0',
  v8: '6.8.275.32-node.52',
  zlib: '1.2.11'
$ node -p process.platform
darwin

(I think things are working as intended so this is not a “bug” and I have moved to #support, but you might prefer it in #ideas. I think it sounds more like a node decision than an npm decision so agree with your first try!)

This page dates back to npm 1.0 and 2011 and suggests things are as intended. What has changed since then is that shell commands are now also encouraged to be local rather than global so that the dependencies can be managed within the project.

Hi, npm inventor and co-designer of Node.js’s original CommonJS module lookup algorithm here.

This is working as intended, and has been this way since node v0.4. Global packages are for cli utils you use everywhere, but with npx, that’s not even necessary.

Better to just install locally.

You can set the NODE_PATH environment variable to work around this if you really want to.

export NODE_PATH=$(npm root -g)

Voila.

Don’t do this. It’s a bad idea. Unless you know better, then you do you :slight_smile:

Yeah, I want to avoid having to set any environment variables, which is how I fell down this rabbit hole.

The scenario (although admittedly a corner case) is that I have a package that has a built in CLI, pretty normal stuff. This package has a peer dependency (which is actually how I solved the problem more or less), but I was hoping that, in the case where a user already had that peer dependency installed globally (and not yet as a peer), that my CLI package could crawl up and find it. My confusion started when I walked through the algorithm and that GLOBAL_FOLDERS was a list of directories that I have never seen used and look non-sensical (e.g. /usr/local/lib/node seems like it was either intended as a binary location, or a very old parent folder for node_modules). Or maybe these locations are for Windows machines, I’m not sure.

Anyway, I agree that modules should be installed locally over globally; I was just making the case that the algorithm didn’t behave as I expected. Why are those lookup paths called “GLOBAL_FOLDERS” if they are not actually where global modules are installed?

@isaacs @shadowspawn ?

Hello @bdharrington7 . What further replies were you hoping for? (I don’t want to join you down the rabbit hole. :rabbit2: )

If your flexibly located dependency has both an API and CLI, perhaps you could “require” the (local) API and fallback to calling the (global) CLI via spawn et al.