tsx
tsx copied to clipboard
Cannot import named export from a typescript file in a workspace package if entry is using es modules and other package is not.
Cannot import named export from a typescript file in a workspace package if entry is using es modules and other package is not.
tsx will throw
SyntaxError: The requested module 'ts-package/src/file' does not provide an export named 'x'
I know this could be considered a node limitation but maybe we can compile typescript files to esm if entry is esm (even if workspace package does not have "type": "module"
Repro: https://github.com/remorses/tsx-repros
pnpm i
pnpm run import-ts-file
I investigated this and it might be tough to fix.
When a ESM file imports a CommonJS file, you would imagine a loader could simply transform the CommonJS file to ESM syntax on import so it's interoperable.
However, Node.js actually bypasses the CJS loader and reads the CommonJS file directly from disk to statically detect named exports with cjs-module-lexer
.
Static analysis is likely necessary because the import statement must assert that the named export exists before running the file. And even if Node.js adds a hook to transform the file before statically analyzing it, we won't be able to support older Node.js versions.
I tackled this problem before (https://github.com/evanw/esbuild/issues/2248) but arrived at the same conclusion. However, I managed to fix it for dynamic imports.
😢 Same issue here, go back to esbuild-node-loader
for a while.
Found some ^bind.*$
and ^[a-z]{3}$
and [A-Z]+_PROJECT_[A-Z]+
not working
@loynoir
esbuild-node-loader
doesn't support this either so I think you're confusing this with a different issue.
Found some
^bind.*$
and^[a-z]{3}$
and[A-Z]+_PROJECT_[A-Z]+
not working
I have no idea what you're talking about here. Can you open a new issue?
@privatenumber No, all three exports works in esbuild-node-loader
.
$ tsx ./src/cli.mts
SyntaxError: The requested module './util' does not provide
an export named 'XXX_PROJECT_XXX'
$ node --loader esbuild-node-loader ./src/cli.mts
OK
Can you upload that reproduction?
Ah, found workaround, maybe reproduce another day.
Given
-
cli.mts
-
util.ts
,.ts
by mistakenly not aligned to.mts
Known
-
tsx
syntax error about no export name -
esbuild-node-loader
working
Workaround
- rename
util.ts
toutil.mts
After
- both
tsx
andesbuild-node-loader
working
Sorry, I don't understand what you're saying. I'm going to hide your comments because they're cryptic and makes this thread harder to follow.
In the future, please provide a reproduction when you report a problem. That would be the best way to communicate it, especially if it's not easy to describe it.
I have just crashed against what seems like the same problem that @loynoir was trying to explain...
Essentially, there doesn't seem to be a way to import ts
/ js + d.ts
modules from an mts
entry point module.
My situation is that I have a non-module workspace in which I'm creating a typescript server module. This has to have an mts
extension to convince typescript that it doesn't share a single huge scope with everything around.
The modules that I am trying to import are generated from proto-gen-es
and the most correct & compatible version of generated artefacts is the aforementioned js + d.ts
option, with imports explicitly including .js
.
That however doesn't work with tsx
since it keeps replacing the .js
imports extension to .ts
.
What does work is renaming everything to mts
and importing with mjs
…
To illustrate, here is what I observed
/**
* - "a.js" & "a.d.ts" exist
* - results in "tsx" trying to import "a.ts"
*/
import {a} from `../gen/a.js`;
/**
* - same files as before
* - tries and fails to import verbatin (extentionless)
*/
import {a} from `../gen/a`;
/**
* - "a.ts" exists
* - produces following error, probably meaning it does't consider it a module:
* index.mts:1
* import {a} from 'a.js';
* ^
* SyntaxError: The requested module 'a.js' does not provide an export named 'a'
*/
import {a} from '../gen/net_pb.js';
Considering that these are my options of generated code, I'm seemingly left with an only option… generate the code with options target=ts,import_extension=.mjs
and rename all files to mts
I have also tried adding "type": "module"
into package.json
, renaming the entry module to ts
and generating js+dts
modules with js
imports, but that also doesn't work producing errors in transitive imports where it replaces js
extensions to ts
and fails.
What does work is:
-
"type": "module"
context -
index.ts
-
ts
files withjs
imports
With all that said, my context is Yarn V3 workspace with PNP enabled and [email protected]
.
Yarn, however, doesn't seem to be the problem here, the algorithm for manipulation with extensions does.
It might also be worth mentioning that the type: module
thing can yet prove problematic, since ES modules are still a bag of wet mice when it comes to interop between the plethora of modules for frontend development (storybook, yarn PnP, linters)
Worth mentioning this bug prevents named imports from lodash
: https://github.com/privatenumber/tsx/issues/361
Also, this is finally fixable when this lands in Node https://github.com/nodejs/node/issues/50839
Hi @privatenumber, I've just bumped into this issue trying to migrate a CJS project to ESM adding "type": "module"
to its package.json
.
The same thing - either I can't load non-esm packages from the monorepo, or (if I add "type": "module"
everywhere) load named exports from lodash
.
I see the PR you mentioned is merged to node, so is there any change of revisiting this bug in tsx
now?
Currently blocked by https://github.com/nodejs/node/issues/51327
So no work around? It seems to be affecting https://github.com/automation-stack/node-machine-id as well
The issue is acknowledged, and the blocker is referenced above. Contributions to the Node project to fix the issue will be appreciated.
To maintain focus, I'm locking this thread until unblocked, but encourage constructive solution-oriented dialogue through PRs.