Skip to content

Commit

Permalink
Make NodeResolver check realpath before resolving with source entry (
Browse files Browse the repository at this point in the history
  • Loading branch information
g6123 committed Mar 20, 2022
1 parent bbf419a commit 63f2a18
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 138 deletions.
1 change: 1 addition & 0 deletions packages/utils/node-resolver-core/.gitignore
@@ -1 +1,2 @@
!/test/fixture/node_modules
!/test/fixture/node_modules/.pnpm/*/node_modules
12 changes: 9 additions & 3 deletions packages/utils/node-resolver-core/src/NodeResolver.js
Expand Up @@ -906,11 +906,17 @@ export default class NodeResolver {
pkg.pkgfile = file;
pkg.pkgdir = dir;

// If the package has a `source` field, check if it is behind a symlink.
// If so, we treat the module as source code rather than a pre-compiled module.
// If the package has a `source` field, make sure
// - the package is behind symlinks
// - and the realpath to the packages does not includes `node_modules`.
// Since such package is likely a pre-compiled module
// installed with package managers, rather than including a source code.
if (pkg.source) {
let realpath = await this.fs.realpath(file);
if (realpath === file) {
if (
realpath === file ||
realpath.includes(`${path.sep}node_modules${path.sep}`)
) {
delete pkg.source;
}
}
Expand Down

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

246 changes: 111 additions & 135 deletions packages/utils/node-resolver-core/test/resolver.js
Expand Up @@ -47,6 +47,13 @@ describe('resolver', function () {
path.join(rootDir, 'packages/source'),
path.join(rootDir, 'node_modules/source'),
);
await outputFS.symlink(
path.join(
rootDir,
'node_modules/.pnpm/source-pnpm@1.0.0/node_modules/source-pnpm',
),
path.join(rootDir, 'node_modules/source-pnpm'),
);
await outputFS.symlink(
path.join(rootDir, 'packages/source-alias'),
path.join(rootDir, 'node_modules/source-alias'),
Expand Down Expand Up @@ -2074,152 +2081,121 @@ describe('resolver', function () {
});

describe('source field', function () {
it('should use the source field when symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'packages', 'source', 'source.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'source', 'package.json'),
],
describe('package behind symlinks', function () {
it('should use the source field, when its realpath is not under `node_modules`', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'packages', 'source', 'source.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'source', 'package.json'),
],
});
});
});

it('should not use the source field when not symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-not-symlinked',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'source-not-symlinked',
'dist.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-not-symlinked',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
it('should not use the source field, when its realpath is under `node_modules`', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-pnpm',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'source-not-symlinked',
'package.json',
'.pnpm',
'source-pnpm@1.0.0',
'node_modules',
'source-pnpm',
'dist.js',
),
],
});
});

it('should use the source field as an alias when symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-alias/dist',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(rootDir, 'packages', 'source-alias', 'source.js'),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-alias',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'source-alias', 'package.json'),
],
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-pnpm',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(rootDir, 'node_modules', 'source-pnpm', 'package.json'),
],
});
});
});

it('should use the source field as a glob alias when symlinked', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-alias-glob',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'packages',
'source-alias-glob',
'src',
'test.js',
),
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-alias-glob',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
describe('package not behind symlinks', function () {
it('should not use the source field', async function () {
let resolved = await resolver.resolve({
env: BROWSER_ENV,
filename: 'source-not-symlinked',
specifierType: 'esm',
parent: path.join(rootDir, 'foo.js'),
});
assert.deepEqual(resolved, {
filePath: path.join(
rootDir,
'node_modules',
'source-alias-glob',
'package.json',
'source-not-symlinked',
'dist.js',
),
],
sideEffects: undefined,
query: undefined,
invalidateOnFileCreate: [
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'index'),
},
{
fileName: 'package.json',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
{
fileName: 'node_modules/source-not-symlinked',
aboveFilePath: path.join(rootDir, 'foo.js'),
},
],
invalidateOnFileChange: [
path.join(rootDir, 'package.json'),
path.join(
rootDir,
'node_modules',
'source-not-symlinked',
'package.json',
),
],
});
});
});
});
Expand Down

0 comments on commit 63f2a18

Please sign in to comment.