Skip to content

feat: replace ts-node with tsx for parsing user configuration #31520

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

Open
wants to merge 18 commits into
base: release/15.0.0
Choose a base branch
from

Conversation

AtofStryker
Copy link
Contributor

@AtofStryker AtofStryker commented Apr 15, 2025

Closes

Side effect of not using Node as the loader

Additional details

Introduces tsx as the new tool of choice to load and parse the end user's cypress.config.(js|ts), replacing ts-node. This solves a lot of issues around ESM projects using Cypress as we are now able to more easily run ESM based cypress configurations (TypeScript or JavaScript) within the Cypress child process. This means we don't need ts-node work arounds to try to run the user's config as commonjs, which results in configuration clashes in TypeScript, nor do we need nodes experimental loaders / options to run ESM JavaScript projects.

Steps to test

Go through some of the reproductions in the aforementioned issues and run the pre release binary installed in the project. Notice the project is now able to run

How has the user experience changed?

The TypeScript / ESM experience is greatly improved as users are now able to run Cypress in their project without having to commit to hacky workarounds!

PR Tasks

@AtofStryker AtofStryker force-pushed the feat/replace_tsnode_for_tsx_config_process branch 2 times, most recently from 463841e to 3f1487c Compare April 15, 2025 19:18
Copy link

cypress bot commented Apr 15, 2025

cypress    Run #62004

Run Properties:  status check passed Passed #62004  •  git commit 0a526aab83: updated node versions in project config ipc tests to remove 18 and test threshol...
Project cypress
Branch Review feat/replace_tsnode_for_tsx_config_process
Run status status check passed Passed #62004
Run duration 16m 42s
Commit git commit 0a526aab83: updated node versions in project config ipc tests to remove 18 and test threshol...
Committer AtofStryker
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 1
Tests that did not run due to a developer annotating a test with .skip  Pending 29
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 794
View all changes introduced in this branch ↗︎
UI Coverage  63.64%
  Untested elements 30  
  Tested elements 56  
Accessibility  96.22%
  Failed rules  0 critical   4 serious   1 moderate   0 minor
  Failed elements 195  

