镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content
This repository was archived by the owner on Sep 2, 2023. It is now read-only.
This repository was archived by the owner on Sep 2, 2023. It is now read-only.

Enabling import meta resolve by default? #550

Description

@daKmoR

When using esm there seems to be no way to resolve paths to a packages 🤔

In a commonjs project, I currently have this "gem" 😅

/**
 * Resolves a file/folder path that can contain bare modules.
 *
 * @example
 * resolvedNodePackagePath('@foo/bar/some-folder');
 * => /absolute/path/node_modules/@foo/bar/some-folder
 *
 * resolvedNodePackagePath('@foo/bar');
 * => /absolute/path/node_modules/@foo/bar/
 *
 * @param {string} resolvePath Path to resolve
 * @return {string} Resolved path
 */
function resolvedNodePackagePath(resolvePath) {
  const hasNamespace = resolvePath.includes('@');
  const parts = resolvePath.split(path.sep);
  const pkgName = hasNamespace ? path.join(parts[0], parts[1]) : parts[0];
  parts.shift();
  if (hasNamespace) {
    parts.shift();
  }
  const purePath = path.join(...parts);
  const pkgJson = require.resolve(path.join(pkgName, 'package.json'));
  const pkgRoot = path.dirname(pkgJson);
  return path.join(pkgRoot, purePath);
}

with --experimental-import-meta-resolve I can basically replace resolvedNodePackagePath with await import.meta.resolve(...).

However, as long as it's an experimental flag it is kind of a tough sell to users and additionally, it requires some trickery for bins 😅

So hence my question any chance this is going to be unflagged any time soon?

