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

Merged
merged 18 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9e4b0cc
feat: replace tsnode with tsx for parsing user configuration in all c…
AtofStryker Apr 15, 2025
20fb1e1
bump ubuntu images from node 18 to 20 as node 18 is not supported in …
AtofStryker Apr 16, 2025
dd1a8b5
fix: issues finding tsx on windows as it needs the file:// protocol a…
AtofStryker Apr 16, 2025
fd80e06
make sure to filter out stack code correctly for windows
AtofStryker Apr 17, 2025
9c0192e
fix: fix flake from windows on reporter menu not expanding (unrelated…
AtofStryker Apr 17, 2025
916a742
chore: update changelog with all issues tsx cutover closes
AtofStryker Apr 18, 2025
f819a48
fix merge conflicts
AtofStryker Apr 18, 2025
3dfeeb9
chore: add regression tests for cypress projects that previously did …
AtofStryker Apr 21, 2025
07cda56
build all binaries
AtofStryker Apr 21, 2025
7670fed
Merge branch 'release/15.0.0' of github.com:cypress-io/cypress into f…
AtofStryker Apr 21, 2025
0669f9c
Merge branch 'release/15.0.0' of github.com:cypress-io/cypress into f…
AtofStryker Apr 24, 2025
4f0a50f
chore: address issues from code review
AtofStryker Apr 24, 2025
96dd554
update changelog
AtofStryker Apr 24, 2025
b6c3daa
Merge branch 'release/15.0.0' into feat/replace_tsnode_for_tsx_config…
AtofStryker Apr 24, 2025
a05ab24
remove todo comment on testing legacy migration with tsx
AtofStryker Apr 25, 2025
faad0b0
Merge branch 'feat/replace_tsnode_for_tsx_config_process' of github.c…
AtofStryker Apr 25, 2025
7dd5ed6
refactor codeFrame calculation into a util function and add a unit test
AtofStryker Apr 28, 2025
0a526aa
updated node versions in project config ipc tests to remove 18 and te…
AtofStryker Apr 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .circleci/workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ mainBuildFilters: &mainBuildFilters
- /^release\/\d+\.\d+\.\d+$/
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- 'update-v8-snapshot-cache-on-develop'
- 'breaking/remove_angular_17_cursor'
- 'feat/replace_tsnode_for_tsx_config_process'

# usually we don't build Mac app - it takes a long time
# but sometimes we want to really confirm we are doing the right thing
Expand All @@ -49,7 +49,7 @@ macWorkflowFilters: &darwin-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'breaking/remove_angular_17_cursor', << pipeline.git.branch >> ]
- equal: [ 'feat/replace_tsnode_for_tsx_config_process', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand All @@ -60,7 +60,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'breaking/remove_angular_17_cursor', << pipeline.git.branch >> ]
- equal: [ 'feat/replace_tsnode_for_tsx_config_process', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand All @@ -83,7 +83,7 @@ windowsWorkflowFilters: &windows-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'breaking/remove_angular_17_cursor', << pipeline.git.branch >> ]
- equal: [ 'feat/replace_tsnode_for_tsx_config_process', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand Down Expand Up @@ -157,7 +157,7 @@ commands:
name: Set environment variable to determine whether or not to persist artifacts
command: |
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "breaking/remove_angular_17_cursor" ]]; then
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feat/replace_tsnode_for_tsx_config_process" ]]; then
export SHOULD_PERSIST_ARTIFACTS=true
fi' >> "$BASH_ENV"
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
Expand Down
4 changes: 4 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 👍🏻


## 14.3.3

_Released 5/6/2025 (PENDING)_
Expand Down
3 changes: 3 additions & 0 deletions packages/app/cypress/e2e/specs.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,9 @@ describe('App: Specs', () => {
.and('have.attr', 'href', 'https://on.cypress.io/styling-components')

cy.log('should not contain the link if you navigate away and back')
// A bit of a hack, but our cy-in-cy test needs to wait for the reporter to fully render before pressing the "f" key to expand the "Search specs" menu.
// Otherwise, the "f" keypress happens before the event is registered, which causes the "Search Specs" menu to not expand.
cy.get('[data-cy="runnable-header"]').should('be.visible')
cy.get('body').type('f')
cy.get('[data-cy=spec-file-item]').first().click()
cy.get('#spec-runner-header').should('not.contain', 'Review the docs')
Expand Down
2 changes: 2 additions & 0 deletions packages/data-context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"execa": "1.0.0",
"front-matter": "^4.0.2",
"fs-extra": "8.1.0",
"get-tsconfig": "4.10.0",
"getenv": "1.0.0",
"globby": "^11.0.1",
"graphql": "^15.5.1",
Expand All @@ -60,6 +61,7 @@
"server-destroy": "1.0.1",
"simple-git": "^3.27.0",
"stringify-object": "^3.0.0",
"tsx": "4.19.3",
"underscore.string": "^3.3.6",
"wonka": "^4.0.15"
},
Expand Down
18 changes: 11 additions & 7 deletions packages/data-context/src/actions/MigrationActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'path'
import debugLib from 'debug'
import { fork } from 'child_process'
import fs from 'fs-extra'
import os from 'os'
import semver from 'semver'
import type { ForkOptions } from 'child_process'
import assert from 'assert'
Expand Down Expand Up @@ -38,7 +39,8 @@ import { hasTypeScriptInstalled, toPosix } from '../util'

const debug = debugLib('cypress:data-context:MigrationActions')

const tsNode = toPosix(require.resolve('@packages/server/lib/plugins/child/register_ts_node'))
// NOTE: need the file:// prefix to avoid https://nodejs.org/api/errors.html#err_unsupported_esm_url_scheme on windows
const tsxCjs = os.platform() === 'win32' ? `file://${toPosix(require.resolve('tsx/cjs'))}` : toPosix(require.resolve('tsx/cjs'))

export function getConfigWithDefaults (legacyConfig: any) {
const newConfig = _.cloneDeep(legacyConfig)
Expand Down Expand Up @@ -74,7 +76,7 @@ export function getDiff (oldConfig: any, newConfig: any) {
}, result)
}

export async function processConfigViaLegacyPlugins (projectRoot: string, legacyConfig: LegacyCypressConfigJson): Promise<LegacyCypressConfigJson> {
export async function processConfigViaLegacyPlugins (projectRoot: string, legacyConfig: LegacyCypressConfigJson, nodeVersion: string | undefined | null): Promise<LegacyCypressConfigJson> {
const pluginFile = legacyConfig.pluginsFile
? await getLegacyPluginsCustomFilePath(projectRoot, legacyConfig.pluginsFile)
: await tryGetDefaultLegacyPluginsFile(projectRoot)
Expand All @@ -99,20 +101,22 @@ export async function processConfigViaLegacyPlugins (projectRoot: string, legacy
const configProcessArgs = ['--projectRoot', projectRoot, '--file', cwd]
const CHILD_PROCESS_FILE_PATH = require.resolve('@packages/server/lib/plugins/child/require_async_child')

// use ts-node if they've got typescript installed
// use tsx if they've got typescript installed
// this matches the 9.x behavior, which is what we want for
// processing legacy pluginsFile (we never supported `"type": "module") in 9.x.
if (hasTypeScriptInstalled(projectRoot)) {
const tsNodeLoader = `--require "${tsNode}"`
let tsxLoader = nodeVersion && semver.lt(nodeVersion, '20.6.0') ? `--loader ${tsxCjs}` : `--import ${tsxCjs}`

debug(`using generic ${tsxLoader} for esm and cjs with TypeScript for legacy migration.`)

if (!childOptions.env) {
childOptions.env = {}
}

if (childOptions.env.NODE_OPTIONS) {
childOptions.env.NODE_OPTIONS += ` ${tsNodeLoader}`
childOptions.env.NODE_OPTIONS += ` ${tsxLoader}`
} else {
childOptions.env.NODE_OPTIONS = tsNodeLoader
childOptions.env.NODE_OPTIONS = tsxLoader
}
}

Expand Down Expand Up @@ -319,7 +323,7 @@ export class MigrationActions {

async setLegacyConfigForMigration (config: LegacyCypressConfigJson) {
assert(this.ctx.currentProject)
const legacyConfigForMigration = await processConfigViaLegacyPlugins(this.ctx.currentProject, config)
const legacyConfigForMigration = await processConfigViaLegacyPlugins(this.ctx.currentProject, config, this.ctx.coreData.app.nodeVersion)

this.ctx.update((coreData) => {
coreData.migration.legacyConfigForMigration = legacyConfigForMigration
Expand Down
132 changes: 58 additions & 74 deletions packages/data-context/src/data/ProjectConfigIpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ import { CypressError, getError } from '@packages/errors'
import type { FullConfig, TestingType } from '@packages/types'
import { ChildProcess, fork, ForkOptions, spawn } from 'child_process'
import EventEmitter from 'events'
import fs from 'fs-extra'
import path from 'path'
import inspector from 'inspector'
import debugLib from 'debug'
import { getTsconfig } from 'get-tsconfig'
import { autoBindDebug, hasTypeScriptInstalled, toPosix } from '../util'
import _ from 'lodash'
import { pathToFileURL } from 'url'
import os from 'os'
import semver from 'semver'
import type { OTLPTraceExporterCloud } from '@packages/telemetry'
import { telemetry, encodeTelemetryContext } from '@packages/telemetry'

const pkg = require('@packages/root')
const debug = debugLib(`cypress:lifecycle:ProjectConfigIpc`)
const debugVerbose = debugLib(`cypress-verbose:lifecycle:ProjectConfigIpc`)

const CHILD_PROCESS_FILE_PATH = require.resolve('@packages/server/lib/plugins/child/require_async_child')

const tsNodeEsm = pathToFileURL(require.resolve('ts-node/esm/transpile-only')).href
const tsNode = toPosix(require.resolve('@packages/server/lib/plugins/child/register_ts_node'))
// NOTE: need the file:// prefix to avoid https://nodejs.org/api/errors.html#err_unsupported_esm_url_scheme on windows
const tsx = os.platform() === 'win32' ? `file://${toPosix(require.resolve('tsx'))}` : toPosix(require.resolve('tsx'))

export type IpcHandler = (ipc: ProjectConfigIpc) => void

Expand Down Expand Up @@ -262,10 +262,8 @@ export class ProjectConfigIpc extends EventEmitter {

private forkConfigProcess () {
const configProcessArgs = ['--projectRoot', this.projectRoot, '--file', this.configFilePath]
// allow the use of ts-node in subprocesses tests by removing the env constant from it
// without this line, packages/ts/register.js never registers the ts-node module for config and
// run_plugins can't use the config module.
const env = _.omit(process.env, 'CYPRESS_INTERNAL_E2E_TESTING_SELF')
// we do NOT want telemetry enabled within our cy-in-cy tests as it isn't configured to handled it
const env = _.omit(process.env, 'CYPRESS_INTERNAL_E2E_TESTING_SELF', 'CYPRESS_INTERNAL_ENABLE_TELEMETRY')

env.NODE_OPTIONS = process.env.ORIGINAL_NODE_OPTIONS || ''

Expand All @@ -279,86 +277,72 @@ export class ProjectConfigIpc extends EventEmitter {
if (inspector.url()) {
childOptions.execArgv = _.chain(process.execArgv.slice(0))
.remove('--inspect-brk')
// NOTE: The IDE in which you are working likely will not let attach to this process until it is running if using the --inspect option
// If needing to debug the child process (webpack-dev-server/vite-dev-server/webpack-preprocessor(s)/config loading), you may want to use --inspect-brk instead
// as it will NOT execute that process until you attach the debugger to it.
.push(`--inspect=${process.debugPort + 1}`)
.value()
}

debug('fork child process %o', { CHILD_PROCESS_FILE_PATH, configProcessArgs, childOptions: _.omit(childOptions, 'env') })

let isProjectUsingESModules = false
/**
* 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)!
*/
Comment on lines +287 to +303
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?


try {
// TODO: convert this to async FS methods
// eslint-disable-next-line no-restricted-syntax
const pkgJson = fs.readJsonSync(path.join(this.projectRoot, 'package.json'))

isProjectUsingESModules = pkgJson.type === 'module'
} catch (e) {
// project does not have `package.json` or it was not found
// reasonable to assume not using es modules
}
debug('fork child process %o', { CHILD_PROCESS_FILE_PATH, configProcessArgs, childOptions: _.omit(childOptions, 'env') })

if (!childOptions.env) {
childOptions.env = {}
}

// If they've got TypeScript installed, we can use
// ts-node for CommonJS
// ts-node/esm for ESM
if (hasTypeScriptInstalled(this.projectRoot)) {
/**
* use --import for node versions
* 20.6.0 and above for 20.x.x as --import is supported
* use --loader for node under 20.6.0 for 20.x.x
* @see https://tsx.is/dev-api/node-cli#node-js-cli
*/
let tsxLoader = this.nodeVersion && semver.lt(this.nodeVersion, '20.6.0') ? `--loader ${tsx}` : `--import ${tsx}`

// If they've got TypeScript installed, we can use tsx for CommonJS and ESM.
// @see https://tsx.is/dev-api/node-cli#node-js-cli
const userHasTypeScriptInstalled = hasTypeScriptInstalled(this.projectRoot)

if (userHasTypeScriptInstalled) {
debug('found typescript in %s', this.projectRoot)
if (isProjectUsingESModules) {
debug(`using --experimental-specifier-resolution=node with --loader ${tsNodeEsm}`)
// Use the ts-node/esm loader so they can use TypeScript with `"type": "module".
// The loader API is experimental and will change.
// The same can be said for the other alternative, esbuild, so this is the
// best option that leverages the existing modules we bundle in the binary.
// @see ts-node esm loader https://typestrong.org/ts-node/docs/usage/#node-flags-and-other-tools
// @see Node.js Loader API https://nodejs.org/api/esm.html#customizing-esm-specifier-resolution-algorithm
let tsNodeEsmLoader = `--experimental-specifier-resolution=node --loader ${tsNodeEsm}`

// starting in nodejs 20.19.0 and 22.7.0, the --experimental-detect-module option is now enabled by default.
// We need to disable it with the --no-experimental-detect-module flag.
// @see https://github.com/cypress-io/cypress/issues/30084
if (this.nodeVersion && (semver.gte(this.nodeVersion, '22.7.0') || semver.satisfies(this.nodeVersion, '>= 20.19.0 < 21.0.0'))) {
debug(`detected node version ${this.nodeVersion}, adding --no-experimental-detect-module option to child_process NODE_OPTIONS.`)
tsNodeEsmLoader = `${tsNodeEsmLoader} --no-experimental-detect-module`
}

// starting in nodejs 20.19.0 and 22.12.0, the --experimental-require-module option is now enabled by default.
// We need to disable it with the --no-experimental-require-module flag.
// @see https://github.com/cypress-io/cypress/issues/30715
if (this.nodeVersion && (semver.gte(this.nodeVersion, '22.12.0') || semver.satisfies(this.nodeVersion, '>= 20.19.0 < 21.0.0'))) {
debug(`detected node version ${this.nodeVersion}, adding --no-experimental-require-module option to child_process NODE_OPTIONS.`)
tsNodeEsmLoader = `${tsNodeEsmLoader} --no-experimental-require-module`
}

if (childOptions.env.NODE_OPTIONS) {
childOptions.env.NODE_OPTIONS += ` ${tsNodeEsmLoader}`
} else {
childOptions.env.NODE_OPTIONS = tsNodeEsmLoader
}

// TODO: get the tsconfig.json that applies to the users cypress.config.ts file
// right now, we are just using the tsconfig.json we find in the project root
const tsConfig = getTsconfig(this.projectRoot)

if (tsConfig) {
debug(`tsconfig.json found at ${tsConfig.path}`)
childOptions.env.TSX_TSCONFIG_PATH = tsConfig.path

debugVerbose(`tsconfig.json parsed as follows: %o`, tsConfig.config)
} else {
// Not using ES Modules (via "type": "module"),
// so we just register the standard ts-node module
// to handle TypeScript that is compiled to CommonJS.
// We do NOT use the `--loader` flag because we have some additional
// custom logic for ts-node when used with CommonJS that needs to be evaluated
// so we need to load and evaluate the hook first using the `--require` module API.
const tsNodeLoader = `--require "${tsNode}"`

debug(`using cjs with --require ${tsNode}`)

if (childOptions.env.NODE_OPTIONS) {
childOptions.env.NODE_OPTIONS += ` ${tsNodeLoader}`
} else {
childOptions.env.NODE_OPTIONS = tsNodeLoader
}
debug(`No tsconfig.json found! Attempting to parse file without tsconfig.json.`)
}
}

debug(`using generic ${tsxLoader} for esm and cjs ${userHasTypeScriptInstalled ? 'with TypeScript' : ''}.`)

if (childOptions.env.NODE_OPTIONS) {
childOptions.env.NODE_OPTIONS += ` ${tsxLoader}`
} else {
// Just use Node's built-in ESM support.
// TODO: Consider using userland `esbuild` with Node's --loader API to handle ESM.
debug(`no typescript found, just use regular Node.js`)
childOptions.env.NODE_OPTIONS = tsxLoader
}

const telemetryCtx = encodeTelemetryContext({ context: telemetry.getActiveContextObject(), version: pkg.version })
Expand Down
Loading