privatenumber / tsx

⚡️ TypeScript Execute | The easiest way to run TypeScript in Node.js
https://tsx.is
MIT License
9.43k stars 144 forks source link

`require()` of malformed script uncatchably crashes the process #493

Closed broofa closed 5 months ago

broofa commented 6 months ago

Acknowledgements

Minimal reproduction URL

https://stackblitz.com/edit/stackblitz-starters-xedxss?file=load.mjs

Version

4.7.1

Node.js version

18.18.0

Package manager

npm

Operating system

Linux

Problem & Expected behavior

See the attached stackblitz MRE.

Basically I'm trying to require() user-supplied code that may be malformed. This causes the tsx process to die immediately. There appears to be no way of preventing this. (try-catch, uncaughtException event, and unhandledPromise event are all ineffective.)

You can see this by running npm start:

❯ npm start

> start
> tsx load.mjs

STARTING ...

[esbuild Error]: Expected "}" but found end of file
    at /home/projects/stackblitz-starters-xedxss/foo.js:1:67

~/projects/stackblitz-starters-xedxss
❯ 

require()'ing a module should behave similar to how running this directly in node works. E.g. node load.mjs produces the following...

❯ node load.mjs
STARTING ...

CATCH Unexpected token 'export'
FINALLY

... AND SETTLED

~/projects/stackblitz-starters-xedxss
❯ 

In other words ...

  1. Process should not die.
  2. Control should always return to the routine calling require().
  3. Any/all errors (e.g. from esbuild) should be catch-able by the calling routine

Note: Possibly related to issue #472, but as you noted the description there is a bit vague. Maybe this issue will help?

Contributions

wesbos commented 6 months ago

Also hitting this as well. In dev mode I have a malformed .tsx file and it causes the whole process to die. I was hoping to just catch the error and print the error and have it retry next run.

Perhaps nodemon might help here..

thelinuxlich commented 6 months ago

Maybe related? https://github.com/evanw/esbuild/issues/577

broofa commented 6 months ago

Additional info: This issue does indeed kill the process, by the way. For example, if you add a setInterval to the top of load.mjs:

import module from 'node:module';

// Timer to keep the process allive
setInterval(() => console.log(Date.now()), 1000);

console.log('STARTING ...\n');

...

... you'll see the process exits under tsx before the timer even has a chance to fire. Whereas in node it will happily chug right along logging once/second.

wesbos commented 6 months ago

Yep, node.js dynamic import or require can be caught, but tsx cannot.

try {
  const x = await import(`./file-with-syntax-error.js`);
  console.log(x);
} catch (e) {
  console.log(`caught error in try/catch block`);
  console.error(e);
}

Change the .js file with a .ts and you'll see the issue.

Right now my whole dev experience breaks with a syntax error and I have to a non-ignored file and save it to restart the process.

privatenumber commented 5 months ago

Fixed in https://github.com/pvtnbr/tsx/pull/7

privatenumber commented 5 months ago

Released in https://github.com/privatenumber/tsx/releases/tag/v4.8.1