Skip to content

--preserve-symlinks and --experimental-specifier-resolution=node fails to find file without extension #47649

Description

@znewsham

Version

16.20

Platform

Linux ed7d7cb37749 5.19.0-38-generic #39~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 17 21:16:15 UTC 2 x86_64 GNU/Linux

Subsystem

No response

What steps will reproduce the bug?

create two JS files:

// index.js
import "./test"
// test.js
// whatever

and a package.json

{ "type": "module" }

run:

node  --preserve-symlinks --experimental-specifier-resolution=node index.js

How often does it reproduce? Is there a required condition?

Always.

What is the expected behavior? Why is that the expected behavior?

It should be able to find the correct JS file without an extension

What do you see instead?

[Error: ENOENT: no such file or directory, open '/path/to/test'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: '/path/to/test'
}

Additional information

This worked correctly in node 14. I know this flag is going away in node 19, but I don't really want to have to implement an entire loader just to get extensionless loading working the same as it did in 14 - particularly irksome because the loader API changed between 14 and 16, so to support both versions of node I need to support both these experimental features.

Adding the .js extension isn't practical.

The error is caused by this code in internal/modules/esm/resolve

  if (!preserveSymlinks) {
    const real = realpathSync(path, {
      [internalFS.realpathCacheKey]: realpathCache
    });
    const { search, hash } = resolved;
    resolved =
        pathToFileURL(real + (StringPrototypeEndsWith(path, sep) ? '/' : ''));
    resolved.search = search;
    resolved.hash = hash;
  }

  return resolved;

there should probably be an else:

else { 
  resolved = path
}

Activity

  1. aduh95 commented on Apr 22, 2023

    @aduh95
    Contributor

    --experimental-specifier-resolution=node is experimental and has been removed as of Node.js 19.0.0. Consider switching to using custom loaders, as the runtime warning asks you to do.

  2. znewsham commented on Apr 22, 2023

    @znewsham
    ContributorAuthor
  3. aduh95 commented on Apr 22, 2023

    @aduh95
    Contributor

    The only way to find out pull be to open a PR against v18.x-staging and see if it goes through, but I wouldn’t be too optimistic about it, typically no changes can land on an LTS line without a “maturation period” on a Current release line. The final decision is up to @nodejs/lts, maybe they can say more on the process and the success chances of such PR.

  4. richardlau commented on Apr 22, 2023

    @richardlau
    Member

    @aduh95 It's not impossible for such a change to land in an active LTS line -- it would depend on how complicated/risky the change looks and we'd probably want some sort of sign off/review/ok from the relevant team (@nodejs/loaders ?). If the change would only be behind an experimental flag that would count positively towards it.

    Changing Node.js 16 (in maintenance) is almost certainly out ruled out.

  5. GeoffreyBooth commented on Apr 22, 2023

    @GeoffreyBooth
    Member

    The loaders team is very resource constrained and it’s not a worthwhile use of their time to devote any effort into bugfixing a removed API.

    I would oppose landing something in the 18.x line only, as 20.x is very new and few users have migrated to it yet; and 16.x is in maintenance mode, leaving 18.x as our most widely used active LTS line.

  6. znewsham commented on Apr 22, 2023

    @znewsham
    ContributorAuthor

    Thanks for your comments all - I opened a PR, the change is very simple and I believe safe. If it doesn't get merged, so be it

    #47674

  7. aduh95 commented on Apr 23, 2023

    @aduh95
    Contributor

    @znewsham I know of https://github.com/nodejs/loaders-test/tree/main/commonjs-extension-resolution-loader that aims at doing this specifically, not sure it's been published on npm though.

  8. znewsham commented on Apr 23, 2023

    @znewsham
    ContributorAuthor

    That's amazing, thanks! At the very least I can see how they work, and I might swap to using that rather than my own! It's also a lot simpler than mine 🤔 I guess the resolve package deals with most of the complexity

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