Search code examples
node.jsnpmcachingsymlinkpackage-managers

Symlink to a custom-made cache in the node_modules folder


I am writing my own package manager for NodeJS. Any installed packages are stored in a node-cache folder like this:

node-cache/[email protected]
node-cache/[email protected]

It is important that packages are named package@version so that multiple versions can be stored inside the cache. When adding a package to a NodeJS project, the node modules folder will contain symlinks to the cache like so:

/node_modules/x -> /node-cache/[email protected]
/node_modules/y -> /node-cache/[email protected]

I got my code to do this, and tested the following case:

// project/index.js
require("x");

With the /node-cache and project/node_modules structured as the examples I showed above. I also made it so that [email protected] does a require("y"), to ensure packages can correctly resolve each other in the cache.

I also set the env variable NODE_PATH to the /node-cache path to ensure modules are resolved in the cache directory and not locally. When running node index.js, [email protected] loads pefectly fine and is resolved. However [email protected] is not resolved and I get this error:

node:internal/modules/cjs/loader:1078
  throw err;
  ^

Error: Cannot find module 'y'
Require stack:
- C:\Users\samal\AppData\Local\node-cache\[email protected]\index.js
- A:\Downloads\test\index.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15)
    at Module._load (node:internal/modules/cjs/loader:920:27)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (C:\Users\samal\AppData\Local\node-cache\[email protected]\index.js:1:11)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    'C:\\Users\\samal\\AppData\\Local\\node-cache\\[email protected]\\index.js',
    'A:\\Downloads\\test\\index.js'
  ]
}

This happens because of the fact my cached files are named package@version instead of just package, which I need to cache multiple versions of the same package. Node is searching for /node-cache/y as require()'d by [email protected], however there is only a /node-cache/[email protected]. Removing the NODE_PATH env variable produces the same error.

I was wondering, what is the best solution to this without forcing the user to do any extra unneccesary work to get the package manager working, while maintaining its fast speed, and using symlinks or anything that doesn't require file system copies?


Solution

  • The solution is actually very simple. The solution is to use the --preserve-symlinks flag. For example node --preserve-symlinks index.js.

    This ensures that the symlinks are resolved locally rather than in the cache, which is how this is meant to work.