Externalize Eventual Send in Endo Bundles
Most Endo applications currently need to import @endo/far to get E and Far. The Endo runtime could instead inject these as global variables, but linters, type checkers, and the language server all like these to be imported for various reasons. We can reduce the weight of bundles and also keep these imports, using Compartment Mapper tricks.
- Ensure that
@endo/bundle-sourceuses theendotag by default, or create a newendo:farbundle tag to indicate the external dependency onendo:far. - Alter the
@endo/import-bundleimportBundlesuch that it provides anendo:farbuiltin module that exportsEandFarand ensure that it uses theendotag. - And an entry to
@endo/far’spackage.jsonlike{ "exports": { "endo": "endo:far" } }.
cc @mfig for design review
Why? Generally globals are an anti-pattern.
OTOH, if these were global, could we avoid the Eval Twin problem https://github.com/endojs/endo/issues/1583 , and know that @endo/pass-style (the origin of Far) is instantiated exactly once? Could passStyleOf then safely recognize fars its Far made simply by brand check in its own WeakMap, which would then no longer need to be only an unobservable memo?
At #1583 I imagined we could solve the Eval Twin problem with compartments without using globals. Is that as easy?
Oh, I’ll edit above. The globals are not necessary in this design. Just threading an exit for builtin modules is. Also would degrade gracefully for other environments.
As for motivation, this would remove a copy of far from every contract bundle and also reduce instances to one. I do not think this is sufficient to completely eliminate the need to mitigate Eval Twins.
And the reason this is not sufficient to eliminate the need to anticipate encountering eval twins is that Endo is not the only environment we need to support. Eventual Send should work on stock node with npm eval twins as well.
At #1583 I imagined we could solve the Eval Twin problem with compartments without using globals. Is that as easy?
This solution would certainly be applicable to other cases. The big deal is that these modules would fall thru to making eval twins on other platforms. I think we should still design these modules to anticipate encountering eval twins.
I'm not sure how exports play a role. I would expect something more along the lines of:
- User code imports
@endo/pass-style - The
@endo/pass-stylepackage.jsonuses a subpath import:"imports": { "#pass-style-impl": { "endo": "endo:pass-style", "default": "./pass-style.js" } }, - The
index.jsof@endo/pass-styledoes something like:export { passStyleOf } from '#pass-style-impl'; - The bundler automatically considers any
endo:*package as an exit module - The bundle loader is responsible to provide a virtual module for the
endo:pass-styleexit module.
I’ve created a general issue for surfacing host modules. https://github.com/endojs/endo/issues/1653
Demonstration https://github.com/endojs/endo/pull/2422