Skip to content

Commit 82789ed

Browse files
committed
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: nodejs/node#48131 Fix: TypeStrong#2024
1 parent 7af5c48 commit 82789ed

File tree

1 file changed

+16
-3
lines changed

1 file changed

+16
-3
lines changed

src/repl.ts

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type * as _diff from 'diff';
22
import { homedir } from 'os';
33
import { join } from 'path';
4-
import { Recoverable, ReplOptions, REPLServer, start as nodeReplStart } from 'repl';
4+
import type * as _nodeRepl from 'repl';
5+
import type { REPLServer, ReplOptions } from 'repl';
56
import { Context, createContext, Script } from 'vm';
67
import { Service, CreateOptions, TSError, env } from './index';
78
import { readFileSync, statSync } from 'fs';
@@ -28,6 +29,17 @@ function getDiffLines() {
2829
return diff.diffLines;
2930
}
3031

32+
// Lazy-loaded to prevent repl's require('domain') from causing problems
33+
// https://github.com/TypeStrong/ts-node/issues/2024
34+
// https://github.com/nodejs/node/issues/48131
35+
let nodeRepl: typeof _nodeRepl;
36+
function getNodeRepl() {
37+
if (nodeRepl === undefined) {
38+
nodeRepl = require('repl');
39+
}
40+
return nodeRepl;
41+
}
42+
3143
/** @internal */
3244
export const EVAL_FILENAME = `[eval].ts`;
3345
/** @internal */
@@ -140,7 +152,7 @@ interface StartReplInternalOptions extends ReplOptions {
140152
*/
141153
export function createRepl(options: CreateReplOptions = {}) {
142154
const { ignoreDiagnosticsThatAreAnnoyingInInteractiveRepl = true } = options;
143-
let nodeReplServer: REPLServer;
155+
let nodeReplServer: _nodeRepl.REPLServer;
144156
// If `useGlobal` is not true, then REPL creates a context when started.
145157
// This stores a reference to it or to `global`, whichever is used, after REPL has started.
146158
let context: Context | undefined;
@@ -271,6 +283,7 @@ export function createRepl(options: CreateReplOptions = {}) {
271283
const canLogTopLevelAwaitHint = service!.options.experimentalReplAwait !== false && !service!.shouldReplAwait;
272284
if (error instanceof TSError) {
273285
// Support recoverable compilations using >= node 6.
286+
const { Recoverable } = getNodeRepl();
274287
if (Recoverable && isRecoverable(error)) {
275288
callback(new Recoverable(error));
276289
return;
@@ -335,7 +348,7 @@ export function createRepl(options: CreateReplOptions = {}) {
335348
// the REPL starts for a snappier user experience on startup.
336349
service?.compile('', state.path);
337350

338-
const repl = nodeReplStart({
351+
const repl = getNodeRepl().start({
339352
prompt: '> ',
340353
input: replService.stdin,
341354
output: replService.stdout,

0 commit comments

Comments
 (0)