tweag / inline-js

Call JavaScript from Haskell, and vice versa!
https://inline-js.netlify.app
131 stars 10 forks source link

Error reporting from node process #77

Closed Vorticity-Flux closed 4 years ago

Vorticity-Flux commented 4 years ago

First of all -- great library! Thanks a lot for making it!

When I've stared using it I had to spend some time digging inside it due to insufficient JS error reporting and my own inattentiveness.

Following code works as expected (prints to stderr): eval session "console.error('Hello JS world!')"

However following code fails silently (no errors/warnings, no exception, nothing at all). I guess this silent failure may be considered a bug. eval session "console.error('Hello JS world!');" The problem is I've used JS statement instead of JS expression. I know about the block quoter and I've used that before, but I've missed it once, typecheck passed and I've got silent failure at runtime so I had to dig quite deep to figure out what's going on.

I've ended up modifying index.js to do extra logging and only then my error has became obvious to me.

    try {
        result = vm.runInThisContext(expr, {
          lineOffset: -1,
          displayErrors: true,
          importModuleDynamically: (spec) => import(spec),
        })(require, ...jsval_tmp);
      } catch (e) {
        console.error("Node error: " + e.message + "\nExpr: " + expr);
        throw e;
    }

For the example above this prints Node error: missing ) after argument list followed by the JS expr being evaluated.

I guess the errors from vm.runInThisContext have to be reported somehow, maybe by forwarding to the calling process or at leased logged to the stderr as I've done above.

TerrorJack commented 4 years ago

As stated in the documentation here, eval performs async evaluation. It returns a thunk; for your example above, forcing the thunk will throw an EvalError Haskell exception containing the SyntaxError.

If you'd like to ensure that eval throws immediately upon an error at the JavaScript side, you can make a strict variant of eval with something like:

import Control.Exception

eval' :: forall a. FromJS a => Session -> JSExpr -> IO a
eval' s e = evaluate =<< eval s e
Vorticity-Flux commented 4 years ago

Aaaah.. Awesome! Sorry, I've completely missed that part. Thank you!