Activity

  1. guybedford commented on Aug 31, 2020

    @guybedford
    Contributor

    Because import.meta.resolve is a common API between platforms, we need some interest from other implementers before unflagging.

    Domenic has made a similar proposal for the browser with roughly the same API, but as a synchronous variant - whatwg/html#5572. The sync / async concern between browsers and Node.js is a tricky one to get agreement on, which is tricky without any open standards space to truly discuss this stuff.

    I've posted an issue to Deno to see if there is interest here - denoland/deno#7296.

  2. guybedford commented on Aug 31, 2020

    @guybedford
    Contributor

    Also I do think it's a critical part of the implementation since require.resolve is such a standard workflow in CommonJS. I really hope we don't allow the lack of collaborative standards in the cross-platform modules space to slow this down.

  3. guybedford commented on Aug 31, 2020

    @guybedford
    Contributor

    I've added the meeting agenda label, let's try to discuss this further.

  4. MylesBorins commented on Sep 1, 2020

    @MylesBorins
    Contributor

    I think we had previously discussed exposing this as module.resolve which I would not be opposed to. It would be preferable for the semantics of import.meta.resolve to be similar cross platform, although I do recognize that import.meta is intended to be a bag for embedders to put things on. Another alternative could be import.meta.node.resolve or import.meta.nodeResolve

    Thoughts?

  5. hybrist commented on Sep 1, 2020

    @hybrist
    Contributor

    I think we had previously discussed exposing this as module.resolve which I would not be opposed to.

    One minor thing consideration there is conditional resolution. import.meta.resolve "clearly" uses import-relative resolution. require.resolve "clearly" uses require-relative resolution. module.resolve could be either or even take the context as another argument if we wanted. E.g. module.resolve(specifier, contextURL, contextConditions = ["require"]) or module.resolve(specifier, contextURL, fromRequire = true).

  6. bmeck commented on Sep 1, 2020

    @bmeck
    Member

    I do like the API being usable to determine either require or import personally.

  7. guybedford commented on Sep 1, 2020

    @guybedford
    Contributor

    The major blocker to import.meta.resolve is the sync / async issue between what is proposed for the browser and what is needed for Node.js. What do people think about just making this sync to align with Domenic's proposal and to try and move forward with that?

    @bmeck do you mean via the distinction of require.resolve and import.meta.resolve, or do you mean enabling an option into the resolve function?

    To explain the benefits of import.meta.resolve over a custom resolver, it's worth mentioning https://github.com/vercel/webpack-asset-relocator-loader.

    Consider loading a template:

    const template = await (await fetch(await import.meta.resolve('pkg/template.html')).text();

    It is possible for the build tool to use the import.meta.resolve expression as something to statically analyze to determine that an asset is being referenced, and then rewrite this in the build to something like:

    const template = await (await fetch(import.meta.url + '../assets/template.html'))

    where assets are relocated by the build process based on their references.

    The other benefit is that this resolver pattern can be transferrable between runtimes, instead of needing some advanced "superResolve" library that can work cross-environment.

  8. bmeck commented on Sep 2, 2020

    @bmeck
    Member

    do you mean via the distinction of require.resolve and import.meta.resolve, or do you mean enabling an option into the resolve function?

    I mean having 1 function that I can throw data into that handles all the basic resolutions I might be curious about. This is not in any way critical as if we have N functions I can just wrap them into a single function anyway.

  9. MylesBorins commented on Oct 7, 2020

    @MylesBorins
    Contributor

    Removing from agenda for now. We can bring this up again if we want to revisit

  10. daKmoR commented on Feb 23, 2021

    @daKmoR
    Author

    just ran into this again and the "hack" won't work anymore 😅

    e.g. require.resolve(path.join(pkgName, 'package.json')); will fail if the pkgName has exports in the package.json defined.

    And I guess basically, no one will have an export map like

    "exports": {
       "package.json": "./package.json"
    }

    what I want to do is read the package.json to create an import map based on the exports in there.

    My idea is to resolve the package directory and then do a regular fs.readFile. Why do I want to use the node solution for that? I am not sure in which node_modules folder my package is... e.g. is it in the root or in some nested node_modules

    sooo is there any other way to resolve the package directory?

    strawman proposal

    const pkgPath = import.meta.resolvePackage('@foo/bar'); // <<<<------ new method?
    const pkgJsonStream = await fs.promises.readFile(path.join(pkgPath, 'package.json'));
    const pkgJson = JSON.parse(pkgJsonStream.toString());
    
    const keys = Object.keys(pkgJson.exports);
    for (let i = 0; i < keys.length; i += 1) {
      const exportKey = keys[i];
      const exportValue = pksJson.exports[i];
      
      // add exportsKey to import map
      
      // resolve dependency package? - e.g. check if it's also in the root or a sub node_modules folder
      const dependency = mport.meta.resolvePackage('@foo/bar', exportValue);
      // ... recursive go through dependency tree
    }

    hmmm or would it better to "just" walk the node_modules folders myself 🤔

  11. borkdude commented on Apr 16, 2022

    @borkdude

    I ran into this issue where require.resolve would not find an ESM .js file, so I fell back on using https://github.com/wooorm/import-meta-resolve for now, until import.meta.resolve is officially available. Or is it a reasonable requirement to ask people to always use the --experimental-import-meta-resolve flag when using certain libraries in the Node.js ecosystem?

  12. GeoffreyBooth commented on Apr 17, 2022

    @GeoffreyBooth
    Member

    Or is it a reasonable requirement to ask people to always use the --experimental-import-meta-resolve flag when using certain libraries in the Node.js ecosystem?

    It’s not reasonable to ask users to use any experimental feature. By definition, experimental features could change or disappear at any time.

    This one in particular seems unlikely to ship in its current form, per whatwg/html#5572 (comment)

  13. chaoyangnz commented on May 3, 2022

    @chaoyangnz

    same issue here, why was this closed?

  14. regseb commented on Apr 18, 2023

    @regseb

    The import.meta.resolve() method has become synchronous in Node v20, but you still need the --experimental-import-meta-resolve flag.

    Synchronous import.meta.resolve()

    In alignment with browser behavior, this function now returns synchronously. Despite this, user loader resolve hooks can still be defined as async functions (or as sync functions, if the author prefers). Even when there are async resolve hooks loaded, import.meta.resolve will still return synchronously for application code.

    Contributed by Anna Henningsen, Antoine du Hamel, Geoffrey Booth, Guy Bedford, Jacob Smith, and Michaël Zasso in nodejs/node#44710

  15. GeoffreyBooth commented on Sep 1, 2023

    @GeoffreyBooth
    Member

    This is resolved by 20.6.0 whenever it ships.

  16. borkdude commented on Sep 2, 2023

    @borkdude

    Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions