Skip to content

Commit

Permalink
feat: skip ts-node register for ESM plugins (#778)
Browse files Browse the repository at this point in the history
* feat: skip ts-node register for ESM plugins

* chore: update debug message
  • Loading branch information
mdonnalley authored Sep 6, 2023
1 parent 660ec2c commit 299df21
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 43 deletions.
33 changes: 10 additions & 23 deletions src/config/ts-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {TSConfig, Plugin} from '../interfaces'
import {settings} from '../settings'
import {isProd} from '../util'
import {Debug} from './util'
import {Config} from './config'
import {memoizedWarn} from '../errors'
// eslint-disable-next-line new-cap
const debug = Debug('ts-node')
Expand Down Expand Up @@ -110,7 +109,6 @@ function registerTSNode(root: string): TSConfig | undefined {
*/
export function tsPath(root: string, orig: string, plugin: Plugin): string
export function tsPath(root: string, orig: string | undefined, plugin?: Plugin): string | undefined
// eslint-disable-next-line complexity
export function tsPath(root: string, orig: string | undefined, plugin?: Plugin): string | undefined {
if (!orig) return orig
orig = orig.startsWith(root) ? orig : path.join(root, orig)
Expand All @@ -122,32 +120,21 @@ export function tsPath(root: string, orig: string | undefined, plugin?: Plugin):
return orig
}

// Skip ts-node registration if plugin is an ESM plugin executing from a CJS plugin
if (plugin?.moduleType === 'module' && Config.rootPlugin?.moduleType === 'commonjs') {
debug(`Skipping ts-node registration for ${root} because it's an ESM module but the root plugin is CommonJS`)
// Skip ts-node registration for ESM plugins.
// The node ecosystem is not mature enough to support auto-transpiling ESM modules at this time.
// See the following:
// - https://github.com/TypeStrong/ts-node/issues/1791#issuecomment-1149754228
// - https://github.com/nodejs/node/issues/49432
// - https://github.com/nodejs/node/pull/49407
// - https://github.com/nodejs/node/issues/34049
if (plugin?.moduleType === 'module') {
debug(`Skipping ts-node registration for ${root} because it's an ESM module`)
if (plugin.type === 'link')
memoizedWarn(`${plugin.name} is a linked ESM module and cannot be auto-compiled from a CommonJS root plugin. Existing compiled source will be used instead.`)
memoizedWarn(`${plugin.name} is a linked ESM module and cannot be auto-transpiled. Existing compiled source will be used instead.`)

return orig
}

// If plugin is an ESM plugin being executed from an ESM root plugin, check to see if ts-node/esm loader has been set
// either in the NODE_OPTIONS env var or from the exec args. If the ts-node/esm loader has NOT been loaded then we want
// to skip ts-node registration so that it falls back on the compiled source.
if (plugin?.moduleType === 'module') {
const tsNodeEsmLoaderInExecArgv = process.execArgv.includes('--loader') && process.execArgv.includes('ts-node/esm')
const tsNodeEsmLoaderInNodeOptions = process.env.NODE_OPTIONS?.includes('--loader=ts-node/esm') ?? false
if (!tsNodeEsmLoaderInExecArgv && !tsNodeEsmLoaderInNodeOptions) {
debug(`Skipping ts-node registration for ${root} because it's an ESM module but the ts-node/esm loader hasn't been run`)
debug('try setting NODE_OPTIONS="--loader ts-node/esm" in your environment.')
if (plugin.type === 'link') {
memoizedWarn(`${plugin.name} is a linked ESM module and cannot be auto-compiled without setting NODE_OPTIONS="--loader=ts-node/esm" in the environment. Existing compiled source will be used instead.`)
}

return orig
}
}

if (settings.tsnodeEnabled === undefined && isProd() && plugin?.type !== 'link') {
debug(`Skipping ts-node registration for ${root} because NODE_ENV is NOT "test" or "development"`)
return orig
Expand Down
40 changes: 20 additions & 20 deletions test/integration/esm-cjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,34 +365,34 @@ type CleanUpOptions = {
await test('Link ESM plugin to ESM root plugin', async () => {
const plugin = PLUGINS.esm2

const linkedPlugin = await linkPlugin({executor: esmExecutor, plugin, script: 'run'})
await linkPlugin({executor: esmExecutor, plugin, script: 'run'})
// test bin/run
// NOTE: this also tests that the compiled source is used when ts-node/esm loader is not specified
await runCommand({
executor: esmExecutor,
plugin,
script: 'run',
expectStrings: [plugin.commandText, plugin.hookText],
})
// test un-compiled changes with bin/run
await modifyCommand({executor: linkedPlugin, plugin, from: 'hello', to: 'howdy'})
await runCommand({
executor: esmExecutor,
plugin,
script: 'run',
expectStrings: ['howdy', plugin.hookText],
env: {NODE_OPTIONS: '--loader=ts-node/esm'},
})

// test un-compiled changes with bin/dev
await modifyCommand({executor: linkedPlugin, plugin, from: 'howdy', to: 'cheers'})
await runCommand({
executor: esmExecutor,
plugin,
script: 'dev',
expectStrings: ['cheers', plugin.hookText],
env: {NODE_OPTIONS: '--loader=ts-node/esm'},
})
// Skipping these because we decided to not support auto-transpiling ESM plugins at this time.
// // test un-compiled changes with bin/run
// await modifyCommand({executor: linkedPlugin, plugin, from: 'hello', to: 'howdy'})
// await runCommand({
// executor: esmExecutor,
// plugin,
// script: 'run',
// expectStrings: ['howdy', plugin.hookText],
// env: {NODE_OPTIONS: '--loader=ts-node/esm'},
// })
// // test un-compiled changes with bin/dev
// await modifyCommand({executor: linkedPlugin, plugin, from: 'howdy', to: 'cheers'})
// await runCommand({
// executor: esmExecutor,
// plugin,
// script: 'dev',
// expectStrings: ['cheers', plugin.hookText],
// env: {NODE_OPTIONS: '--loader=ts-node/esm'},
// })

await cleanUp({executor: esmExecutor, plugin, script: 'run'})
})
Expand Down

0 comments on commit 299df21

Please sign in to comment.