2010-11-09:
[2:19] <Wes-> deanlandolt: any idea why require.main returns main module's module object instead of exports?[2:19] * Wes- mulls syntax[2:19] <Wes-> <form name=area id=areaForm action="javascript:require(module.main.id).showArea();">[2:21] <Wes-> <form name=area id=areaForm action="javascript:module.main.showArea();">[19:37] <Wes-> deanlandolt: around?[19:38] <deanlandolt> Wes- hey, yeah...[19:38] <Wes-> deanlandolt: view source -- http://www.page.ca/~wes/BravoJS/demos/area/[19:38] <Wes-> Does that "read" sensibly to you?[19:38] <deanlandolt> still haven't had time to comb through everything...been slammed by enterprisey crap :-/[19:38] <deanlandolt> i'll read it now[19:38] <Wes-> deanlandolt: I know how that goes!!! :)[19:38] <deanlandolt> wait...read sensibly? like, width, length, area?[19:39] <deanlandolt> the only nonsensical thing is that area isn't disabled[19:39] <Wes-> deanlandolt: Like how the CommonJS interacts with the HTML in a usable bootstrappy sense[19:39] <deanlandolt> oh, you mean the underlying code :)[19:40] * Wes- fixes area :)[19:40] <Wes-> But, yeah[19:40] <deanlandolt> i like the action="javascript:require(module.main.id).showArea(); idiom though[19:41] <deanlandolt> but wouldn't javascript:module.main.showArea(); read a little better?[19:41] <Wes-> I think it may be a tad long, but in general, yeah, I think not relying on properties of window to access CommonJS is wise[19:42] <mschwartz> http://www.barryvan.com.au/2009/05/avoid-javascripts-with-keyword/[19:42] <Wes-> deanlandolt: Yeah, but module.main (previously require.main) returns the module variable, rather than the exports[19:42] <deanlandolt> ah, so yeah, module isn't a global[19:42] <Wes-> Now, WHY that is, I'm not sure[19:42] <mschwartz> Wes- that URL was for you[19:43] <mschwartz> seems to me, "with" is ideal for implementing modules client-side[19:43] <mschwartz> you inject script tag to execute JS[19:43] <mschwartz> instead[19:44] <Wes-> mschwartz: I've thought about that a number of times -- it's equivalent to "using namespace" -- but it has a couple of REALLY ugly sides (beyond the political issues)[19:44] <mschwartz> with (module) { try {eval(js_string);} catch (e) { ...} }[19:44] <Wes-> namely, 1) it's a huge performance hit on all modern browsers, 2) it is disabled in ES5 "use strict"[19:45] <Wes-> deanlandolt: Do you know why require.main returns the module variable instead of the exports?[19:46] <mschwartz> http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/[19:46] <mschwartz> While the feature was certainly mis-understood and possibly mis-used I'm not convinced that it's enough to be stricken from the record.[19:46] <mschwartz> I think it's incredibly valuable[19:46] <deanlandolt> Wes-: my best guess is because of the if (require.main === module) idom[19:46] <mschwartz> in rare circumstances[19:46] <Wes-> deanlandolt: require.main === exports works there though, right?[19:47] <deanlandolt> mschwartz: perhaps, but it's been *officially* stricken from the record :)[19:47] <deanlandolt> Wes- hmm, yeah, that's a good point...much more sane[19:47] <Wes-> I'm going to post another q[19:47] <deanlandolt> why does everyone do it the other way around, i wonder?[19:47] <mschwartz> you don't have to use strict[19:48] <mschwartz> at least not everywhere[19:48] <deanlandolt> mschwartz: no, you don't but strict mode is the /official/ mode going forward...as such its clear that with will probably never get the optimization love it would need to get it out of the slow path[19:49] <deanlandolt> maybe that could change, but that seems to be one thing tc39 actually agrees on :)[19:49] <mschwartz> does this bravo.js really emulate modules?[19:49] <mschwartz> can a module set a global variable?[19:49] <mschwartz> foo = 10;[19:50] <mschwartz> in the browser, I think you'll end up with window.foo = 10[19:50] <mschwartz> if you do with(something)[19:51] <mschwartz> the module would do foo=10 and set something.foo=10[19:51] <mschwartz> and you can throw away something[19:52] <mschwartz> FWIW, there are only two cases I've found for using with[19:52] <mschwartz> this seems like one[19:52] <mschwartz> another is in a templating engine[19:54] <deanlandolt> mschwartz: yeah, both legit cases...i agree[19:55] <mschwartz> I figure if there are two cases, there's likely more[19:55] <deanlandolt> hopefully by the time harmony comes around (and nixes with for good) they damn well better have a substitute[19:55] <deanlandolt> simple modules fixes the former case...and may help in the latter[19:55] <mschwartz> the foo=10 case[19:55] <mschwartz> that could really screw you over[19:55] <Wes-> mschwartz: Modules CAN set global variables, this is unavoidable using ES3 and web browsers -- but they won't set any globals by accident, providing the scripts are running in ES-5 strict mode[19:56] <mschwartz> you include someone's module and you ahve a global collision[19:57] <deanlandolt> mschwartz: sure, but there are far more dangerous implications for including arbitrary, unvetted modules :)[19:57] <mschwartz> Wes: using "with", a Module would have to set window.foo = 10 to set the global variable[19:58] <Wes-> no, there's other ways too[19:58] <Wes-> you can mis-purpose eval[19:58] <Wes-> or travel up the scope chain of a function's constructor[19:58] <Wes-> Using with offers no more protection than function-scope[19:58] <Wes-> and comes at a terrible price (no JIT)[19:59] <Wes-> (no ES-5 strict, and in the future, no ES-Harmony either)[20:00] <mschwartz> http://requirejs.org/[20:00] <Wes-> mschwartz: You're not really up on CommonJS, are you? :)[20:00] <mschwartz> I know enough about the mechanism of module[20:00] <mschwartz> modules[20:00] <mschwartz> "with" came to mind immediately[20:01] <mschwartz> because of the global variable thing[20:01] <mschwartz> like[20:01] <mschwartz> in a module, I could easily see someone doing:[20:01] <mschwartz> var id = 0;[20:01] <mschwartz> function one() {[20:01] <mschwartz> var myid = ++id;[20:02] <mschwartz> }[20:02] <mschwartz> function two() {[20:02] <mschwartz> var myid = ++id;[20:02] <mschwartz> }[20:02] <mschwartz> etc.[20:02] <mschwartz> works great in a sandbox[20:03] <mschwartz> sucks if my code has a global var id[20:03] <mschwartz> and I'm including some wizz-bang module that does the above[20:03] <Wes-> well, if you care about that particular problem, you should have probably invented a module system that didn't have that bug[20:03] <Wes-> Or just used CommonJS[20:04] <deanlandolt> mschwartz: if you care about that problem you should probably lint your included modules :)[20:04] <deanlandolt> Wes-: commonjs modules have that bug though[20:04] <mschwartz> why isn't that valid inside a module?[20:04] <Wes-> deanlandolt: No, he should use a module system that's not so broken that it runs abritrary code in the global context[20:04] <mschwartz> a module is supposed to run in a sandbox[20:04] <deanlandolt> ah, yes[20:04] <Wes-> deanlandolt: No they don't[20:05] <deanlandolt> hmm, well if modules are fn wrapped they wouldn't exhibit the bug but i thought gpsee doesn't fn wrap[20:05] <Wes-> deanlandolt: If that was a commonjs module the 'var id' would have been declared in the module-scope, not the global object[20:05] <deanlandolt> so var id would just get hoisted[20:05] <mschwartz> right[20:05] <mschwartz> I suggested with(module) {[20:05] <mschwartz> then var id is module.id[20:05] <mschwartz> (in module scope)[20:05] <Wes-> deanlandolt: gpsee doesn't fn wrap but it does not hoist variables from modules to global scoep!![20:06] <deanlandolt> so SM internals gives you some mechanism to prevent this?[20:06] <deanlandolt> this isn't an issue w/ main modules? i guess i just assumed it was...so all the better, i guess[20:07] <Wes-> deanlandolt: Yes - I am have extremely good control over the scope chain in GPSEE. There is a proxy between modules and the global that I can even use to further restrict up/down access if I want to implement any kind of sandboxing[20:08] <deanlandolt> ah, sweet[20:08] <mschwartz> wes: GPSEE runs in the browser?[20:08] <Wes-> deanlandolt: main modules it is ATM, but that's an implementation detail. Modules/1.0 does not document clearly what the right behaviour is. That is hopefully corrected in my current draft proposal.[20:08] <deanlandolt> mschwartz: no, but in the browser modules would typically be fn-wrapped and not exhibit the bug you referenced[20:08] <Wes-> mschwartz: no[20:09] <Wes-> deanlandolt: For non-program modules that statement is true. It's more interesting for program moudles in /1.x because the behaviour actually isn't defined[20:09] <Wes-> deanlandolt: A reasoanble /1.1 program module could exist inside script tags with no wrapper[20:11] <deanlandolt> well, none the less...better safe than sorry...if you're requiring arbitrary code you haven't vetted you could have other problems...js isn't secure yet[20:11] <deanlandolt> and SecurableModules certainly aren't SecureModules[20:12] <Wes-> *nod* - although at least with the draft I'm playing with, you need to purposefully /try/ to set global variables (i.e. by dereferencing window), even from a program module[20:12] <deanlandolt> yeah, forcing the fn wrapper does solve a few of these oddities[20:12] <Wes-> Interesting question, should program modules in the browser launch when window.onload, or when their dependencies have been satisfied?[20:13] <Wes-> deanlandolt: Definitely. The more I play with them the more I'm convinced we should have done this two years ago[20:14] <deanlandolt> Wes-: that's a tough question...onload fires way too late, right? so you really mean on dom ready, right?[20:15] <deanlandolt> even still, your modules might not care at all about the dom so that seems like it could be (in admittedly rare cases) a bit limiting[20:15] <deanlandolt> but if you need dom-ready just include a dom-ready module in your dep list :)[20:15] <Wes-> deanlandolt: Well, that's a good question right there... Right now, I'm running the main module as soon as possible, but the naive thought is "it should run on window.onload"[20:15] <Wes-> OTOH, you might be using the main module to draw the page (document.write)[20:15] <Wes-> or maybe you are using elements from the main module in event handlers[20:15] <deanlandolt> yeah, but you don't need onload for that...just dom-ready[20:16] <Wes-> like, form onclicks[20:16] <Wes-> So I guess the real questoin is --- is there a reason you can think of to artificially delay the running of the program module in the browser?[20:16] <Wes-> programmers who need the delay can always do this[20:16] <deanlandolt> Wes-: yeah, that's dom-ready[20:17] <Wes-> BODY onload = require(module.main.id).go();[20:17] <Wes-> (ugh at the verbosity, for now)[20:17] <deanlandolt> but it seems like it'd be a really elegant solution to have a dom-ready dependency[20:17] <deanlandolt> and that dependency would delay your execution until you can munge the dom[20:17] <Wes-> Yeah. There's still some interesting shaking-out for the browser side that hasn't really been discussed[20:18] <Wes-> deanlandolt: OTOH, if you have a dependency on anything other than the main module, you're stuff waiting for dom ready anyhow, right?[20:18] <deanlandolt> that'd be an easy module to write if it weren't for one complication...i guess it'd have to set an event listener so it'd probably have to return a promise or some such...[20:18] <Wes-> because you need that to perform script-tag injection of XHR?[20:19] <deanlandolt> perhaps not...console would probably be available immediately[20:19] * Wes- thinks[20:19] <deanlandolt> perhaps you're just doing logging (yeah, that's kinda stupid...but still :)[20:20] <deanlandolt> you're probably right though...no sense in complicating matters...may as well spec dom-ready and be done with it[20:20] <Wes-> I think I'm going to leave kick-off as earlier as possible, and if anybody needs it later they can delay it easily enough[20:21] <deanlandolt> i'll have to think on that...it would be nice to not have to double-wrap[20:21] <deanlandolt> (meaning, wrapping the contents of your wrapped module in a readiness fn)[20:21] <mschwartz> modules shouldn't document.write()[20:21] <mschwartz> solved[20:22] <mschwartz> the body onload works[20:22] <Wes-> Yeah, that's true - although you could make your readiness an export from the main module and at least get a nice looking event declaration :)[20:23] <deanlandolt> mschwartz: how does onload work? do you really want your module execution to be delayed until your images have loaded?[20:24] <Wes-> and the ads![20:25] <mschwartz> everything but the ads, actually[20:25] <mschwartz> but sure[20:26] <mschwartz> the important .js file was loaded in the head[20:26] <mschwartz> bravo.js[20:27] <mschwartz> fwiw[20:27] <mschwartz> almost all the ads I see these days are loaded in iframes or deferred via adding script tags to the dom[22:09] <kixxauth> Wes-: A browser loader may execute at any time (depending on the implementation) so...[22:10] <kixxauth> it SHOULD provide an event emitter / promise that indicates that DOM ready has fired in case the loaded modules do not get a chance to listen for it.[22:10] <kixxauth> is that what you guys are thinking?[22:13] <kixxauth> I don't think it would be good practice for loaders to defer exection of the module chain until DOM ready fires.[22:14] <kixxauth> There are too many things that a program might want to do before that point in implementations that allow it.
Logs by date :