From 8f6f4e51bee5262090f8adfdcc1e2df17a6d7886 Mon Sep 17 00:00:00 2001 From: isaacs Date: Mon, 29 May 2023 19:10:58 -0700 Subject: [PATCH] fix: lazy-load repl to avoid domain side effects (#2025) * fix: lazy-load repl to avoid domain side effects Actually starting the repl will still put the process into domain-mode, but this at least allows programs to use `ts-node` or `--loader=ts-node/esm` without losing the ability to use process.setUncaughtExceptionCaptureCallback(). The problem should ideally be fixed (or mitigated) in node core, but this is still worthwhile for the benefit of supporting current node versions. Re: https://github.com/nodejs/node/issues/48131 Fix: https://github.com/TypeStrong/ts-node/issues/2024 * Update src/repl.ts --------- Co-authored-by: Andrew Bradley --- src/repl.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/repl.ts b/src/repl.ts index b55693fed..bb1abe83b 100644 --- a/src/repl.ts +++ b/src/repl.ts @@ -1,7 +1,8 @@ import type * as _diff from 'diff'; import { homedir } from 'os'; import { join } from 'path'; -import { Recoverable, ReplOptions, REPLServer, start as nodeReplStart } from 'repl'; +import type * as _nodeRepl from 'repl'; +import type { REPLServer, ReplOptions } from 'repl'; import { Context, createContext, Script } from 'vm'; import { Service, CreateOptions, TSError, env } from './index'; import { readFileSync, statSync } from 'fs'; @@ -28,6 +29,17 @@ function getDiffLines() { return diff.diffLines; } +// Lazy-loaded to prevent repl's require('domain') from causing problems +// https://github.com/TypeStrong/ts-node/issues/2024 +// https://github.com/nodejs/node/issues/48131 +let nodeRepl: typeof _nodeRepl; +function getNodeRepl() { + if (nodeRepl === undefined) { + nodeRepl = require('repl'); + } + return nodeRepl; +} + /** @internal */ export const EVAL_FILENAME = `[eval].ts`; /** @internal */ @@ -271,6 +283,7 @@ export function createRepl(options: CreateReplOptions = {}) { const canLogTopLevelAwaitHint = service!.options.experimentalReplAwait !== false && !service!.shouldReplAwait; if (error instanceof TSError) { // Support recoverable compilations using >= node 6. + const { Recoverable } = getNodeRepl(); if (Recoverable && isRecoverable(error)) { callback(new Recoverable(error)); return; @@ -335,7 +348,7 @@ export function createRepl(options: CreateReplOptions = {}) { // the REPL starts for a snappier user experience on startup. service?.compile('', state.path); - const repl = nodeReplStart({ + const repl = getNodeRepl().start({ prompt: '> ', input: replService.stdin, output: replService.stdout,