@AtofStryker AtofStryker force-pushed the feat/replace_tsnode_for_tsx_config_process branch from 3f1487c to 3803906 Compare April 16, 2025 03:47
@AtofStryker AtofStryker force-pushed the feat/replace_tsnode_for_tsx_config_process branch from 3803906 to dd4a87b Compare April 16, 2025 15:49
@AtofStryker AtofStryker force-pushed the feat/replace_tsnode_for_tsx_config_process branch from e069098 to 916a742 Compare April 18, 2025 19:46
@AtofStryker AtofStryker changed the title feat: (DRAFT) replace tsnode with tsx for parsing user configuration feat: replace tsn-ode with tsx for parsing user configuration Apr 21, 2025
@AtofStryker AtofStryker changed the title feat: replace tsn-ode with tsx for parsing user configuration feat: replace ts-node with tsx for parsing user configuration Apr 21, 2025
@AtofStryker AtofStryker added the type: feature New feature that does not currently exist label Apr 23, 2025
Comment on lines +287 to +303
/**
* Before the introduction of tsx, Cypress used ts-node (@see https://github.com/TypeStrong/ts-node) with native node to try and load the user's cypress.config.ts file.
* This presented problems because the Cypress node runtime runs in commonjs, which may not be compatible with the user's cypress.config.ts and tsconfig.json.
* To mitigate the aforementioned runtime incompatibility, we used to force TypeScript options for the user in order to load their config inside the our node context
* via a child process, which lead to clashes and issues (outlined in the comments below).
* This is best explained historically in our docs which a screenshot can be see in @see https://github.com/cypress-io/cypress/issues/30426#issuecomment-2805204540 and can be seen
* in an older version of the Cypress codebase (@see https://github.com/cypress-io/cypress/blob/v14.3.0/packages/server/lib/plugins/child/ts_node.js#L24)
*
* Attempted workarounds with ts-node and node: @see https://github.com/cypress-io/cypress/pull/28709
* Example continued end user issues: @see https://github.com/cypress-io/cypress/issues/30954 and @see https://github.com/cypress-io/cypress/issues/30925
* Spike into ts-node alternatives (a lot of useful comments on tsx): @see https://github.com/cypress-io/cypress/issues/30426
* feature issue to replace ts-node as our end user TypeScript loader: @see https://github.com/cypress-io/cypress/issues/31185
*
* tsx (@see https://tsx.is/) is able to work with both CommonJS and ESM at the same time ( @see https://tsx.is/#seamless-cjs-%E2%86%94-esm-imports), which solves the problem of interoperability that
* Cypress faced with ts-node and really just node itself. We no longer need experimental node flags and ts-node permutations to load the user's config file.
* We can use tsx to load just about anything, including JavaScript files (@see https://github.com/privatenumber/ts-runtime-comparison)!
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there value in having comments about code that's no longer in the repo here? I'm not understanding how I would find how Cypress used to work valuable here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt like we should capture it here someplace because why else are we using different tooling to register the user config than how we do it everywhere else in the repo? At least until we unify it maybe? or link out in the comments

Copy link
Contributor Author

@AtofStryker AtofStryker Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want this captured someplace but I don't think this is the best place. any ideas?

import type { DataContext } from '..'

const tsxCodeFrameFilter = '/node_modules/tsx/dist/register'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we be able to catch if this path changed in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think the transform error tests in the app package cy-in-cy tests would error since the codeFrame would be broken and missing, which the test checks for https://github.com/cypress-io/cypress/blob/develop/packages/launchpad/cypress/e2e/config-files-error-handling.cy.ts#L204

@jennifer-shehane jennifer-shehane dismissed their stale review April 24, 2025 17:57

Dismissing my comments as addressed

@@ -95,13 +95,13 @@ async function setFocus () {
async function getBrowserLauncher (browser: Browser, browsers: FoundBrowser[]): Promise<BrowserLauncher> {
debug('getBrowserLauncher %o', { browser })

if (browser.name === 'electron') return await import('./electron')
if (browser.name === 'electron') return require('./electron')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: can we type this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's somewhat irrelevant but we could also explore just importing the files at the top and returning them here

browser: 'electron',
project: 'yarn-v3.1.1-pnp',
onRun: async (run) => {
await run({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one is a bit bizarre, but the --dev mode doesn't work exactly correct here has we are using ts-node to register the typescript options, which pollutes the tsconfig with allowSyntheticDefaultImports and was causing the test to fail. Not sure why we need dev mode here, but it works fine without it to completely isolate us from ts-node in our system tests

@@ -10,6 +10,10 @@ _Released 07/01/2025 (PENDING)_
- Removed support for [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol) with the [firefox](https://www.mozilla.org/) browser. Addresses [#31189](https://github.com/cypress-io/cypress/issues/31189).
- The Cypress configuration wizard for Component Testing supports TypeScript 5.0 or greater. Addresses [#31187](https://github.com/cypress-io/cypress/issues/31187).

**Features:**

- [`tsx`](https://tsx.is/) is now used in all cases to run the Cypress config, replacing [ts-node](https://github.com/TypeStrong/ts-node) for TypeScript and Node for commonjs/ESM. This should allow for more interoperability for users who are using any variant of ES Modules. Addresses [#8090](https://github.com/cypress-io/cypress/issues/8090), [#15724](https://github.com/cypress-io/cypress/issues/15724), [#21805](https://github.com/cypress-io/cypress/issues/21805), [#22273](https://github.com/cypress-io/cypress/issues/22273), [#22747](https://github.com/cypress-io/cypress/issues/22747), [#23141](https://github.com/cypress-io/cypress/issues/23141), [#25958](https://github.com/cypress-io/cypress/issues/25958), [#25959](https://github.com/cypress-io/cypress/issues/25959), [#26606](https://github.com/cypress-io/cypress/issues/26606), [#27359](https://github.com/cypress-io/cypress/issues/27359), [#27450](https://github.com/cypress-io/cypress/issues/27450), [#28442](https://github.com/cypress-io/cypress/issues/28442), [#30318](https://github.com/cypress-io/cypress/issues/30318), [#30718](https://github.com/cypress-io/cypress/issues/30718), [#30907](https://github.com/cypress-io/cypress/issues/30907), [#30915](https://github.com/cypress-io/cypress/issues/30915), [#30925](https://github.com/cypress-io/cypress/issues/30925), [#30954](https://github.com/cypress-io/cypress/issues/30954) and [#31185](https://github.com/cypress-io/cypress/issues/31185).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this long list 👍🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Cypress 15 topic: typescript type: feature New feature that does not currently exist
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: replace ts-node with tsx for user configuration parsing and cypress runtime
4 participants