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

ts-node ESM support #64

Closed
Gregoor opened this issue Nov 10, 2020 · 9 comments
Closed

ts-node ESM support #64

Gregoor opened this issue Nov 10, 2020 · 9 comments

Comments

@Gregoor
Copy link

Gregoor commented Nov 10, 2020

Hola,

thanks for the amazing(est!) test runner.

I just moved one of my projects to a TS setup which requires me to use ES modules. ts-node has some preliminary support for that: TypeStrong/ts-node#1007
Unfortunately that doesn't work with the --require flag. I'm not quite sure yet what is needed to make it completely work yet. Maybe just work for ts-node to have a runtime solution that doesn't require calling node --loader ts-node/esm?
Just wanted to start the conversation, as there doesn't seem to be one around this yet.

✌️

@lukeed
Copy link
Owner

lukeed commented Nov 10, 2020

Hola~!

Thank you :)

There's no conversation, but an example instead: https://github.com/lukeed/uvu/tree/master/examples/typescript

Notice the -r hook on test command, and the extra "ts-node" config block inside its tsconfig.json.
It tells ts-node to transpile to require statements on the fly, which is needed for the underlying node runtime.

... I've not tried it yet, but you can probably leave this as module: 'esnext' if you were to include --experimental-specifier-resolution=node too, so that import/export can work. Again, not sure on that part.

@Gregoor
Copy link
Author

Gregoor commented Nov 10, 2020

Thanks for the quick reply :)

Unfortunately setting ts-node's doesn't work for me, as somewhere in my code there's a "blanket" import (to be precise import t from '@babel/types', which has different semantics pending on module type. For ES modules it behaves like good old import * as t from '@babel/types', for "module": "commonjs" it just seems to be undefined.

edit: just started reading this about esm's import semantics, but I'm still not quite sure if I can express it in a way which would be compatible with both module types.

@lukeed
Copy link
Owner

lukeed commented Nov 10, 2020

TBH I'm not sure what the issue for uvu is – sounds like just a ts-node issue/limitation. Maybe I'm missing something?

But given your babel mention, I think that (unfortunately) you need allowSyntheticDefaultImports and/or moduleInterop enabled so that you get the correct require statement for commonjs output

@Gregoor
Copy link
Author

Gregoor commented Nov 10, 2020

Unfortunately no combination of esModuleInterop and allowSyntheticDefaultImports (which is apparently always true when the former is) does the trick. I'm beginnig to suspect that the way @babel/types exports some of its members might be part of the problem, namely:
https://github.com/babel/babel/blob/e498bee10f0123bb208baa228ce6417542a2c3c4/packages/babel-types/src/index.js#L15

Anyway wrt uvu, I was hoping that ts-node adding a runtime loader hook would make it also work in uvu. But now I tried NODE_OPTIONS="--experimental-loader=ts-node/esm" uvu which unfortunately errors due to /bin.js require()s all the found test files, instead of import()ing them. One could use one or the other, depending on whether "type": "module" is set in package.json, if you also see value in supporting it. I'd personally prefer something along those lines to the tsconfig option as it does not necessitate having separate tsconfigs and diverging import-semantics.

Happy to look into creating a PR with examples, if you think it'd be worthwhile!

@lukeed
Copy link
Owner

lukeed commented Nov 10, 2020

Hmm... if you can provide me with a reproduction repo I'll be happy to poke around. I would not consider type: 'module' inside uvu, but there are other ways around it.

If I can get a repro in front of me I can contribute more to this convo, but right now I don't have much else to offer you 🙈

@Gregoor
Copy link
Author

Gregoor commented Nov 10, 2020

Here is basically what it comes down to:
https://github.com/Gregoor/uvu-ts-node-esm
Running yarn build && yarn start works, whereas yarn test fails due to differing import semantics.

Now when you remove the ts-node section tsconfig.json and run node --loader ts-node/esm src/astify.ts, it does work, as that would yield equivalent import semantics. To get it to work inside uvu I had to do some rewriting of bin.js, e.g.

const useESM = require(path.join(process.cwd(), 'package.json')).type == 'module';

globalThis.UVU_DEFER = 1;
for (let idx = 0; idx < suites.length; idx++) {
  const x = suites[idx];
  globalThis.UVU_INDEX = idx;
  QUEUE.push([x.name]);
  // auto-add to queue
  if (useESM) {
    const m = await import(x.file);
  } else {
    require(x.file);
  }
}

and then calling it with some experimental flags NODE_OPTIONS="--loader ts-node/esm --experimental-specifier-resolution=node" uvu src

Anyway, thanks for thinking this through with me. This all seems to be still somewhat in-flux and experimental. So maybe i should just close this issue for now and we can look into it again once things stabilize?

@lukeed
Copy link
Owner

lukeed commented Nov 10, 2020

Thanks, I'll poke around 👍

You might want to try uvu@next which has native ESM support. Basically, it removes the need for your custom bin.js changes.

The rest of it seems very much in flux and out of my control. Have been loosely waiting for these things to settle into a consensus too, but we're in this CommonJS/ESM limbo for a while longer I'm afraid

@Gregoor
Copy link
Author

Gregoor commented Nov 10, 2020

Woop, uvu@next indeed makes my hacky changes up there unnecessary! And with that and those experimental flags it also works in my original use case. Thankslots!

@lukeed
Copy link
Owner

lukeed commented Nov 10, 2020

Cool :) I think we can close this then. Now that #7 is unblocked, uvu will move native ESM support to its main branch.
Unfortunately you'll still have to deal with all those flags though :D

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants