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

[WIP] Draft PR for adding imports to package.json #995

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

Conversation

siddarthkay
Copy link

@siddarthkay siddarthkay commented Jun 5, 2023

This is a WIP PR to just collect my thoughts and to ask questions about this implementation.
fixes #978

Summary

  • Add optional imports type to packageJson
  • Implement PACKAGE_IMPORTS_RESOLVE inside packages/metro-resolver/src/PackageImportsResolve.js as per spec at https://nodejs.org/api/esm.html#resolver-algorithm-specification
  • Do we need to Implement the methods PACKAGE_IMPORTS_RESOLVE depends on like ?:
  • lookupParentScope
  • readPackageJSON
  • packageImportsExportsResolver
  • packageTargetResolve
  • isValidURL
  • packageResolve
  • isBuiltinModule
  • PackageSelfResolve
  • PackageExportsResolve
  • update metro resolver to handle imports and to call logic at packages/metro-resolver/src/PackageImportsResolve.js

Test plan

tests must pass by running npm test

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 5, 2023
@siddarthkay siddarthkay marked this pull request as draft June 5, 2023 07:22
import path from 'path';
import fs from 'fs';
import * as url from 'url';
export function resolvePackageTargetsFromImports(specifier: string, parentURL, conditions){
Copy link
Member

Choose a reason for hiding this comment

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

Please update this function to use the existing ResolutionContext object, which provides APIs such as context.getPackageForModule() and context.doesFileExist().

  • This should enable your implementation to work without importing and using fs.
  • Removes the need for separate lookupParentScope and readPackageJSON utils.
  • Enables this function to read config options such as resolver.unstable_conditionNames.

The function should also be named to reflect returning a singular Target (typo). Together, the signature might look closer to:

export function resolvePackageTargetFromImports(
  context: ResolutionContext,
  importSpecifier: string,
  importsField: ExportMap,
  platform: string | null,
): FileResolution {

This also means we should move the specifier.startsWith('#') check externally, to around resolve.js#L52 and call this function with the parsed imports field if it exists.

}

if(specifier.startsWith('#/') || specifier === '#') {
throw Error('Invalid Module Specifier.');
Copy link
Member

@huntie huntie Jun 6, 2023

Choose a reason for hiding this comment

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

This should be replaced with a dedicated error type — this existed previously and can be copied over: https://github.com/facebook/metro/blob/47856447a885d695f781694e5200ca2c3adecc87/packages/metro-resolver/src/errors/InvalidModuleSpecifierError.js

Similarly for any other errors we're introducing from the Node.js spec.

return null;
}

function packageTargetResolve(packageURL, target, patternMatch, isImports, conditions) {
Copy link
Member

@huntie huntie Jun 6, 2023

Choose a reason for hiding this comment

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

Do we need to Implement the methods PACKAGE_IMPORTS_RESOLVE depends on[?]

We don't! 😄 packageTargetResolve and PackageExportsResolve are already implemented elsewhere in metro-resolver — please remove.

While this lines up 1:1 with the Node.js resolution algorithm, let's reuse what's available in the rest of the resolver code rather than reimplementing here — which (while not an exact match with Node's strategy) will respect other Metro resolution behaviours such as resolver.extraNodeModules.

Please look to locate the function call for resolvePackageTargetsFromImports() within the main resolve() function and use resolve() to evaluate the package target read from "imports" (updating context.originModulePath when calling this).

The control flow would look roughly like:

  • Within resolve()
    • if the import specifier (moduleName) begins with # AND if imports is in context.getPackageForModule(context.originModulePath)
      • get the result of resolvePackageTargetFromImports(context, moduleName, importsField, ...)
      • if a target was returned (containing the matched import specifier value from "imports"), call and return resolve(target)
      • else, fall through (will error after all other resolution steps)

@siddarthkay
Copy link
Author

@huntie : Thanks for taking the time to do a detailed PR review! I'll address the feedback 🙏🏻

@siddarthkay
Copy link
Author

Resuming work on this.

@kraenhansen
Copy link
Contributor

@siddarthkay do you have plans to continuing working on this?

Alternatively, I'd be interested in taking over the assignment of the original issue.

@siddarthkay
Copy link
Author

HI @kraenhansen : hmm, I'd be happy if you took it over. Thank you.

@siddarthkay
Copy link
Author

cc @huntie

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature: package.json "imports" field
4 participants