debugging modules

# Guy Bedford (11 years ago)

If I load a module, where one of the dependencies of that module throws in its immediate execution, the module I loaded will return successfully, while the error will be thrown in the environment. There is no way to currently see the tree that caused that module to be loaded in the first place.

My worry is that we get random errors in third party libraries, without knowing how they even ended up being loaded.

I understand at a theoretical level that because of circular references, there is no single path for any given module execution, so that this doesn't make any sense.

At the same time, I loaded X, and got an error in Y, so I need some way to inspect the dependency relations between X and Y to know how it got loaded. If we consider this as all possible relations, things get very complex.

The thing is though, there is a single execution thread, which can throw back to the importing module. And I think that is more sensible, as that is the information that is useful to the user.

The question then is what to do with these "failed" modules. I would continue to store them in the module table as "failed", and anything that imports from them as also "failed", and not to return as a successful import but to rather invoke the import reject handler.

I think this is important to simplify debugging.

See related issue - ecmascript#2993

# Domenic Denicola (11 years ago)

This seems like a dev-tools problem, and/or an issue of how informative the promise rejection's .message should be. I don't see anything we should be doing at the language level.

# Guy Bedford (11 years ago)

If it is a tools problem, it becomes a much more complex problem.

Firstly note that the promise isn't rejecting, it is resolving correctly. That is if I have a module X:

X.js throw "this module throws";

Then:

System.import('X').then(function(m) { // this returns correctly, with m defined. });

So the only information we have is the environment exception that something went wrong executing module X. We have no information of what dependency chain caused this.

If we want to inspect the dependency chain, there is nothing to inspect, since we don't even know what loads might have caused it in the first place.

So there is no way for a debugger to tell the user anything useful apart from inspecting the entire dependency tree. The evaluation chain that was an explicit set of modules for ensureEvaluated, is no longer available for useful debugging.

# John Barton (11 years ago)

On Tue, Jun 24, 2014 at 12:53 PM, Guy Bedford <guybedford at gmail.com> wrote:

If it is a tools problem, it becomes a much more complex problem.

Firstly note that the promise isn't rejecting, it is resolving correctly. That is if I have a module X:

X.js throw "this module throws";

Then:

System.import('X').then(function(m) { // this returns correctly, with m defined. });

Surely this case must call reject(). What circumstances would call reject() if not the failure to import?

So the only information we have is the environment exception that something went wrong executing module X. We have no information of what dependency chain caused this.

If we want to inspect the dependency chain, there is nothing to inspect, since we don't even know what loads might have caused it in the first place.

So there is no way for a debugger to tell the user anything useful apart from inspecting the entire dependency tree. The evaluation chain that was an explicit set of modules for ensureEvaluated, is no longer available for useful debugging.

I don't follow all of this but using your example from es6-module-loaders/test for import('load/main') dependent on 'load/depError' which throws 'dep error', then we should be able to give an error like

Module Evaluation Error: 'dep error' in loads/deperror loaded by loads/main

google/traceur-compiler#1127

We can give line/col info with a bit of work in Traceur; it would be trivial in a native implementation.

If the spec does not allow this, then we need to fix it.

jjb

# Patrick Mueller (11 years ago)

"This seems like a dev-tools problem" seems like semantic problem with the design. Some people write dev-tools with user-land code, and so those people are screwed.

# Kevin Smith (11 years ago)

Firstly note that the promise isn't rejecting, it is resolving correctly. That is if I have a module X:

X.js throw "this module throws";

Then:

System.import('X').then(function(m) { // this returns correctly, with m defined. });

This needs to reject. Anything else is crazy-pants.

# Jason Orendorff (11 years ago)

On Tue, Jun 24, 2014 at 1:11 PM, Guy Bedford <guybedford at gmail.com> wrote:

If I load a module, where one of the dependencies of that module throws in its immediate execution, the module I loaded will return successfully, while the error will be thrown in the environment. [...]

I think it's just a mistake: a ReturnIfAbrupt is missing after EnsureEvaluated's recursive call to itself. That is, if something goes wrong during EnsureEvaluated, the error should be propagated. I filed a bug: ecmascript#2996

Separately, as you say below, the failed module stays in the registry without being marked as failed. So a subsequent loader.get() can return it; later LinkSets can depend on it. (read on)

[...] There is no way to currently see the tree that caused that module to be loaded in the first place. [...] My worry is that we get random errors in third party libraries, without knowing how they even ended up being loaded.

Oh, well, implementations should report the chain of imports that caused the throwing module to be loaded!

The spec doesn't get into error messages generally. It's a quality-of-implementation thing. A note might be in order though.

The question then is what to do with these "failed" modules. I would continue to store them in the module table as "failed", and anything that imports from them as also "failed", and not to return as a successful import but to rather invoke the import reject handler.

I think this is important to simplify debugging.

Sounds good. I agree.