On Dec 11, 2013, at 3:08 PM, Tim Fox <[email protected]> wrote:
> On 11/12/13 13:50, Attila Szegedi wrote:
>> On Dec 11, 2013, at 2:22 PM, Tim Fox <[email protected]> wrote:
>>
>>> On 11/12/13 13:19, A. Sundararajan wrote:
>>>> The way Avatar/js project ( https://java.net/projects/avatar-js ) project
>>>> implements CommonJS/require is as follows.
>>>>
>>>> It creates a anonymous function code wrapping a module (say like http.js).
>>>> The anonymous function accepts 'exports' as argument. When you eval that
>>>> code at top level global scope, because of the anon function wrapping
>>>> around, all top level vars in a module code like http.js become locals of
>>>> that anon function.
>>> Isn't that the same as what I described in my last post?
>>>
>>> If so, the problem with that is that globals that aren't prefixed with var
>>> still leak.
>> I might be mistaken, but isn't that the best technique browser-based (pure
>> JavaScript) require() implementations can do too? Again, not justifying the
>> design (I'm saying this a lot today), just pointing out that a widespread
>> deployment base - namely, all browsers - might also suffer from the problem.
> tbh I don't think CommonJS is used much in browsers, but most probably any
> browser implementation would have the same issue with non var globals leaking
> too.
>
> Having said that it should be possible to get around the leaking non var
> global issue even using a pure JS require.
>
> If you pre-parsed the JavaScript before executing it (would need a JS parser
> written in JS for this, e.g. JSLint), you could, I guess prefix any non var
> globals with a namespace, e.g.
>
> myglobal = 123;
>
> function foo() {
> return myglobal;
> }
>
> would be transformed to:
>
> somenamespace.myglobal = 123;
>
> function foo() {
> return somenamespace.myglobal
> }
>
> Where somenamespace could be generated using a random UUID or such-like.
>
You can also prevent modules that assign to new globals from loading by forcing
a strict eval:
function loadModule(src) {
"use strict";
var _exports = {};
eval("(function(exports){" + src + "})(_exports)");
return _exports;
}
With this function
loadModule("x = 1")
will throw a ReferenceError.
var m = loadModule("var x = 2; exports.f = function() { return x }")
on the other hand will work, and m.f() will print 2.
Of course, this doesn't prevent the module script from modifying an _existing_
global, but this is as far as we can get.
Attila.