JS/TS Ecosystem Sucks at not breaking things.
Here's a list of things that I discovered.
-
Import extension
When using Node with ESM, it requires .js extension on imports. Use node
--experimental-specifier-resolution=node
to revert back to old node behavior of not requiring an extension.Why:
This is a problem because, by default, people writing typescript write imports without extension. Typescript doesn't transform the import extensions. So if you writeimport "./foo"
orimport "./foo.ts"
, it will come out as-is in the output JS file.import "./foo.ts"
won't obviously work because the output files are not.ts
files.import "./foo"
used to work when not using ESM in Node.So when ESM was introduced, Typescript devs, instead of going the sane path of rewriting the imports, because they are obviously changing the extension of the output files, decided to allow
import "./foo.js"
in Typescript. The compiler will rewrite.js
to.ts
just during compiling. This works, I can compile and run stuff usingts-node
.But.. Jest is broken now. Jest resolves modules in its own way. kulshekhar/ts-jest#1057 Although the issue is filed in ts-jest, the issue is actually in jest. And I couldn't find any issue addressing the same in the jest repo.
-
millparsec, ky are esm-only. These aree some packages that I needed in my app. They only provide an ESM build.
-
Typescript can't import ESM libs when compiling in CJS mode. TS when compiling in CJS mode, transpiles all
import foo from "foo"
torequire()
. ES Modules can't berequire()
d. -
Ava doesn't support BDD.
-
Uvu, docs are sparse. No proper TS+ESM support.
-
Jest errors out when importing milliparsec, because Jest uses its own resolve function which doesn't support "node exports package entrypoints"
Refs: jestjs/jest#9771 https://nodejs.org/api/packages.html#packages_package_entry_points
-
Using jest-node-exports-resolver doesn't seem to fix this.
Errors: Cannot find module 'milliparsec' from 'src/app.ts' ReferenceError: You are trying to
import
a file after the Jest environment has been torn down.jest-node-exports-resolver: https://github.com/k-g-a/jest-node-exports-resolver
-
Using enhanced-resolve kinda fixes it. How to: jestjs/jest#9771 (comment) Caveats: I had to also add querystring to the list in
if([..].includes())
. So node builtins wont be properly resolved by enhanced-resolve. Every node builtings that any of my transitive dependencies use must be listed here. That's fragile.
Constraints:
- I must use typescript in ESM mode. TS can't properly transpile ESM imports to CJS. (See above)
Decisions:
- Use typescript in ESM mode, not CJS mode.
- Replace Jest with Ava. Jest has been too slow in fixing stuff related to TS+ESM setup. When one thing is fixed, another thing breaks. Tired of playing cat and mouse.
Other noteworthy things:
I tried to integrate esbuild in my testing flow. But eventually went back to using ts-node, because, it's just another fragile point in my workflow.
There was a combinatorial explosion in number of ways things broke. I couldn't even begin to make things work. So I had to kick the least priority thing among the offenders: Typescript, ESM, Jest, ESBuild.
So ESBuild was out.
I might later reintroduce it after replacing Jest with Ava. Ava looks a bit more stable. Need to check it out before I can say for sure.