digital-loukoum / esrun

Simple wrapper around esbuild to execute a Typescript file
MIT License
171 stars 11 forks source link

Readline (or any input library) exits instantly without error #23

Closed JeremyMoeglich closed 1 year ago

JeremyMoeglich commented 2 years ago

When using readline or any other command line input library (I tested prompt-sync, cli-select, inquirer, prompts and readline) the program instantly exits without any errors

here's some code that results in the issue

// main.ts
import readline from 'readline'

async function input(msg: string): Promise<string> {
    return new Promise((resolve) => {
        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout,
        })
        rl.question(msg, (answer) => {
            rl.close()
            resolve(answer)
        } )
    } )
}

console.log(await input("test"))

console.log("This line will never be printed")
Gin-Quin commented 2 years ago

Oh, it's due to the fix for this issue.

When developing esrun, I tried to create no file on the file system. The output code is passed to the node process that just execute it.

The forementioned issue raised the bug that on windows, the string passed to the node process could be too long and cause an ENAMETOOLONG critical error.

The fix was too use stdin to pass the code to the node process. Stdin can be arbitrarily long so the bug was resolved.

But I didn't expect that it would also impact other programs that make an internal use of stdin.

We arrive to a point where the only viable solution would be to actually write a temporary file to pass to the node process. If the location of the temporary file is a classic hidden location it should not bother user experience, and this technique guarantees the behavior of esrun in a much safer way than using complex node arguments.

Gin-Quin commented 1 year ago

I start to work on that issue today. Sorry for the delay. It's an important issue, as any program that ask user input will not be able to run through esrun.

As said in my previous message, the issue first appeared because of a previous fix: the compiled code was passed to a node instance as a string argument. Like this: node --eval "<my source code>".

On windows if the source code was too long it used to raise an ENAMETOOLONG error.

The fix was to start the node process like this: node - and then to send to the process via stdin the code to execute. This works fine but... breaks reactivity in the cli - which is not acceptable.

I will introduce two execution modes for esrun:

  1. the first one send code via a command line parameter (default mode for every non-windows OS),
  2. the second one will write the code in a temporary file, execute that file, then delete the file (default mode for windows).

In second mode, the temporary file will be written in the node_modules/.bin directory, a location that should not break node modules imports and that won't be noisy for the user (there will be no flashing file in the IDE). Plus it is a folder that is usually git_ignored, so there is no risk for a temporary file to be commited in a git repository.

It will be possible to manually indicate which mode to use via a new option, though there is no use case that I can think of right now.

Gin-Quin commented 1 year ago

It is fixed since 3.2.13 🎉