Module naming and declarations
dherman at mozilla.com
Wed May 8 23:47:05 PDT 2013
On May 8, 2013, at 8:05 AM, Andreas Rossberg <rossberg at google.com> wrote:
> You seem to believe otherwise, but I think you still need to explain
> how any of the above cases is not sufficiently (or even superiorly)
> supported by lexical modules + the loader API.
The most important flaw of this is staging. The loader API lets you *dynamically* modify the registry, but those changes cannot be used by code compiled at the same time as the code that does the modification.
> In any case, I don't see how this observation necessarily implies
> _anything_ for the form of module *declarations*. I suspect that your
> thinking had very much to do with (naive) concatenation, but
> concatenation without a tool will never be possible for modules
> anyway. So it really is a totally moot point.
I think it's important not just to be able to write bundlers, but to be able to do the transformation in a fine-grained way. It should be possible to move module declarations around by hand, it should be possible for servers to make on-the-fly decisions about where to place module declarations, etc. And it should be possible to do this without greatly perturbing the shape of the resulting code.
Put differently, controlling where and when code is bundled together is something that sophisticated web applications do often and sometimes at fine granularity, and it's done by experts at web development who shouldn't have to be experts at writing compilers or reading their output. Consider Eric Ferraiuolo's examples of servers making decisions to speculatively bundle additional modules in a response to a request. These are decisions that are about network efficiency, and they shouldn't have to deal with code transformations at the same time.
> OK, let's get concrete and see how this works. Assume you are writing
> some subsystem or library. There are three phases.
> 1. Development. Most modules will typically be in individual files,
> that you import through external names...
> 2. Deployment. Once you're ready to release, you want to bundle
> everything into one file ("concatenation"). Either way, that requires
> a tool.
You don't necessarily bundle *everything* into one file. Large-scale apps may bundle things in various ways.
> With lexical module declarations, the tool will be similar, but
> distinguishes the set of module paths that you intend to export from
> the package. The resulting file will again contain all individual
> files wrapped into module declarations, but this time with lexical
> names (generated by some means -- the details don't matter since there
> is no intention of making them accessible; you could even wrap
> everything into an anonymous module). All import file names referring
> to non-exported modules are replaced by their lexical references. In
> addition, the tool generates a couple of suitable calls to loader.set
> for registering the exported modules. The names for those are picked
> in the same manner as in the other approach.
As I said above, this is broken. If we don't provide a declarative way to register modules, then they have to be added to the registry *in a different stage* from any code that uses them. This forces you to sequentialize the loading of different packages of your application, which is a non-starter.
What's more, when you start from your assumption #1 (and I do) that most modules will be in separate files, then lexical modules aren't buying the user much at all. Except for the cases where it makes sense to have small sub-modules that fit within a single file. As I've said before, I can imagine this being occasionally useful, but it's simply not important enough for ES6.
> The advantage of the latter approach is again that all intra-bundle
> references can be (1) cheap and reliable
Sounds like you're misinterpreting the semantics of static linking. I have clarified this several times already. References between ES6 modules are not dynamically indirected through a dynamic table. They are statically resolved at link time. Linked modules are every bit as cheap and reliable as lexical references.
> and (2) don't pollute the
> global namespace. At the same time, you are free to export as many of
> the modules as you like. So this approach is strictly more powerful,
> the user has control.
Except that as I explained above, without a way to register a module name declaratively, this forces you to load dependencies sequentially, which is unacceptable.
It also couples structural containment ("module X is conceptually part of package Y") with textual containment, which is strictly less flexible for controlling the delivery of the source over the wire.
> 3. Usage. In both approaches, the bundled file you have created
> contains a number of modules with external (logical) names. There are
> two ways to fetch them in another program: (a) either through a script
> tag, or (b) by calling loader.ondemand with the list of provided
> names. Both ways work equally for either of the designs!
Doing it through a script tag is sequentializing. I don't understand how loader.ondemand works if the contents of the file has to do a dynamic loader.set. Once again, this sounds broken from a staging perspective.
More information about the es-discuss