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

module: package imports targets outside package #52641

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

bmeck
Copy link
Member

@bmeck bmeck commented Apr 22, 2024

this allows the imports field of package.json to target a location outside of the package boundary. doing so allows for imports to work in directories just altering things like the type field of package.json and to enable monorepo workspace workflows.


Node already allows resolving to external packages for "imports"; this fixes some usability problems of mixing monorepos and directories containing a {"type":"module"} (or vice versa) package.json preventing the ability to properly use "imports" to resolve to reasonable locations. It does not enable .. in a specifiers to escape still per the tests it must be in the target of the package.json to allow escaping.

An example of a case where this feature is high friction is:

/app/package.json => {"type":"module","imports": ...}
/app/bin/package.json => {"type":"commonjs"} -- cannot use any "imports", even if redeclared in /app/bin

Note: this still requires duplication of imports for this use case with this PR.

Another example is in a monorepo situation:

/app/lib
/app/workspaces/a -- cannot reference /app/lib using "imports"

this allows the imports field of package.json to target a location
outside of the package boundary. doing so allows for imports to work
in directories just altering things like the type field of package.json
and to enable monorepo workspace workflows.
@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/loaders

@nodejs-github-bot nodejs-github-bot added esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run. labels Apr 22, 2024
Copy link
Member

@GeoffreyBooth GeoffreyBooth left a comment

Choose a reason for hiding this comment

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

Overall looks great, thanks for contributing this!

@@ -485,7 +485,7 @@ where `import '#dep'` does not get the resolution of the external package
file `./dep-polyfill.js` relative to the package in other environments.

Unlike the `"exports"` field, the `"imports"` field permits mapping to external
packages.
packages and locations.
Copy link
Member

Choose a reason for hiding this comment

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

@@ -414,7 +416,8 @@ function resolvePackageTargetString(
const resolvedPath = resolved.pathname;
const packagePath = new URL('.', packageJSONUrl).pathname;

if (!StringPrototypeStartsWith(resolvedPath, packagePath)) {
// if (mustBeInternalTarget && !StringPrototypeStartsWith(resolvedPath, packagePath)) {
Copy link
Member

Choose a reason for hiding this comment

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

Unsure why this is here.

Suggested change
// if (mustBeInternalTarget && !StringPrototypeStartsWith(resolvedPath, packagePath)) {

@@ -465,14 +468,15 @@ function isArrayIndex(key) {
* @param {boolean} internal - Whether the package is internal.
* @param {boolean} isPathMap - Whether the package is a path map.
* @param {Set<string>} conditions - The conditions to match.
* @param {boolean} mustBeInternalTarget - If the target must be in the package boundary.
Copy link
Member

Choose a reason for hiding this comment

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

This might be a bit much for a JSDoc comment, but is it possible to briefly explain when we would want this restriction? Is it like If the target must be in the package scope: yes for "exports", no for "imports"?

@@ -26,6 +26,10 @@ const { requireImport, importImport } = importer;
['#subpath//asdf.asdf', { default: 'test' }],
// Double slash
['#subpath/as//df.asdf', { default: 'test' }],
// Target steps below the package base
['#belowbase', { default: 'belowbase' }],
Copy link
Member

Choose a reason for hiding this comment

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

I know this is what it was called previously, but why is this “below” the base and not above the base?

@GeoffreyBooth GeoffreyBooth added the module Issues and PRs related to the module subsystem. label Apr 24, 2024
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

@RafaelGSS does this needs to do anything specific for permissions?

@@ -587,6 +591,7 @@ function packageExportsResolve(
const resolveResult = resolvePackageTarget(
packageJSONUrl, target, '', packageSubpath, base, false, false, false,
conditions,
true,
Copy link
Member

Choose a reason for hiding this comment

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

I know it's not new in this PR, but I'm not a big fan of bare boolean arguments like this where someone can't tell at a glance what the true or false means when looking at the callsite. For this, adding comments like... the following example would be helpful:

  const resolveResult = resolvePackageTarget(packageJSONUrl, target, '', packageSubpath, base,
     false /* pattern */,
     false /* internal */,
     false /* isPathMap */,
     conditions,
     true /* mustBeInternalTarget */);

But not blocking for this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
esm Issues and PRs related to the ECMAScript Modules implementation. module Issues and PRs related to the module subsystem. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants