Saturday, December 24, 2011
RequireJS 1.0.3 released
Small fixes, mostly for the optimizer. See the 1.0.3 fix list for:
Wednesday, December 07, 2011
almond 0.0.3 released
Changes in 0.0.3:
- Patrick Mueller had some suggestions on how to make it more friendly to CommonJS modules that are simply wrapped with define(function (require, exports, module){}) calls, and to allow out of order module listings in the built file.
- Works properly with jQuery 1.7+ versions that optionally call define().
Monday, November 21, 2011
RequireJS 1.0.2 released
Tuesday, November 15, 2011
Why not AMD?
His concerns as mentioned in the tweets:
- Isn't canonical in any JS runtime
- Inefficient by default
- Incompatible with JS.next
- Known temporary solution
Isn't canonical in any JS runtime
The goal is to create a grassroots effort based on real, multiple implementations that makes it canonical. I believe it is following the way to get something standardized. There are multiple implementations (requirejs, curl, dojo and mootools), and there are multiple higher level toolkits that register with it: jQuery, Dojo and MooTools.It is also based on real world experience supporting modular code in the browser. It is informed by Dojo's previous modular experience, and jQuery's needs for modular loading. I believe this places it in a better position than how modules in ES harmony are being designed, particularly since it can be opt-in that works with ES3 grammar.
Node adopted a variation of CommonJS modules, but Node's implementers have been very explicit about not picking up anything else from CommonJS, and they support their own non-conformant extensions, like module.exports. Node is a monoculture and very inward focused, and since it has sync IO, it is not concerned with browser needs.
Even if CommonJS were supported well in the browser today, there still needs to be a way to embed multiple CommonJS modules in a file. AMD is a great candidate for that format -- CommonJS never standardized on a "transport format" for this need.
I expand on this a bit more in the Why AMD document.
Inefficient by default
I assume this means that it allows separate modules to be loaded async. FWIW, the current state of ES harmony modules will allow separate file loading for each module. This works better for debugging.For AMD, you can get the "one script file at the bottom of the page" loading with the 750 byte almond AMD shim and runtime http loading.
I cannot see a better solution to this issue. If you have ideas I would like to hear them.
Incompatible with JS.next
Since JS.next/ES harmony modules do not have an implementation yet, I am not sure what this means. It still needs at least one good implementation to prove out the API. I think AMD can better inform the ES harmony effort since it has real deployment by web-based JS users, the harder environment to get right.Also, given that harmony modules uses new syntax and by default there is no global access, I think they are making it very hard to allow existing code to opt in to being a harmony module. I have given David Herman feedback to this effect.
I want to help make any harmony module implementation better based on AMD's real deployment. I go into it more in the aforementioned Why AMD page, but being able to set the exported value to a function, and the use of loader plugins to avoid nested, async callbacks for simple resources are of great value in any module system.
Known temporary solution
As you might gather from the above, I do not see it as a temporary solution. It has more legs than CommonJS modules because it works well in browsers and it can be used as the "transport format" for CommonJS modules.In addition, unless someone can get Microsoft to adopt rapid IE updates, even for old IEs, AMD will be around for a long time. It is a great transpile target for ES harmony module code that wants to run in older browsers. I am prototyping that effort, although I need to update to a real parser instead of regexps. I have a branch of narcissus that has the core parser/lexer/definitions that will run in ES3 browsers as part of that work.
All things considered, I would rather not work on JS module formats. I want to get on to building useful things for end users. But the CommonJS effort was deficient (but a great first effort given their design goals -- AMD uses a bunch of their work), and I do not think ES harmony modules are there yet. Instead of just complaining, I worked with others to work out something better and got implementations and actual, real adoption.
I'm open to something else that has done the above, but I have not seen it yet. Feel free to offer alternatives and feedback though. I just want to get to a good solution, but I'm also tired of waiting for something magical to fix the problem.
Thursday, November 03, 2011
RequireJS 1.0.1 released
This just has three small bug fixes in it (one in require.js, two in r.js). It was prompted by the release of jQuery 1.7 and wanting to make sure people could use the "namespace" optimizer option with it, now that jQuery 1.7 registers as an AMD module.
The bug fixes were related to:
- allowing full URLs for simplified CommonJS wrapped modules
- AST parsing of dependencies for modules that use a variable for the factory function
- catching more cases that should have the "namespace" optimizer option applied
Detailed list of changes for require.js and the r.js optimizer:
Tuesday, October 18, 2011
RequireJS 1.0 released
This release is basically the same as the 0.27.1 release. There was just one change, to a regexp used by the optimizer when it converts CommonJS modules to AMD modules via its -convert flag.
This release has been two years in the making. The code and APIs have changed over time based on feedback from the community, and now there are some very strong AMD loaders besides RequireJS. The AMD API and RequireJS have been proven useful and used in real projects.
I created a new Why AMD document if you want to learn more about why the AMD API exists and how you can use it.
I still plan on doing RequireJS releases and pushing modular JavaScript forward. This is not the end, but it is an important milestone. Thank you to the RequireJS and AMD communities for making this release.
Go use it already!
- Use it to build apps!
- Upgrade your library code to optionally call define()!
- Implement AMD in your favorite JS environment!
Friday, October 07, 2011
RequireJS 0.27.1 released
Just a small update with some bug fixes for 0.27.0. See the 0.27.0 release for the major functionality changes over previous releases.
I will wait about a week to see if this release seems stable for a 1.0 release.
Fixes:
- define(id, function () {}) where the function has require('') dependencies will now be scanned for dependencies. Allows for smaller universal module adapters.
- Loader plugin that depends on a different plugin's loaded resource works as it did in 0.26.0.
- Optimizer: update UglifyJS to 1.1.
- Optimizer: semicolons are inserted between files if concatenating would cause errors.
- Optimizer: always strip BOM files on all platforms when file transforms/concatenations are done.
- Optimizer: allow override of modules used in optimizer. Example.
- Optimizer: allow copying of .directories via build config option.
- Optimizer: Resolving paths for .js dependencies might fail if an appDir was not part of the config.
Sunday, October 02, 2011
RequireJS 0.27.0 released, 1.0 release candidate
This is the 1.0 release candidate. Unless things go horribly awry, I expect to do the 1.0 release in about a week. So please be sure to try it out soon if you have concerns. If you need more time to evaluate it, let me know.
From the release notes:
- require.ready() has been removed. In its place, use the domReady plugin. This allows better interoperability with other AMD loaders and better separation of concerns.
- A new wrap config option for the optimizer is available, for wrapping built code in a function. Allows for better API hiding and tiny builds with the almond API shim.
- The order plugin is improved for IE.
- Loader plugins can now have dependencies and they will work in the optimizer, as long as the dependencies work in the optimizer environment (Node, Rhino).
- The namespace config option for the optimizer is more robust.
- Removed require.def(), use define() instead.
- Removed module.setExports, use module.exports instead.
Sunday, August 21, 2011
almond: a small AMD shim loader
From the README:
Some developers like to use the AMD API to code modular JavaScript, but after doing an optimized build, they do not want to include a full AMD loader like RequireJS, since they do not need all that functionality. Some use cases, like mobile, are very sensitive to file sizes.
By including almond in the built file, there is no need for RequireJS. almond is 948 bytes when minified with Closure Compiler and gzipped.
Since it can support certain types of loader plugin-optimized resources, it is a great fit for a library that wants to use text templates or CoffeeScript as part of their project, but get a tiny download in one file after using the RequireJS Optimizer.
If you are building a library, the wrap=true support in the RequireJS optimizer will wrap the optimized file in a closure, so the define/require AMD API does not escape the file. Users of your optimized file will only see the global API you decide to export, not the AMD API. See the usage section below for more details.
So, you get great code cleanliness with AMD and the use of powerful loader plugins in a tiny wrapper that makes it easy for others to use your code even if they do not use AMD.
Wednesday, August 17, 2011
RequireJS 0.26.0 released, npm install requirejs
The big feature is being able to npm install requirejs to allow require("requirejs"). This allows you to:
1) Load AMD modules inside node without running a bootstrap script. It also fixes some path issues using traditional Node modules alongside AMD modules. So, now you can use requirejs inside Node to load AMD modules and use loader plugins:
var requirejs = require("requirejs");
requirejs.config({
nodeRequire: require
});
requirejs(["module/a", "module/b", "text!templates/one.html"],
function (a, b, template) {
//use a and b with the text template
});
2) Exposes the optimizer as require("requirejs").optimize() to allow dynamic server builds for people who like to do "only one script tag before end of body tag" development. With the "excludeShallow" optimizer config, you can still debug a single module/script while having the rest combined into one script.
Pretty sweet -- using JavaScript to run a server to optimize JavaScript on the fly but still get fine-grained JavaScript debugging. JavaScript turtles all the way down (until you hit the C turtle).
You can still use the r.js script to do command-line build optimizations. If you npm install -g requirejs, then you can use r.js as an executable (the requirejs package replaces the old requirejs-r package).
More information on the Use with Node page.
The requirejs npm package includes require.js for the browser. So, for web pages, load node_modules/requirejs/require.js to use RequireJS in the browser. As always, it is easy to get require.js for the browser without using npm.
Also notable in the release: UglifyJS in the minifier is updated to 1.0.6. The upside: has() branch trimming now works with the default minifier.
Other items from the release notes:
- Fixes for running under Node on Windows using the native node.exe builds that are available in the Node 0.5.x series. Now there is less of a need to use Java to drive the RequireJS Optimizer!
- Configuration is now done via a require.config({}) call, to get in line with the amdjs require API. The old require({}) method works on the global require() for backwards compatibility, but the suggested API going forward is require.config({}). The API doc has been updated to show proper usage.
- There is a namespace option now for builds, to allow moving require() and define() calls under a different namespace. This allows you to build an optimized file that uses RequireJS but does not interfere with any other AMD loader on the page, and you can make sure only your modules are loaded in that namespaced object.
- The default error behavior when a define() factory function throws an error is to not catch it. The catching done in 0.25.0 made it more difficult to debug. However, there are some situations where catching the errors is preferred. Setting the config value catchError.define = true will switch to catching the errors and allow processing via require.onError()
- Closure Compiler in the optimizer was updated. As a result, the code to invoke Closure Compiler changed, and will likely only work with the latest Closure Compiler release. You can grab a version known to work with the optimizer in the optimizer's lib/closure directory.
- There is now a pragmasOnSave build option, which is used in the require-cs CoffeeScript loader plugin build profile to strip out the CoffeeScript compiler after a build. The end result: tiny build layers of converted CoffeeScript code.
Tuesday, July 19, 2011
RequireJS node adapter now in npm
[Update July 21, 2011: GitHub users arlolra and JasonGiedymin clued me in to setting up r.js as a bin file that can be installed globally, making it much easier to use. The instructions below have been updated to reflect the changes.]
As asked for on the requirejs list, the RequireJS Node adapter + optimizer is available via npm now:
npm install -g requirejs-r
This will install the r.js file as a global bin/executable that is available for any of your Node projects.
To run main.js via RequireJS in Node:
r.js main.js
To optimize a web project using RequireJS, assuming app.build.js contains your optimization profile:
r.js -o app.build.js
"requirejs-r" is a bit of a funny package name, but it comes out of the requirements to use a directory for publishing to NPM, and the r.js name. If it seems useful, I may publish other RequireJS-friendly loader plugins under the "requirejs-" prefix. I may even push require.js to npm, but I am not sure it makes sense yet. If you think it would be useful to you, feel free to leave a comment on this issue.
I'll update the requirejs.org docs if this installation option seems to work out for people.
Monday, July 11, 2011
RequireJS 0.25.0 released, AMD advancing
It has been a few months since the last release, longer than normal. I have had some life changes (for good reasons) and I have busy at the day job. The interest in AMD loaders has picked up, and I have done some groundwork related to that interest. More information later in this post.
I wanted RequireJS 1.0 to be this release, but decided to name it 0.25.0 since I did some changes in the interest of better compatibility with other AMD loaders. Most applications should not notice the changes, but I want to have a release to shake out any problems on the edges.
Release Highlights
The awesome part: the optimizer is now just one JS file, r.js! It also doubles as a bootstrap script that supports the full capability of AMD modules and loader plugins in Node and in Rhino.
To use the optimizer, pass the "-o" option to r.js:
node r.js -o app.build.jsTo run your AMD-based project in Node (assuming server.js is your top-level AMD module):
node r.js server.jsRunning AMD modules in Node has more information. The optimizer docs have been updated to the new optimizer syntax, and the r.js script has its own project now, to allow releases that are decoupled from require.js.
Running r.js under Rhino is still supported, but you need to fetch a couple of JAR files first.
Other highlights:
- The loader plugin API changed to allow plugins to create cross-domain-accessible resources. The main use case: you use the text plugin to dynamically load text resources, but you want to deploy your scripts and text resources to a CDN. See the text plugin's implementation of writeFile() as an example.
- There is a global requirejs() function object that is the same as the global require() function object. This should allow RequireJS to work better in environments like Mozilla Chromeless, which already have a built-in require() function that does not have full AMD/loader plugin capabilities.
- It is now possible to specify the precise version of jQuery to allow in a RequireJS context. This is useful if you know of other scripts that load different versions of jQuery on a page.
- The "lib" directory configuration in package support was removed. It was always very awkward to support. Node no longer supports it, and that was the extra justification I needed to remove it.
- Relative module IDs are now relative to the related module ID, not the related module's resolved path.
- includeRequire in the optimizer config was removed, Use a paths config to include require.js instead. See the optimization docs for more details.
A New Home for AMD
Part of the RequireJS release delay was because the AMD API was moved off the CommonJS wiki and a set of compatibility tests were created.
While it was useful to hash out some of the basic goals and API on the CommonJS list, support for AMD on that list did not reach consensus. However, there has been continued and increasing interest in others making AMD-compatible loaders and tools. To avoid bothering people that would rather talk about other non-module things on the CommonJS list , a new AMD-focused discussion list and wiki has been set up and there is a set of compatibility tests.
AMD is advancing
More evidence that AMD is advancing:
- Alternate AMD loaders are available. Curl continues to advance, as well as the Dojo's 1.7 loader. Loadrunner has grown some basic support.
- There are at least two "AMD lite" projects, one in Ace, and one called DefineJS, that focus on basic AMD API support for when all the modules have been optimized into one file. The goal is to use a smaller bootstrap in optimized applications instead of a full standalone loader, like RequireJS.
- Node 0.5.0 supports the simplified CommonJS wrapper version of define(). While this support is very limited (no dependency array or loader plugins), it is a start to allowing some basic low-level module sharing between Node and browser apps better. See Kris Kowal's excellent Q library as an example of a module that works in both Node and in full AMD loaders.
- Look for better opt-in support for AMD in a couple of browser-focused libraries and toolkits later this year.
For RequireJS, I want to get to a 1.0 when:
- 0.25.0 has been shown to work well in existing projects.
- Do some work around require.ready: possibly using a domReady plugin/module with optional loader hooks, to help improve cross-loader compatibility.
- Try to finalize more of the loader plugin API with other AMD implementers, to make sure more code can be shared across loaders. The loader plugin API is a separate API from basic AMD support, so I may push out a 1.0 before that API is completely final, and go to a 2.0 branch for any backwards incompatible changes to the loader API.
Wednesday, April 06, 2011
On inventing JS module formats and script loaders
AMD is Winning
If you are one of those people that think they want to invent a module format or a script loader that works well in today's browsers, let me save you some trouble: a module format has already been worked out. Check out the Asynchronous Module Definition (AMD). There is still some room for innovation though, see near the end of this post.
If your script loader does not support AMD, it will be of very limited usefulness and in a sea of competitors that will make it hard for you to gain adoption.
So, for the module syntax, that problem is solved, and the solution is AMD.
A Solved Problem
Why is it solved?
- It has been discussed for more than a year and a half by multiple people, in the Dojo world, and on the CommonJS list.
- It has been implemented more than 5 times by different people.
- It has been deployed in real projects, the BBC iPlayer being a very visible one.
- It works in the browser, web workers, Node, Rhino, Mozilla Add-On SDK-based add-ons, and can be used in traditional Mozilla add-ons (Firebug will be using it).
- Many AMD implementations support loader plugins. You can add modules that know how to load other things as dependencies. While not strictly part of AMD, plugin systems greatly enhance a base technology.
I do not want to harsh your mellow, and I definitely want to follow your bliss, but just know the actual cost involved, and do your research first. Make sure you understand why AMD is constructed how it is, and what it really is.
It is not the traditional CommonJS Module format, but it can support similar concepts. However, it is different, take the time to figure out why.
Here is a handy gist with a summary of the AMD API, loader plugins, and some thoughts as to how it relates to modules implemented in Node, which are more like traditional CommonJS modules. In addition, you can read the RequireJS API docs, and the AMD wrapper format for traditional CommonJS modules.
If you think something was missed, feel free to ask on the RequireJS list, or on the CommonJS list, and enlighten us all. Or just send me an email or GitHub message if you want to talk privately. However, I believe most questions will be in the minor bikeshed/personal preference arena that do not ultimately matter for adoption. In particular, do not propose anything that requires the developer to do more typing that what is in AMD already. The format needs to be usable and easy to type. Discoverability is not a goal, daily usability is, and the AMD format is easy to explain.
Requirements
This leads to a discussion of other requirements. Here is what I believe are the minimum requirements for a module format in the browser, and they well-met by AMD:
- No globals: The module format needs a way for the developer to avoid creating global variables for each module they create. The format needs to be web-scalable, which means that some sites need the ability to embed two different versions of a module on a page. This normally means embedding in different "contexts" (the different versions do not need to talk to each other, just co-exist on the page), but it is a web-scale need. Seriously. We have seen it in Dojo. jQuery has seen it, it is the reason they have noConflict(). While noConflict() is nice, there are edge cases where it falls down. Know why that happens (in particular, dynamic script loading in IE: more than one script can execute before the first script's onload event fires).
- Allow for globals: at the same time, you want developers to be able to do want they want, in particular, some like to modify global object prototypes. Prototype and MooTools are valid ways to build web sites. So allow for it. This is one of my concerns with the ECMAScript harmony modules experimentation, but I think they know they need to allow for this, even if within a module loader instance.
- Do not require server transforms or think that using XHR+text transform+eval() is usable across all of web development. It is not. Here are some reasons why. They are fine for your boutique rails projects, but do not assume that translates well to the web at large, for instance, to serving JS files from disk for mobile widgets.
- You will need to use a function wrapper and a way to specify dependencies before that function wrapper is executed. You will be using script elements to load content (seriously, don't use eval, that is an evolutionary dead path), and dynamic script elements will load scripts async and out of order. A function wrapper will need to be part of the format.
- You need a way for modules to have a name. Otherwise you cannot combine them all together for optimization purposes.
- At the same time, it is best to allow source modules (the non-optimized ones) to not be named. This makes it much easier to move code around. This is not a hard requirement though, and I think one of the easiest to try to not support, see next section.
So you are not going to come up with a better module format. I know that sounds harsh, and for some of you that will be just the thing you need to hear to try something different. But I really am trying to save you some work. Again though, go for it if it really is your bliss, just know the amount of work you are taking on.
A better use of your time might be doing the best AMD implementation/script loader. In particular, you can choose some limiting design choices to help make it easier to meet/more compact:
- Do not support the simplified wrapper for traditional CommonJS Modules.
- Only allow named modules.
- Do not support loader plugins.
- Do not worry about supporting more than one version of a module in a page. The module format allows for it, which is the most important aspect, so module authors can code for it if they wish. However, most sites can get away without needing a loader that can actually support loading multiple versions.
If you make a script loader that does not understand AMD, it will be a boutique loader, and not something that fits all of front-end development, and limits the ability to share code with other JS environments. Which is fine, boutique businesses can be really satisfying, just realize you are in a boutique, and do not over-sell the loader.
FAQ
These are odds and ends that do not fit above.
Why use modules or a script loader at all? Just server-side concat all your scripts!
The goal is to establish a larger ecosystem of shared code that works without puking globals all over the place. JavaScript is also not just jQuery (although I greatly appreciate the project), so it cannot rely on a jQuery implementation.
Not all environments can use server-side script concatenation (file-served mobile widgets), and it does not allow for more nuanced optimization like loading built layers on demand after initial page load. On-demand loading is really needed for large web apps like a webmail UI.
With tools like the RequireJS optimizer, you can still get the same effect of "concat all files". If you do not want to take the hit of downloading a script loader in that scenario, there is work underway to allow a simplified stub that removes the need for a full script loader. The Ace project uses a "mini-require" after they build the code to avoid loading the RequireJS script loader.
What about YUI 3 modules?
YUI 3 got a lot of things right with their modules, in particular designing for async up front. However, I believe the way they implemented the module name-to-JS-variable-name mapping is not right. It requires knowledge of two names that allows for easy typos and creates the opportunity for a naming conflict on the Y object. For instance:
YUI().use("io-base", "my-module", function(Y) {
//Where does .on() come from? Did 'my-module' add it?
//Did 'io-base'? What if both tried to add it?
Y.on(...);
//'io-base' creates the 'io' property on Y.
//How is that known? Should it be 'ioBase'?
//What else does 'io-base' add to Y?
var request = Y.io(...);
});
In short, too much magic that requires extra documentation. YUI 3 has very nice documentation so that helps, but I do not believe that approach scales as well as AMD.
Is AMD a CommonJS specification?
No, it is a proposal, but with lots of implementations and real use. Not all participants on the CommonJS list believe it should be a elevated to "endorsed spec" status. Those participants wish browsers would grow better base technology and/or they want to maintain stricter compatibility with traditional CommonJS modules, which were not designed primarily for async loading environments like the browser.
Any browser technology change will likely be for harmony module support which operate differently than traditional CommonJS modules, and AMD works well today in all JS environments. AMD is proven, and it can work on the server side. The RequireJS Node adapter even allows using NPM-installed modules in Node.
How does AMD relate to ECMAScript harmony modules?
They are unrelated, although hopefully the AMD work and the traditional CommonJS module work will help inform the harmony effort. I believe AMD modules will be easy to convert to harmony modules, but as the harmony work is still in progress it is hard to know for sure. The return value options in AMD may be more flexible than harmony modules, and it is unclear if loader plugins will work in a harmony module world.
AMD has the benefit of working in all the JS environments now, and it will work in the future, and I do not believe the syntax gains in harmony modules are a vast improvement over the typing cost in AMD, particularly if sharp functions are supported. That said, I hope to inform the harmony effort where I can to help make it the best it can be.
Who are you?
I'm James Burke (GitHub, Twitter). I maintained the original Dojo XHR-based script loader, maintained Dojo Core, created the Dojo xdomain script element-based loader, created RequireJS (formerly RunJS), and rewrote RequireJS about three times. I have strongly advocated for browser-friendly modules on the Dojo and CommonJS lists. I like Pina Coladas and getting caught in the rain.
Friday, April 01, 2011
RequireJS+jQuery project moved, updated to jQuery 1.5.2
Also, the sample project has gone back to using an integrated RequireJS+jQuery file as the basis for the example. Keeping RequireJS and jQuery separate and using the "priority" configuration option in jQuery has some edge case considerations that required more explanation than what most people need. However, the README in the sample project repository explains how to use the priority configuration if you prefer to use that option.
Monday, March 14, 2011
RequireJS 0.24.0 Released
Themes for this release: IE 9, better jQuery integration, better loader plugins, and a CoffeeScript plugin:
- Support for IE 9. It has a non-conformant script loading behavior that necessitated the change. It would be ideal if IE 9 would change the behavior to be conformant.
- Changes to jQuery integration:
- jQuery 1.5.1 included in sample project.
- No more bundled RequireJS and jQuery file. RequireJS includes special code to detect jQuery as a module, so the combined file is not necessary, and this approach makes it easier to swap in new versions of jQuery as they are released.
- Because of that change, the jQuery sample project uses the new priority: config approach.
- allplugins-require.js has been removed. Plugins are no longer bundled with require.js or in the sample jQuery project. There are separate download links to the existing plugins on the download page. Special treatment of these plugins has also been removed from the require.js source, so those plugins behave like any other loader plugin.
- There is now a CoffeScript plugin. It makes it easy to code in CoffeeScript in the browser, it can participate in the optimizer optimizations, and it works in Node and Rhino. This is the best way to do cross-environment, modular CoffeeScript.
- Bug fixes.
This release is the "release candidate" for RequireJS 1.0, so please give it a whirl. There may be some small tweaks for the final release, particularly around how the optimizer is packaged, but if this release holds up well, RequireJS 1.0 should be out in about a month.
Monday, February 14, 2011
RequireJS 0.23.0 Released
Highlights
- The baseUrl defaults have changed. This will likely be the biggest impact, and may require a change in your code.
- Node is now the default JS engine used for the optimizer. It is blazing fast. However, not everyone can switch to the new hotness, so it is still possible to run the optimizer in Java/Rhino. But Node is the default, so if you use build.sh/.bat and want to use Java, update to buildj.sh/.bat.
- UglifyJS is the default minifier for the optimizer, since it runs in both Node and Rhino.
- The Node adapter is updated and should match Node's native behavior for any npm-installed module, but see the release notes for more detail.
The env plugin
One of my favorite things in this release is how the optimizer can run on either Node or Rhino. The optimizer is structured as a set of RequireJS modules and a new plugin: the env loader plugin. That plugin tells RequireJS to load a particular module based on the environment that is running RequireJS.
To indicate a module dependency that varies based on the environment, modules use dependencies that look like "env!env/file", and the env loader plugin will load "node/file" if in Node or "rhino/file" if in Rhino.
While the env plugin in its current form is not ready for outside use (in particular it needs more work to be useful in an optimizer build), I believe it shows the way forward for doing environment-based branching of module loading. In particular, it can be seen as a great alternative to the concept of "overlays" that have come up in some approaches to CommonJS packages.
jQuery integration
The integrated jQuery+RequireJS file has not been updated to jQuery 1.5.0 yet. I want to wait for jQuery 1.5.1 since it may contain a fix related to jQuery.readyWait which is used by RequireJS.
Next up
With the conversion to using Node as the default optimizer engine, the code is one step closer to a 1.0 release.
I want to do another release that breaks out the text, i18n and order plugins into a separate repo or repos. Right now they have a magic status that will cause problems in the long run.
I also want to deliver the optimizer just as one script file, instead of a small collection of modules as it is now. This is possible since the optimizer is written as RequireJS modules/loader plugins, and not something that would be easy to do if they were CommonJS modules. I may punt on this though in the interest of getting to 1.0 sooner.
It may also make sense to break out the optimizer into its own repo, but again I may punt on that to reach 1.0 faster.
So hopefully just one or two more releases before going to 1.0. Depending on the timing of jQuery 1.5.1, there may be one additional release in that set.
Monday, January 10, 2011
jQuery UI as AMD modules, for use in RequireJS
- Have the full range of jQuery UI available for use in different ways on different pages, but still get optimization benefits via the RequireJS optimizer.
- Dynamically load parts of jQuery UI based on user actions.
I created an example project too, showing how to load the Tabs widget, then when the user clicks on the second tab, dynamically load the Datepicker widget with its French localization.
The example project includes the RequireJS optimizer and a build profile. What is really neat: the unoptimized source project is about 25 HTTP requests. After the optimizer runs, it goes down to 8 requests, 4 of which are images.
There is more information on the conversion process in the README on GitHub. If the jQuery UI team is interested in supporting this more directly in their project, I'm happy to work with them to set up a define() stub/wrapper to allow the code to work even when an AMD loader like RequireJS is not in the page.
Enough talk, on the code:
Wednesday, January 05, 2011
RequireJS 0.22.0 Released
The highlights:
- A full plugin API that supports also including plugin loaded artifacts in optimized builds.
- Robust Node support: now can use npm-installed modules, .node add-ons, and modules on require.paths.
- Support for has.js optimizations in the optimizer, including dead code branch removal via Closure Compiler.
- Bug Fixes from 2010-12-21 through 2011-01-05.
This brings the code closer to a 1.0 release. I want the plugin API to settle a bit, see if others can build useful plugins with it, and then look at moving the optimizer from Rhino to Node. Hopefully just a couple releases away from a 1.0.
A side note: I goofed on the previous two releases, they should have been 0.20.0 and 0.21.0, but I released them as 0.2.0 and 0.2.1 respectively. This 0.22.0 release gets the version back on track.