On Tue, Feb 23, 2010 at 12:49 PM, ibolmo <[email protected]> wrote: > Hey James. Thanks for contacting us. > > I'm taking a look at RequireJS. I've worked with Google Closure and it > appears that there's very similar language with RequireJS. > > While I continue to sift through the differences, could you outline > the differences in approach? > > Here's my summary of goog.require: > > Create file.js. > > Use goog.require for dependency with the namespace.class.name as the > argument: e.g. goog.require('goog.Uri'); > Use goog.provide for definition of a module: e.g. > goog.provide('goog.Uri'); > > To use this "uncompiled" you'd need to load base.js from goog (which > is effectively require.js) and do a goog.require('goog.Uri'); > Internally it'll try to load goog.Uri if you had also included the > file.js with the goog.provide. > > If you had not included the uri.js file then an error would be thrown > since there's no mapping. > > I think similar to requirejs is that you can "calcdeps.py" for > creating a file with all the dependencies for a file. You'd then > include the base.js, deps.js, and inside your other script or the page > itself do all the goog.require('goog.Uri') you'd need.
There are some differences vs. a goog.require (and dojo.require) vs. how RequireJS's require() works: - In RequireJS, there does not have to be a provide, all RequireJS cares about is that script tag that maps to the required dependency loads. This is nice because it can handle existing scripts without having to write them specifically for the loader. In fact, if the loaded file does not have dependencies, it does not need to use any require() calls at all. - RequireJS also allows you to load normal JS files, like say an API script from something like Google Maps or Facebook -- just put in the full URL to the script as a "dependency" and RequireJS will load it. When the script onload fires for that script tag, then RequireJS considers it loaded. - goog.provide also defines goog.Uri as an object in the global JS space. The dependency names in RequireJS are just path structures, and do not imply something defined in the global JavaScript space. I think this is particularly useful in cases like MooTools where a module may just augment native prototypes for example. - In RequireJS, if you want to define discrete modules that work with multiversion support, you can use require.def() and in the function wrapper for the module, return a value, and that value is given to any other function callback in require() that asks for that dependency. This feature is probably not so useful for MooTools code, but just mentioning it in contrast to a goog.require. > --- > > Bottom line this is great. It's proven and it's able to move forward. > > The irksome is that document.write is slow (see various Steve Souder > posts in regards to that. In particular: > http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/). RequireJS uses the equivalent of head.appendChild(script) exclusively for loading scripts, not document.write() calls. > We had previously talked about a sort of require system for MooTools > but we had already started using the YAML module header. And since the > Forge (PluginsKit) is using it extensively it's unlikely that we would > eliminate the header and instead use require calls. Although there's > huge advantageous to using procedural calls (in particular doing some > kind of Class Mutator for Requires... @credit davidwalsh). > > Davidwalsh brought the idea to use a Requires mutator for Class but > because of the redundancy with the YAML header we started picking at > the idea. > > My (untested) solution is to XHR for the (local, or by proxy, or by > any x-domain solution) file and parse its headers. Then recursively > grab other files and its headers and so on. Once you're done > collecting the dependency branch for that file you'd eval and pop each > xhr'ed file content. I am not familiar with "Class Mutator for Requires", will have to look it up. If you have a system in place now, then great. However, given our experience on Dojo, the duality of local domain vs xdomain causes more moving machinery, more things to break and for abstractions to leak. XHR loading is just not that great. Either you use eval or scripts with body set to XHR text to load the module, both hurt debugging, or you pull the header via XHR, but then do a script tag with src="" path to module, which depending on cache rules may cause another request to happen. Also, requiring a server side process to inject HTTP headers does not work so well with files on disk, it also forces a particular server solution on a developer. That may be fine for your community, but I do not think in general a loader should force those restrictions. It also does not work with local files on disk. As far as saving space, I do not believe an HTTP header gives any advantage over listing them in the script. Note that RequireJS only expects module/script names to be in the source file. The configuration of base path for those names is done as a config call to require with a paths: property, something that can happen once in the top-level HTML page. > > I'm not familiar with the requirejs specifications on synchronous or > asynch loading of scripts -- I think I saw a john resig commit in > regards to blocking or waiting for a script to finish downloading. I > think that XHR and buffering the file content until has the advantage > that you can eval when ever you want. And as shown by Steve Souder, > it's faster than document.write and you don't have the rendering > problems in most browsers. Dynamically appended script tags load async, it should allow the best performance over document.write and eval: at least doc.write in FF will block other rendering. And using eval is problematic. I tried to outline some of the issues in general with loader choices here: http://requirejs.org/docs/why.html Using async script loading can lead to a "flash of unscripted content" since the scripts can finish loading after first render. I believe this is generally preferred for performance reasons, but it is something that needs to be considered in constructing the UI. James
