How do I use the Optimization Tool?§ 1

See the general optimization page for basic set-up. Also see the jQuery doc page for a good way to set up your project, even if you are not using jQuery.

How can I provide a library to others that does not depend on RequireJS?§ 2

If you are building a library for use on web pages that may not use RequireJS or an AMD loader, you can use the optimizer to combine all your modules into one file, then wrap them in a function and use an AMD API shim. This allows you to ship code that does not ship with all of RequireJS, and allows you to export any kind of API that works on a plain web page without an AMD loader.

almond is an AMD API shim that is very small, so it can be used in place of require.js when all of your modules are built into one file using the RequireJS optimizer. The wrap build config option will put a function wrapper around the code, or you can provide your own wrapper if you need to do extra logic.

See the almond project for details on how to build with the API shim and with wrap.

If you need to dynamically load code after a build, then using almond+wrap will not be sufficient as almond cannot dynamically load code. Instead, you may want to namespace your use of require/define. See next section.

How can I namespace my code to play well in other people's pages?§ 3

If you want to provide your code to web sites that may not use an AMD loader, and you need to dynamically load code, doing a simple one file build with a wrapper is not enough. You also may want isolate your loading needs from the page's AMD loader.

There is a namespace build option that does the following:

  • Renames requirejs, require and define uses to have "namespace." in front of them.
  • If the file does an existence check for define, in the following form typeof define === 'function' && define.amd, then it will prefix the define references with "namespace.".
  • If require.js is included in the built file, it will make sure it exposes the "namespace." versions of the API.

Do not code your source with namespace.require()/namespace.define() calls, but rather use require()/define() as you normally would, then use the optimizer to do the renaming.

How can I download all script dependencies in parallel?§ 4

Using require() and define() to define script modules and dependencies is an efficient syntax for indicating related code. However, for deploying code in the browser, it may not lead to the best overall performance. To find nested dependencies, a script has to be fetched, then a require() or define() call in that script might trigger other script downloads.

The Optimization Tool allows a quick way to build all your scripts into one file, so only one script download is needed for your page.

However, if you have many pages in your web app, it may make more sense to optimize your scripts into a set of two or three optimized layers:

  • One layer for common toolkit code, like jQuery, Dojo, Prototype or MooTools (toolkit.js). It may make sense to roll this layer in with the appcommon.js layer.
  • One layer for common web app code (appcommon.js)
  • One layer for page-specific code (page.js)

Ideally you could do that layering after you finish development, and tune those layers for optimal, parallel download of the files, without having to change all your scripts.

This is possible with RequireJS:

Script modules/files specified in the config's priority array will be downloaded in parallel before any other script dependencies are traced. Note: resources loaded by loader plugins (like 'text!template.html') cannot be specified in the priority array: the priority mechanism only works with regular JavaScript resources.

This example builds on the sample jQuery project to demonstrate the approach:

Assume the project has the following structure:

  • app.build.js (the build profile used by optimization tool)
  • webapp
    • page1.html
    • page2.html
    • scripts
      • require.js (the loader)
      • appcommon.js (used on both pages, "appcommon")
      • jquery.js (used on both pages, "appcommon")
      • page1.js (lists the dependencies for page 1)
      • page2.js (lists the dependencies for page 2)
      • object.js (used on both pages, "appcommon")
      • event.js (used on both pages, "appcommon")
      • widget.js (used on both pages, "appcommon")
      • Dialog.js (used on both pages, "appcommon")
      • Slider.js (used only on page 2)
      • Tabs.js (used only on page 1)
  • webapp-build
    • this directory will hold the optimized files

page1.html might look like this:

<!DOCTYPE html>
<html>
    <head>
        <title>Page 1</title>
        <script src="scripts/require.js"></script>
        <script>
            require.config({
                priority: ["appcommon", "page1"]
            });
        </script>
    </head>
    <body>
    </body>
</html>

with appcommon.js looking like this:

define(["jquery", "object", "event", "widget", "Dialog"],
function () {
    //Just an empty function, this is a place holder
    //module that will be optimized to include the
    //common depenendencies listed in this module's dependency array.
});

and page1.js looking like this:

define([ "jquery", "object", "event", "widget", "Dialog", "Tabs"],
function ($,        object,   event,   widget,   Dialog,   Tabs) {
    ...
});

page2.html and page2.js would look similar, except referencing "page2" instead of "page1" and using "Slider" instead of "Tabs" in page2.js.

The build profile, app.build.js would look like this:

({
    appDir: "webapp",
    baseUrl: "scripts",
    dir: "webapp-build",
    optimize: "none",
    modules: [
        {
            name: "appcommon"
        },
        {
            name: "page1",
            exclude: ["appcommon"]
        },
        {
            name: "page2",
            exclude: ["appcommon"]
        }
    ]
})

Once the build is run, it will generate the contents of webapp-build that look similar to webapp, except that the contents are optimized. appcommon.js will contain the common modules, and page1.js will have all the modules page1 needs, excluding appcommon's modules and their nested dependencies.

The priority config value tells RequireJS to load appcommon.js and page1.js in parallel and wait before both are loaded before tracing dependencies. With those two files, along with require.js, all the dependencies in the page will be loaded with three requests, with the appcommon.js and page1.js scripts being loaded asynchronously and in parallel.