Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(resolve): make tryNodeResolve more robust #9170

Closed
wants to merge 12 commits into from

Conversation

aleclarson
Copy link
Member

@aleclarson aleclarson commented Jul 17, 2022

⚠️ Merge #10504 before this

Description

The "{id}/package.json" lookup done by resolvePackageData is insufficient for certain edge cases, like when "node_modules/{dep}" is linked to a directory without a package.json in it. With this PR, you can now import any file from node_modules even if it has no package.json file associated with it. This mirrors the same capability in Node's resolution algorithm.

Probably fixes #6061 as reported by @sodatea here, since the getPossibleModuleIds function now includes the full module ID (even if it has an extension) in the returned array.

Additional context

Help wanted with testing...

Here's a (non-exhaustive?) list of cases that should be supported now:

  • import foo/bar when node_modules/foo/bar.js exists without package.json
  • import xyz when node_modules/xyz.js exists
  • import xyz when node_modules/xyz/index.js exists without package.json

edit: Tests added!


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

@aleclarson aleclarson force-pushed the fix/flexible-node-resolve branch from 488e9ee to 02ddba9 Compare July 17, 2022 17:08
if (!pkg) {
return
}
const nodeModules = lookupNodeModules(basedir)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lookupNodeModules is an alias for the built-in Module._nodeModulePaths function

This is the same way Node.js gets the node_modules directories to check for dependencies in.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern I have is that this function produces node_modules directories outside of the importer's root directory (which I would define as the directory with .git, although we might also want to consider SVN or Mercurial support too). It feels wrong for a bundler to allow node_modules access outside the root directory, as this isn't reproducible by default outside the current machine. Any opinions on this, @patak-dev?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should let the user access the folder they whitelisted for fs access? Even if they are out of the .git root?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continued here: #9170 (comment)

packages/vite/src/node/plugins/resolve.ts Show resolved Hide resolved
packages/vite/src/node/plugins/resolve.ts Outdated Show resolved Hide resolved
packages/vite/src/node/plugins/resolve.ts Outdated Show resolved Hide resolved
packages/vite/src/node/plugins/resolve.ts Outdated Show resolved Hide resolved
@@ -506,8 +512,10 @@ function tryResolveFile(
}
}
}
const index = tryFsResolve(file + '/index', options)
if (index) return index + postfix
const indexFile = tryIndexFile(file, targetWeb, options)
Copy link
Member Author

@aleclarson aleclarson Jul 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change avoids checking for {file}/index/index or {file}/index/package.json, both of which would be incorrect if found.


let basedir: string
if (dedupe?.some((id) => possiblePkgIds.includes(id))) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for possiblePkgIds anymore with the new logic, as long we assume the resolve.dedupe array only ever references package IDs and not module IDs. This assumption makes sense to me!

Bug introduced in vitejs#10683

Some packages use "require" instead of "default" for CJS entry
…in the `getInlineConditions` function.
…and avoid breaking certain `tryFsResolve` calls too (like with `es5-ext`)
The "{id}/package.json" lookup done by `resolvePackageData` is insufficient for certain edge cases, like when "node_modules/{dep}" is linked to a directory without a package.json in it. With this PR, you can now import any file from node_modules even if it has no package.json file associated with it. This mirrors the same capability in Node's resolution algorithm.

In addition to supporting more edge cases, this new implementation might also be faster in some cases, since we are doing less lookups than compared to the previous behavior of calling `resolvePackageData` for every path in the `possiblePkgIds` array.
@aleclarson aleclarson force-pushed the fix/flexible-node-resolve branch from 85d90b1 to f62843d Compare November 14, 2022 20:39
@aleclarson
Copy link
Member Author

Just rebased onto main

@aleclarson aleclarson requested review from bluwy and sapphi-red and removed request for bluwy November 14, 2022 20:40
@aleclarson aleclarson added the p4-important Violate documented behavior or significantly improves performance (priority) label Nov 14, 2022
@aleclarson aleclarson force-pushed the fix/flexible-node-resolve branch from e303e99 to fff33dc Compare November 14, 2022 22:43

const workspaceRootFiles = ['lerna.json', 'pnpm-workspace.yaml', '.git']

export function isWorkspaceRoot(
Copy link
Member Author

@aleclarson aleclarson Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using searchForWorkspaceRoot, I added this function, which takes advantage of the packageCache. It also only checks the given directory, instead of an upward traversal.

@bluwy
Copy link
Member

bluwy commented Apr 1, 2023

We've recently reworked tryNodeResolve and tryFsResolve for Vite 4.3, and it changes a lot of what's done here. I think we have a more robust resolver now, but the test case here and "node_modules/{dep}" is linked to a directory without a package.json in it could be interesting to support still.

I think it'll be easier to open a new PR for this if there's interest in it. Closing for now.

@bluwy bluwy closed this Apr 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p4-important Violate documented behavior or significantly improves performance (priority)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Production build fails in runtime after update to 2.7.1
3 participants