Feed back and proposal for modules: allow importing ES5 files

Alex Russell alex at dojotoolkit.org
Mon Sep 24 07:00:48 PDT 2012


Hi Shaofei:

Inline:

On Mon, Sep 24, 2012 at 7:22 AM, 程劭非 <csf178 at gmail.com> wrote:

> Thank you for replying, Alex.
>
> Replied inline.
>
> 2012/9/24 Alex Russell <alex at dojotoolkit.org>:
> > Hi Shaofei:
> >
> > On Sep 22, 2012, at 6:29 PM, 程劭非 <csf178 at gmail.com> wrote:
> >
> >> Hi, everyone,
> >>
> >>
> >> I noticed that current importing grammar will not work for ES5 files,
> >> I mean there is no way to import one or more es5/es3 files as a module
> >> and import variables from it.
> >>
> >> The problem is:
> >> 1. There are no "export" keywords in a es5/es3 file, no variables are
> exported.
> >> 2. They might be using more than one files but current mudule grammar
> >> allows only one file as one module.
> >>
> >> When the new standard(es6) comes out, I guess a big number of
> >> libraries need updating. And before they finish their work, I think we
> >> need a cheap solution for the new code(es6) to use old
> >> libraries(es5/es3) without modifying their code
> >
> > One option here is for you to create an export "wrapper" for them, in
> essence a separate file that requires the old library be loaded which then
> exports the library's symbols through an export. Not pretty, but it
> requires no code changes for well-designed libraries.
>
> I tried to find a way to make a wrapper but I failed.
>
> Consider I have a file
> // mylib.js
>
> //depends on jQuery
> $(......).attr(......)
>
> When importing it as a library
>
> //There is no way to add $ to it's scope
> //except polluting the global object
> import "mylib.js" as myLib;


Right. What I'm suggesting isn't that you'll be able to prevent the global
from being augmented, rather that if your goal is to take an *already well
behaved* library and wrap it with modules, that's possible.


>  >> For the two points, I was considering two solution:
> >>
> >> 1. Export all global variable by default.
> >>
> >> Anonymous function could be used to protect the global namespace and
> >> most libraries are already using it. So I don't think "export" is
> >> needed.
> >
> > You inadvertently identified why we need "exports": it's very difficult
> what is "global". In particular, what should be exported in the case of a
> file that includes:
> >
> > var f = function(param) {
> >   thinger = param;
> > };
> >
> > // ...
> >
> > if (someGlobalConfigurationSetting) {
> >  f("howdy!");
> > }
> >
> >
> > ?
> >
> >> Exporting all global variable will not pollute the module's user's
> >> namespace for we still need "import" phase.
> >
> > Perhaps instead of "global" you mean "the top-level IFFE"?
> >
> > In that case, it's easier, but then it depends on the IFFE both being
> executed (it's not a static form here) and there being only one. Or is the
> suggestion that a file like this should export both a and b? And what will
> the value of c be?
> >
> > // example.js
> >
> > (function(p){
> >  var a = p;
> > })("hello");
> >
> > (function(p){
> >  var b = p;
> > })("world");
> >
> > var setValue = function(p){
> >   var c = p;
> > };
> >
> > setValue("it's a sunny day!");
> > setValue("it's raining in London");
> >
> > // end example.js
> >
> >
> > As you can see, at the limit, this creates some serious hazards for
> violating the data-hiding provided by closure-bound variables. Suddenly
> importers can not only see these internal names, but watch their values
> change!
>
> Perhaps I'm not expressing clearly.(Sorry I'm not a native speaker.)
>
> I'm not saying that  we should export variables inside a IFFE.
>
> I mean that :
>
> //example.js
>
> var $;
> // for ES5 $ should be a property of global object,
> //I mean even without “export”, Module instance object
> //should have a binding for "$" when example.js imported
> //as a Module
>
> (function(){
>
>     $ = function(){
>     }
>     // $ could be changed
>
>     var $2 = function(){
>     }
>     // $2 will not be imported
>     // because it's in a IFFE.
> })();
>
> -----------------------------------------
> // somewhere
> // Variant A:
> import "example.js" as myQuery;
> import $ from myQuery;
>
> // Variant B:
> module myQuery = "bar.js";
> import $ from myQuery;
>
> //$ should be able to be used here


I see. It's unclear, then, how this sort of thing works with conditionals
and "this" assignment. E.g.:

// conditional.js
if (false) {
  var thinger = "whatevs";
}

print(thinger); // undefined

this.thinger = "whatevs";

print(thinger); // "whatevs"
// end conditional.js

I think you can make a strong argument that since it's the user of the
module that is deciding how to use it, "this" assignment not having the
normal side-effects is fine...although I expect legacy scripts to point to
a "this" which isn't module scope but rather is a global. The "var" thing
points to a deep vein of difficulty -- notably the inability to reason
about the exports in a reliable way.

I'm curious what others thing about this.


>  >
> >> 2. Allow importing multiple files as one module.
> >>
> >> This will completely decouple file and module. We need to modify the
> >> ModuleSpecifier grammar:
> >>
> >> ModuleSpecifier ::= StringLiteral | Path
> >> ===>
> >> ModuleSpecifier ::= ( StringLiteral | Path ) ( "," StringLiteral | Path
> )*
> >>
> >> With this, for example, if I'm using a RSA library like
> >> <http://www-cs-students.stanford.edu/~tjw/jsbn/>, I can do the
> >> following:
> >>
> >>
> >> import "jsbn.js","prng4.js","rng.js","rsa.js" as RSA;
> >>
> >> If I want to use a module depend on jQuery1.3.2, I can do:
> >>
> >> import "jQuery1.3.2.js","MyModule.js" as MyModule;
> >>
> >> I've mentioned this idea in a reply, post it as a separate thread to
> >> get more feed back :-)
> >
> >
> > This is interesting. Do you have a proposed resolution mechanism for
> conflicts? We had such a thing in the old traits system for classes, but I
> don't think it has survived anywhere.
>
> Do you mean name conflict?
>
> If "jQuery1.3.2.js" and "MyModule.js" are all ES5 style (no module
> system used). There should not be any conficts or they will not work
> in ES5.
>

That's not true. One will simply overwrite the other. There's a default
resolution mechanism there (last wins). Let bindings and module forms
create a new static early-error scenario that we didn't have before.


> This is different from
> import "jQuery1.3.2.js" as jQuery;
> import "MyModule.js" as MyModule;
>
> The declaration
> import "jQuery1.3.2.js","MyModule.js" as MyModule;
> should behave like importing a file just like "jQuery1.3.2.js" and
> "MyModule.js" are copied together.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120924/530d76bb/attachment.html>


More information about the es-discuss mailing list