I generally try to make my slides visual aids instead of a crib sheet, which means they aren’t typically self-contained. So I should provide a little context for my earlier post on the Harmony module system.
First things first: this design has been a collaboration with Sam Tobin-Hochstadt, who’s been utterly indispensable, as well as discussions with the TC39 committee and the es-discuss mailing list.
One of the best practices on the web is Doug Crockford’s “module pattern,” which is a coding pattern for writing unobtrusive components that avoid stepping on the toes of other components. Design patterns are a recurring theme on the web: innovative users find workarounds to the limitations of web technologies, and as these patterns of use become popular, browser vendors and standards organizations can and should provide built-in support to ultimately alleviate the need for the workarounds altogether.
The modules in this design are second-class, that is, they are a static declaration form rather than a general expression form. This means that the imports and exports of a module are known statically to the compiler, which makes them more amenable to supporting lexical scope.
The general forms for using modules are simple and intuitive: a
module declaration binds a module and the
export form determines what definitions within it are shared with the outside world. You can access the exports of another module simple by selecting them with the usual dot-syntax (such as
UI.Widget), or you can bind local variables to the exports of another module with the
Modules can have cyclic dependencies, as long as the modules are all in scope with one another — much like function declarations.
These basic, simple features are part of the theme of usability and minimal intrusion into the development process: putting code in a module should be as convenient a refactoring step as possible.
var declarations or misspelled variable names!
Module declarations are scoped just like other declarations. They can be declared inline, they can be simple renamings of existing modules, or they can be loaded from external files. This latter form has much the same semantics as a
Notice that the client gets to name the module it loads, instead of the module naming itself. This is critical: it means that modules don’t have to try to contend for a global namespace and use painful naming techniques for defensively avoiding stepping on each other’s toes. They can also contain nested modules and happily name them whatever they like, without contention.
The last piece of the design is dynamic loading. Just because modules are second-class does not mean they cannot be dynamically represented as values. In fact, module instances are easily reflected as objects simply by referring to them in expressions. Module instance objects are essentially immutable “views” of module instances; you cannot modify the exports of a module instance, but you can dynamically query their properties just like any object.
Module loaders give you the ability to dynamically load modules, and even to create multiple isolated contexts in which to load them. You can even provide low-level hooks to create custom loading semantics for a given module loader. Dynamic loading makes it possible to achieve important web use cases like dynamic feature detection, conditional loading, or on-demand loading. At the more intricate end of the spectrum, you can do live upgrades, implement isolated and stratified execution environments like online IDE’s, and write security-critical code that runs untrusted code in restricted contexts.