00:23 | <rbuckton> | rbuckton: I do want to confer with you sometime in December (but not in the next few days) about the resource management, cancellation, and proxy revocation proposals. Do you attend SES's strategy sessions occasionally? |
00:28 | <rbuckton> | My suggestion was to just close over regular bindings, and when serializing determine if the binding is:
A side benefit would be that it would be an error to accidentally reference a variable that shadows a global. |
00:29 | <rbuckton> | To further clarify, we'd determine if a binding is rewritable or not rewritable, and if the binding is not rewritable, determine if its value is portable (i.e., serializable) or non-portable. |
00:30 | <littledan> | When blöcks was presented, there was a lot of skepticism about this particular aspect of the proposal. It is very deliberate that module blocks omits it. |
00:31 | <littledan> | I honestly don’t understand how we could make this mechanism work well enough, given how dynamic JS is and how this committee tries to meet expectations of all the edge cases working well (eg with eval) |
00:31 | <littledan> | I like that you have some details spelled out though |
00:32 | <rbuckton> | IIRC, the blöcks proposal wanted you to substitute the bindings explicitly when you instantiated the block |
00:32 | <littledan> | In particular I don’t know how “rewritable” would work. Module blocks is content with just reevaluating in the other realm. |
00:33 | <rbuckton> | In particular I don’t know how “rewritable” would work. Module blocks is content with just reevaluating in the other realm. |
00:33 | <littledan> | Ah Ok |
00:34 | <rbuckton> | The current proposal allows you to lexically reference another module and explicitly breaks that model, since you're not just looking up that name in another realm. |
00:34 | <littledan> | So the other thing is, given module blocks, you can define a system which serializes a list of things and then passes them as arguments to a default-exported function. I guess a bit more unergonomic due to the duplication though. |
00:35 | <rbuckton> | So the other thing is, given module blocks, you can define a system which serializes a list of things and then passes them as arguments to a default-exported function. I guess a bit more unergonomic due to the duplication though. |
00:35 | <littledan> | The current proposal allows you to lexically reference another |
00:36 | <rbuckton> | Another approach would be to go the WASM route where you have to explicitly provide any external module references when instantiating the Module , which would mean no lexical scoping. |
00:36 | <rbuckton> | That would still work with bundlers, though they'd need to emit a chunk of code at the bottom of the file that linked all of the declarations together. |
00:37 | <littledan> | Yeah, Nicolo has sketched out this chunk of code in a gist. It would work with module expressions + the importHook in the module constructor |
00:37 | <littledan> | I got the impression that V8 was highly skeptical of this hook. Module declarations are more limited in expressiveness; more “static” |
00:37 | <littledan> | Anyway there are probably bundler use cases that need the dynamic hook |
00:38 | <rbuckton> | If there was no lexical closure for modules, you could still have import {} from id but you'd need to define those ids when instantiating the module, i.e. await import(module { import foo; }, { bindings: { foo: module {} } }) |
00:39 | <Kris Kowal> | That would still work with bundlers, though they'd need to emit a chunk of code at the bottom of the file that linked all of the declarations together. |
00:39 | <rbuckton> | That would be roughly analogous to the blöcks proposal where you'd need to supply values for bindings. |
00:41 | <Kris Kowal> | Concretely, this is Nicolò’s sketch of a module expression and Module constructor bundle generator https://gist.github.com/nicolo-ribaudo/81f18db096659ac8447ca94f50f2c37a |
00:41 | <rbuckton> | You could even do that with module declarations and stitch them together using a
|
00:42 | <Kris Kowal> | In my opinion, module expressions fully solve the bundling problem. |
00:42 | <rbuckton> | Its definitely not as convenient |
00:43 | <Kris Kowal> | Pardon module expressions + Module constructor. |
00:44 | <Kris Kowal> | (ModuleSource constructor not being necessary to that end and if the committee is intransigent about ModuleSource providing a path to eval , I’m in favor of further separation of layers.) |
00:44 | <rbuckton> | In my opinion, module expressions fully solve the bundling problem. I assume that a pure module expression solution would do something like:
|
00:45 | <Kris Kowal> | Though, in my opinion, ModuleSource is no more egregious a path to eval than <script type=module src=*> . It is certainly not a direct-eval evil. |
00:46 | <rbuckton> | I mean, there's always import("data:text/javascript,console.log('hello')") :) |
00:46 | <Kris Kowal> |
|
00:49 | <Kris Kowal> | In any case, I think we get a lot of bang from the module harmony proposals even if ModuleSource is replaced with something like Module.parse that can confirm the integrity of a module string and reflect its import/export bindings. Bundlers need that and on the evaluator side, module expressions suffice. We would still want an ModuleSource inert constructor just to host the prototype , since module expressions have a source of that prototype. And, at the end of the day, that’s equivalent to what what we’d have with a full-power ModuleSource constructor under a no-unsafe-eval CSP. |
00:50 | <Kris Kowal> | Concretely though, new Module((module { import './foo.js' }).source, { importHook() { return fooModule; }) does the trick of remapping an import to a particular Module instance. You can extrapolate from there. |
00:52 | <Kris Kowal> | In fact, module expressions are preferable to module declarations as a vessel for bundles because the module can be injected verbatim between the braces of a module expression. |
00:53 | <Kris Kowal> | Though, no doubt in every case that matters, there will be a minification pass and a sourcemap, so that advantage isn’t likely to be realized in any case that matters. |
00:54 | <Kris Kowal> | Where module declarations shine though is that they do not require import() to trampoline into user space importHook functions, which shu hinted could limit their usefulness in production. |
00:56 | <Kris Kowal> | But the downside is that they place a new cognitive burden on developers, who will now need to choose between using lexical or stringy module specifiers on a case-by-case basis, depending on whether they want the bundle (or worker payload!) to come with its own singleton of a module or exit to the host’s singleton of the module. |
00:57 | <Kris Kowal> | That’ll be an attractive nuisance for the worker case, since each time you “add” an entrypoint module expression/declaration to a worker, that entrypoint will retain a separate instance of its module declaration graph and connect to shared instances from the host for any remaining stringy specifiers. |
00:59 | <Kris Kowal> | I think that’ll have some negative consequences for the ecosystem, where libraries will be compelled to export a module declaration instead of their own API, so that the consumer can decide whether they want to instantiate it or transport it. |
00:59 | <Kris Kowal> | And in fact, they do not need module declarations to have that choice. They get the same facility from module import reflection. |
01:02 | <Kris Kowal> | That is, postMessage can send an array of ModuleSources with a description of their linkage and the receiver can rehydrate the graph with Module and a little machinery, just like a bundle. |
01:21 | <littledan> | I think that’ll have some negative consequences for the ecosystem, where libraries will be compelled to export a module declaration instead of their own API, so that the consumer can decide whether they want to instantiate it or transport it. |
01:24 | <Kris Kowal> | Reflective imports would give you a module and module source, module bindings reflection would give you the shallow dependencies, import.meta.resolve would give you host resolution, recursive reflective imports would get you the whole working set. |
01:25 | <Kris Kowal> | Everything you need to construct a transportable artifact. |
03:50 | <littledan> | That would still work with bundlers, though they'd need to emit a chunk of code at the bottom of the file that linked all of the declarations together. |
05:19 | <Kris Kowal> | Given that the stated scope of the proposal is bundling, limiting the reach of module expression and declaration imports to a single file would obviate all of my concerns. The names need not even be lexical, just file local. |
07:57 | <sffc> | Michael Ficarra: the Google i18n team is voicing explicit support for Well-Formed Unicode Strings |
11:05 | <Rob Palmer> | We are proposing to defer the January plenary meeting by one week to avoid overlap with Chinese New Year. https://github.com/tc39/Reflector/issues/453#issuecomment-1335074233 |
15:15 | <littledan> | Given that the stated scope of the proposal is bundling, limiting the reach of module expression and declaration imports to a single file would obviate all of my concerns. The names need not even be lexical, just file local. |
15:16 | <littledan> | I still don’t understand the concerns you have though, Kris |
15:17 | <littledan> | What I really disagree with is when people state that the feature is only for bundlers |
16:18 | <Kris Kowal> | Ah, Nicolò stated that the feature was primarily for bundlers. I agree that it would also be used for transmission to workers, which is really quite similar. |
16:18 | <Kris Kowal> | postMessage-as-bundler |
16:20 | <Kris Kowal> | To wit, if we could postMessage into a file and revive it over HTTP, structured clone would be a bundle format. |
16:40 | <littledan> | Primarily != only |
16:42 | <littledan> | I need to think more about this ecosystem implications issue. I guess we already have an ecosystem thing going on where some people distribute bundled packages… |
17:14 | <Kris Kowal> | I’ll make a point not to misrepresent the intent. Regardless of the intent, Hyrum’s Law applies. It’ll be used in any way it’s found useful. |
22:23 | <ljharb> | bakkot: is there a reason that union makes sure other has a callable has method, when it doesn't use it? |
23:01 | <bakkot> | ljharb: for consistency with the other methods |
23:01 | <bakkot> | we decided they should all have exactly the same expected arguments |
23:02 | <ljharb> | hm, ok. i haven't looked at the others yet, so i'm assuming some of the methods use all three, some two, some one, but all of them require all three as you indicated |
23:03 | <bakkot> | yup |
23:03 | <bakkot> | also some of them switch which ones get used depending on the relative sizes of the receiver vs the argument |
23:04 | <ljharb> | ah right, ok |