Modules loader define method
This is excellent, but I had been worried about a string/eval-based define() API as well.
Throwing this out there while I stew on the pros/cons of it (so others can as well): I wonder how terrible it would be to have this API define module bodies in terms of a passed function that, say, accepted and/or returned a module object?
Surely this can be dealt with by extending the CSP policy to allow script domains which are able to call System.define. Surely it is an equivalent permission to being able to load script from the domain anyway, when it is restricted to running in the outer scope only?
I think I must be missing something?
On Fri, Nov 1, 2013 at 6:47 AM, Guy Bedford <guybedford at googlemail.com>wrote:
Surely this can be dealt with by extending the CSP policy to allow script domains which are able to call System.define.
How is that different to extending the CSP policy to allow script domains to call eval/Function?
Surely it is an equivalent permission to being able to load script from the domain anyway, when it is restricted to running in the outer scope only?
I don't see how it is equivalent to loading scripts?
window.onload = function() {
System.define(['name'], [`export var name = '${document.querySelector('#name').value }';`)]);
};
function later() {
var nameModule = System.import('name');
alert(`Hello ${ nameModule.name }!`);
}
How is it restricted to running in the outer scope?
I suppose I am hypothesising that it might be possible to limit the invocation to the outer scope only in some CSP mode.
// allowed:
System.define(['some-module'], ['export var q = "p";']);
// not allowed:
(function() {
System.define(['some-module'], ['export var q = "p";']);
})();
In this way, your window.onload example would not be possible, and no dynamic injections would be possible in anyway that is different to running a typical script.
But yes, my assumption is that such a non-standard restriction might be possible.
On Thu, Oct 31, 2013 at 8:32 PM, Jeff Morrison <lbljeffmo at gmail.com> wrote:
Throwing this out there while I stew on the pros/cons of it (so others can as well): I wonder how terrible it would be to have this API define module bodies in terms of a passed function that, say, accepted and/or returned a module object?
This would mean allowing import
and export
inside a function,
which starts to break down the semantic meaning of what a module "is",
and how to refer to them. Any function would be allowed to import or
export. What does that mean? Does a function name now qualify as a
module ID? Why do import statements use string IDs?
If the function wrapping was restricted to only System.* calls to express dependencies, then it loses out on the cycle benefits of import and export: it would not be possible to adequately convert a module that used export/import to a plain function form.
For me, at least as end user, it seems more straightforward to just
allow module 'id' {}
. It also avoids the ugliness of having strings
of JS inside JS files. I appreciate it may have notable semantic
impacts though.
James
If we limit module 'm' { ... }
to Script then we still keep the flat
module hierarchy.
On 11/1/13, 11:32 AM, James Burke wrote:
This would mean allowing
import
andexport
inside a function, which starts to break down the semantic meaning of what a module "is", and how to refer to them.
No, that's why I said the function generates an instance of a Module
object imperatively (we're already in imperative definition land with
this API anyway).
No need for import
or export
On Fri, Nov 1, 2013 at 1:04 PM, Jeff Morrison <lbljeffmo at gmail.com> wrote:
No, that's why I said the function generates an instance of a Module object imperatively (we're already in imperative definition land with this API anyway). No need for
import
orexport
My understanding is that there is no way to express a mutable slot like the ones that import/export creates using existing syntax, or some property on an object.
I very well could be incorrect. Looking at this: harmony:module_loaders#module_objects
I cannot see how that might work, but the info seems sparse, or at least I could have misunderstood it.
Perhaps you know how a mutable slot could be expressed using existing syntax for creating Module objects? Illustrating how would clear up a big disconnect for me.
James
On 11/1/2013 1:28 PM, James Burke wrote:
Perhaps you know how a mutable slot could be expressed using existing syntax for creating Module objects? Illustrating how would clear up a big disconnect for me.
If I'm understanding what you mean by "mutable slot", the only way it
can be expressed currently is via source rewriting or with
. That is to
say, it is possible currently to emulate how module bindings work today,
it's just really ugly.
(I'm operating on the assumption that the Module constructor is still part of the spec):
System.define({
A: {
deps: ['B','C'],
factory: function(B, C) {
var stuff = B.doSomething();
return new Module({stuff: stuff});
}
},
B: {
deps: ['D', 'E'],
factory: function(D, E) {
return new Module({
doSomething: function() { ... }
});
}
}
});
On Fri, Nov 1, 2013 at 2:19 PM, Jeff Morrison <lbljeffmo at gmail.com> wrote:
(I'm operating on the assumption that the Module constructor is still part of the spec):
System.define({ A: { deps: ['B','C'], factory: function(B, C) { var stuff = B.doSomething(); return new Module({stuff: stuff}); } }, B: { deps: ['D', 'E'], factory: function(D, E) { return new Module({ doSomething: function() { ... } }); } } });
Do you know if the factory arguments are regular variable references, or are they actually an import-like mutable slot that at a later time may hold the Module value? I did not think it was possible that they could be mutable slots, those were reserved for import/export statements?
But maybe the factory args are mutable slot entities, instead of just variable references? If so, that fixes my disconnect. Still trying to understand the nuances with the mutable slots.
If they are just regular variables, I do not believe they work for a cycle, at least it does not for AMD-type of systems, as the factory argument would be undefined for at least one part of the cycle chain:
System.define({
A: {
deps: ['B'],
factory: function(B) {
return new Module({
prefix: 'thing',
action: function() {
return B.doSomething();
})
}
},
B: {
deps: ['A'],
factory: function(A) {
return new Module({
doSomething: function() { return A.prefix; }
});
}
}
});
James
On Oct 31, 2013, at 7:10 AM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:
I see that Jason added a Loader.prototype.define to his reference implementation. people.mozilla.org/~jorendorff/js-loaders/Loader.html#section-177. This is great. It is a much needed capability to allow bundling modules into a single file.
It allows you to do something like
System.define(['url-a', urlB], ['export var a = "a";', moduleBodyForUrlB]);
However, this is just another form of eval and will therefore not be available in CSP. Can we come up with something that works in CSP environments? How about?
module 'url-a' { export var a = "a"; }
As I said in the September meeting, eliminating the named declarative module form (a form which, you might recall, you went on record in the London meeting as saying was a mistake we'd regret... ;-P) is motivated by separation of browser concerns and ES concerns.
The answer to making this work in CSP is to (a) make the loader API sufficiently generic that we can (b) solve it in the HTML layer. So the way we've done that is to say that loaders have a polymorphic notion of what "module source" is -- it doesn't have to be a string. In the browser API level, the AppWorker (aka ServiceWorker aka NavigationController) will be introducing ways to load cross-domain opaque payloads that can be absorbed by some sinks in the platform that are allowed to absorb them (e.g. <img> and <script> tags). The browser system loader will then be specified to allow .define to take such cross-domain payloads.
There's no need for ad hoc language forms for peculiarities of the web platform, when they can much more cleanly be designed with web platform API's.
I see that Jason added a Loader.prototype.define to his reference implementation. people.mozilla.org/~jorendorff/js-loaders/Loader.html#section-177. This is great. It is a much needed capability to allow bundling modules into a single file.
It allows you to do something like
System.define(['url-a', urlB], ['export var a = "a";', moduleBodyForUrlB]);
However, this is just another form of eval and will therefore not be available in CSP. Can we come up with something that works in CSP environments? How about?
module 'url-a' { export var a = "a"; }
=P