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

require() fails to resolve import map to core module (Node.js bug) #425

Open
3 of 5 tasks
firxworx opened this issue Dec 1, 2023 · 4 comments
Open
3 of 5 tasks
Labels
blocked bug Something isn't working

Comments

@firxworx
Copy link

firxworx commented Dec 1, 2023

Precheck

  • I searched existing issues before opening this one to avoid duplicates
  • I'm able to reproduce this issue and prove it with a minimal reproduction
  • I understand this is not a place to ask for free debugging support

Problem

tsx fails to import packages that in turn use subpath imports with the following error:
TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file

Subpath imports is a feature dating back to node v12.
Docs reference (current LTS): https://nodejs.org/api/packages.html#subpath-imports

Example error output:

> tsx src/index.ts

node:internal/url:1393
    throw new ERR_INVALID_URL_SCHEME('file');
          ^

TypeError [ERR_INVALID_URL_SCHEME]: The URL must be of scheme file

A noteworthy aspect of subpath imports is that they have a # character for the internal "package" name. I don't know about the inner workings of tsx however I suspect this could be relevant to the issue and why its not interpreted as a correct file url.

Expected behavior

tsx should Just WorkTM in this case and support packages that use this feature without issue.

Example

code with p-limit v5 (refer to the stackblitz repro) should run correctly i.e. without error just as it would with p-limit v4 which does not have subpath imports.

I think p-limit is a very representative example of a package that any developer would expect tsx to be able to support: 84,485,661 weekly downloads, and as a sindresorhus package it is 100% ESM.

Here is the v4 vs. v5 release diff with a hash link to exactly the line of code with subpath import that appears in the error trace:
sindresorhus/p-limit@v4.0.0...v5.0.0#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346R2

Thanks for your work on tsx, this project was a lifesaver for me on a project when I first discovered it!

Minimal reproduction URL

https://stackblitz.com/edit/node-pqu7ir?file=index.ts

Version

v4.6.1

Node.js version

v20.10.0

Package manager

pnpm

Operating system

Linux

Contributions

  • I plan to open a pull request for this issue
  • I plan to make a financial contribution to this project
@firxworx firxworx added bug Something isn't working pending triage labels Dec 1, 2023
@privatenumber
Copy link
Owner

privatenumber commented Dec 1, 2023

This is a bug or limitation in Node.js that is not resolving core modules in import maps when using require():
https://stackblitz.com/edit/node-cimhvu?file=index.js

Please report it in Node. As a side, it's also worth mentioning that the node: protocol should work there too.

@privatenumber privatenumber changed the title tsx fails w/ imports of packages that have node subpath imports: TypeError [ERR_INVALID_URL_SCHEME] require() fails to resolve import map to core module (Node.js bug) Dec 1, 2023
@firxworx
Copy link
Author

firxworx commented Dec 2, 2023

Thanks for weighing in @privatenumber, I reported to node.

I'm not sure if its worth noting to you that I noticed tsx behaves differently when I add "type": "module" to the package.json file.

With explicit "module" this particular issue disappeared (I assume because tsx would not use require() under the hood) however gave rise to a new issue where the import alias paths would not resolve (!)

In the tsconfig everything was setup for ESM (e.g. "module": "ESNext") so it surprised me that under the hood tsx would choose to use require().

It also seems to have no problem with ESM-only dependencies even when it apparently chooses require() under the hood.

Import aliases that Just Work are my top use-case for tsx! Import alias / library path hassles and issues with Nx are exactly what lead me to this project in the first place!


background context of the use-case

The affected project is an Nx monorepo that has web apps, shared libraries, and a cli app used for administration and by ci/cd.

In this typical Nx configuration there is a package.json in monorepo root with consolidated dependencies for the whole project, plus a common tsconfig.base.json which is where import path aliases for all the different libraries/packages within the monorepo are centrally defined (e.g. @myproject/my-library).

In my case my cli lib (e.g. ./packages/project-cli) has a package.json "stub" (for defining name, description, etc. with no dependencies listed in it -- Nx can be configured to generate a "full" one that includes only that lib's deps on build).

Also typical of Nx projects in this configuration, the cli lib has its own a tsconfig.json that extends the tsconfig.base.json.

When running tsx I pass it the --tsconfig to point to the cli's tsconfig.

I don't understand why tsx would fail to resolve the import path aliases in this case with "module" in package.json.

@privatenumber
Copy link
Owner

however gave rise to a new issue where the import alias paths would not resolve

If it's a bug, feel free to file an issue.

In the tsconfig everything was setup for ESM (e.g. "module": "ESNext") so it surprised me that under the hood tsx would choose to use require().

tsx doesn't read that value. It could preserve the ESM, but then Node would error that it can't handle ESM in a CJS context (defined by your package.json#type). Feel free to file an issue to emit a warning here.

It also seems to have no problem with ESM-only dependencies even when it apparently chooses require() under the hood.

Easing the ESM migration in Node is one of tsx's biggest selling points.

(Also, I don't mean to be rude but please keep your comments short and concise.)

@firxworx
Copy link
Author

firxworx commented Dec 4, 2023

@privatenumber No worries, I wasn't sure if you would consider the differing behaviour to be a bug or not. I will leave it for now.

Good to know that tsx doesn't consider tsconfig.json module setting.

Sorry for writing out the use-case with Nx and if that was too verbose. I've found reporting issues with a monorepo in the mix a lot of project contributors weren't familiar with the differences.

Thanks a million for your work on tsx!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants