What would you like?
To replace ts-node with tsx for generic transpiling of TypeScript and generic file loading
Why is this needed?
How cypress works with ts-node today
For end users today, we currently use ts-node to:
- compile
typescript and esm via ts-node/esm with --experimental-specifier-resolution=node flag. We detect this based on the users package.json.
typescript via cjs uses the default ts-node loader.
cjs/esm without typescript uses node only.
See ProjectConfigIpc.ts for more details.
Issues with ts-node today
- The user config process is run by
cypress on a subprocess, which is all run in commonjs currently. The interoperability between ESM and CJS inside the node.js runtime is still something that isn't well supported. In other words, the process needs to either be executed as ESM or CJS. It cannot handle both. For this reason, commonjs is forced as the module for typescript users. This is explained fairly well in our docs.
Unfortunately, this leads to a whole new superset of problems when can be seen in this PR as well as a few of the issues linked in this issue.
- Cypress also only checks the
tsconfig.json in the users project root, even though cypress recommends having it's own tsconfig.json. Given this is mostly to add cypress type checking to your editor in the cypress directory, it has two pitfalls:
- Likely will not apply type checking to component tests, which commonly live outside the cypress directory.
tsconfig.json is not used to transpile the cypress config, which may be a problem for users who have complex plugin configurations.
Ideally, even if users don't have a tsconfig, cypress in 99% of cases for simple configs should be able to parse the file.
- ts-node has not had any active development in over 2 years and does not appearing to be actively maintained
Why tsx?
Experimenting with tsx, it looks like we can fix most of the above issues with ts-node.
tsx works as a generic node loader with typescript support, meaning it can handle any esm, cjs, and typescript variant. This allows us to use the same loader for any config format, eliminating the logic needed to try and discover the expected config module format.
- It also has seamless cjs and esm import support, meaning we can run a user's cypress config with an independent
tsconfig.json and it be compatible with our run time. This completely gets rid of the need to override a users typescript config, eliminating many of the bugs associated with such behavior.
- We can also feed
tsx a unique tsconfig.json path, allowing us to actually use the tsconfig.json defined in the cypress directory or whatever directory their cypress tests live.
More details can be seen on the tsx spike comment
Other
removing @packages/ts and updating mocha tests to use tsx are out of scope for this issue. This issue should address the loading of the user's cypress config inside the require async child processes as well as replacing the registering of @packages/ts inside cypress packages to use ts-node for runtime transpilation and instead using tsx/cjs.
We should be able to build and test a binary with all of our tests passing. The only things that should be using the @packages/ts and ts-node runtimes are our mocha tests
What would you like?
To replace
ts-nodewithtsxfor generic transpiling ofTypeScriptand generic file loadingWhy is this needed?
How
cypressworks withts-nodetodayFor end users today, we currently use
ts-nodeto:typescriptandesmviats-node/esmwith--experimental-specifier-resolution=nodeflag. We detect this based on the userspackage.json.typescriptviacjsuses the defaultts-nodeloader.cjs/esmwithouttypescriptusesnodeonly.See ProjectConfigIpc.ts for more details.
Issues with
ts-nodetodaycypresson a subprocess, which is all run incommonjscurrently. The interoperability between ESM and CJS inside the node.js runtime is still something that isn't well supported. In other words, the process needs to either be executed as ESM or CJS. It cannot handle both. For this reason,commonjsis forced as the module for typescript users. This is explained fairly well in our docs.Unfortunately, this leads to a whole new superset of problems when can be seen in this PR as well as a few of the issues linked in this issue.
tsconfig.jsonin the users project root, even though cypress recommends having it's owntsconfig.json. Given this is mostly to add cypress type checking to your editor in the cypress directory, it has two pitfalls:tsconfig.jsonis not used to transpile thecypressconfig, which may be a problem for users who have complex plugin configurations.Ideally, even if users don't have a
tsconfig, cypress in 99% of cases for simple configs should be able to parse the file.Why
tsx?Experimenting with
tsx, it looks like we can fix most of the above issues withts-node.tsxworks as a generic node loader with typescript support, meaning it can handle anyesm,cjs, andtypescriptvariant. This allows us to use the same loader for any config format, eliminating the logic needed to try and discover the expected config module format.tsconfig.jsonand it be compatible with our run time. This completely gets rid of the need to override a users typescript config, eliminating many of the bugs associated with such behavior.tsxa unique tsconfig.json path, allowing us to actually use thetsconfig.jsondefined in thecypressdirectory or whatever directory theircypresstests live.More details can be seen on the
tsxspike commentOther
removing @packages/ts and updating
mochatests to usetsxare out of scope for this issue. This issue should address the loading of the user's cypress config inside the require async child processes as well as replacing the registering of@packages/tsinside cypress packages to usets-nodefor runtime transpilation and instead usingtsx/cjs.We should be able to build and test a binary with all of our tests passing. The only things that should be using the
@packages/tsandts-noderuntimes are ourmochatests