tc39 / proposal-defer-import-eval

A proposal for introducing a way to defer evaluate of a module
https://tc39.es/proposal-defer-import-eval
MIT License
208 stars 12 forks source link

Nice Bonus Benefit: Module cycle problems can often be easily resolved #15

Open Jamesernator opened 1 year ago

Jamesernator commented 1 year ago

So at present with cyclic modules particularly those involving subclassing we can often have a nasty issue appear in that due to a cycle during extends the superclass may not be defined. (While cycles are often anti-patterns, they are also often unavoidable in a code-base with sufficiently many classes, e.g. components that depend cyclically on each other).

i.e. We might have the following

// A.js
import B from "./B.js";

export default class A {
   // ... do something with B
}
// B.js
import A from "./A.js";

export default class B extends A {}

Whether these modules successfully evaluate is dependent on whether A.js or B.js is executed first. Current solutions tend to be complicated messes or annoying to maintain as cycle sizes grow.

However lazy eval happens to be able to fix these types of cycles just by specifying lazy init for any modules that aren't needed during module evaluation. i.e. To fix the above cyclic evaluation issue the fix is as simple as:

// A.js
// This import will not imply a cycle now, so it will never be evaluated before A.js
import B from "./B.js" with { lazyInit: true };

export default class A {}

This is particularly nice as it can scale to basically any cycle (that is fixable) simply by marking any modules that are not immediately required as lazy init.

codehag commented 1 year ago

This is a really interesting use case, thanks!

guybedford commented 4 months ago

Just worked through this case again with @nicolo-ribaudo and we can confirm that it is still covered by the current specification as written. Although note that the converse - something like class A extends B.B where B is lazy may end up being an explicit error.