Skip to content

Loaders that use childProcess.fork lead to endless recursion of processes #47615

@Jamesernator

Description

@Jamesernator

Version

v20.0.0

Platform

Linux 5.19.0-38-generic #39~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Fri Mar 17 21:16:15 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

loaders

What steps will reproduce the bug?

Use childProcess.fork within a loader, for example in the following loader:

// loader.mjs
import childProcess from "node:child_process";

const cp = childProcess.fork("./worker.mjs");
// worker.mjs
// Nothing needs to be in here for the behaviour to occur
// test.mjs
import readline from "node:readline";

function input(prompt = "") {
    return new Promise((resolve) => {
        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout,
        });
        rl.question(prompt, (answer) => {
            resolve(answer);
            rl.close();
        });
    });
}

// This is included so we can control when the process ends
await input(`[Continue] `);

And run node --loader ./loader.mjs ./test.mjs.

How often does it reproduce? Is there a required condition?

This happens consistently.

What is the expected behavior? Why is that the expected behavior?

The short answer is I'm not sure what should be done here. But it seems problematic that libraries (such as typescript) that uses childProcess.fork cannot be used within a loader without endless recursion of processes.

Perhaps the solution is simply not to carry over loaders onto child processes that are forked within loaders.

What do you see instead?

Loaders get continually created spamming the console with:

Loaded loader
(node:414589) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Loaded loader
(node:414589) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
Loaded loader
(node:414589) ExperimentalWarning: Custom ESM Loaders is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)

while also rapidly growing memory usage from the endless chain of processes.

Additional information

I noticed this because ts-node rapidly memory leaks in Node 20. I experimented it a bit and found that TypeScript is calling childProcess.fork which causes this error. i.e. A minimal loader that exhibits this behaviour would just be:

// loader.mjs
import ts from "typescript";

// Haven't even written any hooks yet

Using this loader with node --loader ./loader.mjs ./test.mjs will rapidly consume all memory on the machine until the OS kills the process (if not terminated sooner).

Metadata

Metadata

Assignees

No one assigned

    Labels

    loadersIssues and PRs related to ES module loaders

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions