Skip to content

Commit

Permalink
Resolve symlinked modules correctly (#92)
Browse files Browse the repository at this point in the history
Some systems (e.g. rush, pnpm) use symlinks to create a recursive dependency graph
instead of relying on the hoisting aspect of the node module resolution algorithm (like npm and yarn do)
in these cases, we want to resolve to the real path of a module, so that the tree structure below
only ever tries to run the `x` module once (rather than once on each module that depends on it)

- node_modules
  - a
    - node_modules
      - symlink to x
  - b
    - node_modules
      - symlink to x

Co-authored-by: Ryan Tsao <ryan.j.tsao@gmail.com>
  • Loading branch information
lhorie and rtsao committed Feb 11, 2020
1 parent 427bb88 commit d7f9908
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 7 deletions.
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
language: node_js
node_js:
- "0.8"
- "0.10"
- "4"
- "5"
- "6"
- "8"
- "10"
- "12"
20 changes: 19 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ function build_resolve_opts(opts, base) {
return opts;
}

function resolve(id, opts, cb) {
function resolve(id, opts, callback) {

// opts.filename
// opts.paths
Expand All @@ -216,6 +216,24 @@ function resolve(id, opts, cb) {
opts = opts || {};
opts.filename = opts.filename || '';

var cb = function(err, path, pkg) {
fs.stat(path, function(notPath) {
if (notPath) {
callback(err, path, pkg);
}
else {
fs.realpath(path, function(notReal, real) {
if (notReal) {
callback(err, path, pkg);
}
else {
callback(err, real, pkg);
}
});
}
});
}

var base = path.dirname(opts.filename);

if (opts.basedir) {
Expand Down
136 changes: 136 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"empty.js"
],
"scripts": {
"test": "mocha --reporter list test/*.js"
"test": "node scripts/setup-symlinks.js && mocha --reporter list test/*.js"
},
"repository": {
"type": "git",
Expand Down
10 changes: 10 additions & 0 deletions scripts/setup-symlinks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
var fs = require('fs');

try {
fs.mkdirSync(__dirname + '/../test/fixtures/node_modules/linker/node_modules');
} catch (e) {}
process.chdir(__dirname + '/../test/fixtures/node_modules/linker/node_modules');
try {
fs.unlinkSync('linked');
} catch (e) {}
fs.symlinkSync('../../../linked', 'linked', 'dir');
1 change: 1 addition & 0 deletions test/fixtures/linked/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// dummy
1 change: 1 addition & 0 deletions test/fixtures/node_modules/linker/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions test/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,25 @@ test('not fail on accessing path name defined in Object.prototype', function (do
done();
});
});

test('respect symlinks', function (done) {
// some systems (e.g. rush, pnpm) use symlinks to create a recursive dependency graph
// instead of relying on the hoisting aspect of the node module resolution algorithm (like npm and yarn do)
// in these cases, we want to resolve to the real path of a module, so that the tree structure below
// only ever tries to run the `x` module once (rather than once on each module that depends on it)
//
// - node_modules
// - a
// - node_modules
// - symlink to x
// - b
// - node_modules
// - symlink to x
//
resolve('linked', { paths: [ fixtures_dir + '/linker/node_modules' ], package: { main: 'fixtures' } }, function(err, path, pkg) {
assert.ifError(err);
assert.equal(path, require.resolve('./fixtures/linked/index'));
assert.strictEqual(pkg, undefined);
done();
});
});

0 comments on commit d7f9908

Please sign in to comment.