privatenumber / tsx

⚡️ TypeScript Execute | The easiest way to run TypeScript in Node.js
https://tsx.is
MIT License
9.79k stars 154 forks source link

`ERR_UNSUPPORTED_ESM_URL_SCHEME` when dyanmic import in windows #345

Closed tangdaoyuan closed 5 months ago

tangdaoyuan commented 2 years ago

Description

In windows, Using dynamic import with absolute path cause ERR_UNSUPPORTED_ESM_URL_SCHEME error

image

Reproduction

  1. create a.ts file following
    
    import path from "path";

const abs_path = path.resolve('./b.ts', ); // absolute path import(abs_path)



2. run  `node --loader @esbuild-kit/esm-loader a.ts`

### extra

`tsx`  has same error.
privatenumber commented 2 years ago

Apparently this is by design: https://github.com/nodejs/node/issues/34765#issuecomment-674096790

Does this work in any other Windows environments? eg. different versions of Node.js or TypeScript

tangdaoyuan commented 2 years ago

Apparently this is by design: nodejs/node#34765 (comment)

Does this work in any other Windows environments? eg. different versions of Node.js or TypeScript

It works after temp fix in win10 with typescript v4.5 ~ v4.8, node v12.20.0, node v14.20.0, node 16.14.2. I have no other windows enviroments, so I try to create a repo for more tests by github actions.

here is test actions:

privatenumber commented 11 months ago

Feel free to open a PR

TimPietrusky commented 10 months ago

I ran into the same issue, but I got it working when using not an absolute path, but a relative path as configured in the path of tsconfig:

tsconfig

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
}

dynamic import The file that I want to import exists at src/mydynamicimport.ts.

const name = "mydynamicimport";
await import(`@/${name}`);

Actual problem: absolute path on Windows

So the "issue" here is the usage of an absolute path, which is not working on Windows. You would have to use a proper URL:

import path from "node:path";
import { pathToFileURL } from "node:url";

export async function dynamicImport(fullPath: string) {
  const fileURL = pathToFileURL(fullPath).href;
  return import(fileURL);
}

// Usage example, assuming your mydynamicimport.ts is inside of "src"
await dynamicImport(path.join(process.cwd(), "src", "mydynamicimport"));

This will produce an URL like this: file:///D:/src/mydynamicimport.

so1ve commented 9 months ago

It works when dynamic importing a literal:

import('file:///D:/foo.ts') works

so1ve commented 9 months ago

Is https://github.com/esbuild-kit/esm-loader/pull/39 a proper fix? I'd like to back-port it to tsx if it works.

privatenumber commented 8 months ago

I'm currently wondering if this is even a tsx issue, or if this is a Node.js issue ya'll are trying to patch with tsx?

Specifically, does this work in Node (no tsx) on Windows?

import path from "path"

const abs_path = path.resolve('./b.ts', );  // absolute path
import(abs_path)

To determine this, I'd throw the above snippet in a GitHub repo with CI on ubuntu and windows running it.

mvarendorff commented 5 months ago

@privatenumber very much appears to be a Node issue itself

grafik

privatenumber commented 5 months ago

Thanks for verifying @geisterfurz007

Closing as it's expected behavior.