Open cefn opened 2 years ago
Thanks to the solution in https://github.com/google/zx/issues/125#issuecomment-850392517 for helpful summary of changes to fix the issue.
The more detailed issue above documents that you would experience if you DIDN'T get each of the steps right, as that's probably what will lead people to finding a solution.
An alternative might be to use @cspotcode/zx which pins zx to 5 and has some defaults which enable things to mostly work. See https://github.com/cefn/zx-tsnode-repro/pull/3 as an alternative solution.
With the aim of modernising, but at the cost of breaking existing usages, zx no longer publishes a CommonJS bundle, only an ESM bundle.
This can be observed in the package.json of zx which only references
.mjs
files and no.cjs
...Point of view of the zx maintainers is that this is hard cheese, so it's up to users of
zx
to find a way to fix it.Initial Error
My reference zx-node-repro project has nothing but the default npm and typescript scaffolding that comes from
npm init
andtsc --init
followed bynpm install --save-dev zx ts-node
.Running an example script breaks with the following error whenever you try to use ts-node to run a file which includes e.g.
import { $ } from 'zx';
.Note the stack trace originates from
node:internal/modules/cjs/loader
which embodies Node's CommonJS loading strategy. The EcmaScript Modules (ESM) strategy has not been triggered since we haven't declared our project as using ESM.We might try to run it as esm by telling
ts-node
, but that doesn't change how it attempts to load its dependencies, giving us this error, which is maybe a bug in how zx is packaged? It's hard for anyone to know what is actually going on, and we'd rather just be able to run our scripts but we still get ...Step 1: Move importing package to ESM
So let's declare the project as being an ESM project, by adding this property to the top level of our
package.json
...However, this doesn't fix the issue straight away. Running
npx ts-node src/example.ts
now gets this even more unhelpful error...Step 2: Instruct ts-node it's ESM
Because this isn't enough, yet, we might try instructing ts-node that our example.ts should be interpreted as an ESM module like...
Which gets us this error instead...
Step 3: Change our Typescript Project type
So now we might accept, to run this one script, we need to change our package AND our typescript config from CommonJS to ES Module. This change also requires that we declare a moduleResolution strategy.
If this is impossible given you might be writing some other Typescript code you can have a separate
tsconfig.example.json
from the default, and pass it with--project tsconfig.example.json
tots-node
if you need to.However, even with all the package and typescript changes in place, ts-node can't make sense of our example file...
Finally Executing a script
We can get the script to run but ONLY with the
--esm
flag...Reference configuration
You can see the reference configuration in this PR and the
test
script shows an example execution of an example tooling script I wrote with zx that checks if your git worktree is clean as part of other routines. In that PR branch you can run it like ...Epilogue
If we had missed adding
"type":"module"
above, passing--esm
would raise the really helpful error below that tells us to declare the package type. If only ALL maintainers in the javascript ecosystem wrote meaningful errors. Props to whoever wroteObject.compileFunction
you are the hero we need...