#

Jump to Table of Contents

# Creating YUI Modules

In this example we will show you our recommended approach to creating your own `YUI` modules.

## What is a module?

A `YUI` module can be described as "any code that can be separated to run on its own". Many times, this code can be reusable in different ways.

### How is a module defined?

`YUI.add()` is a static method that registers a reusable module—essentially, it adds a module to the set of modules available to be attached to a YUI instance via the `use()` method.

Defining a reusable YUI module is as simple as providing a name and a callback function to `YUI.add()`.

    YUI.add('my-module', function (Y) {
       // Write your module code here, and make your module available on the Y
       // object if desired.
       Y.MyModule = {
           sayHello: function () {
               console.log('Hello!');
           }
       };
    });

Note that there are no parentheses after `YUI` when calling `YUI.add()` as there are when calling `YUI().use()`. This is because `add()` is a static method of the global `YUI` object, not a method on a specific YUI instance. Modules are registered globally via `add()` and are later attached to a specific YUI instance via `use()`.

The `add()` method accepts two optional arguments after the callback function: a module version string and a config object. The most useful option in the config object is `requires`, which allows you to specify an array of other YUI modules that your module requires. YUI will then be sure to load these dependencies before executing your module.

    YUI.add('my-module', function (Y) {
       // ...
    }, '0.0.1', {
        requires: ['node', 'event']
    });

After your module has been added via `YUI.add()`, you can specify its name in a `use()` call to attach it to a YUI instance.

    YUI().use('my-module', function (Y) {
        // The Y instance here is the same Y instance that was passed into
        // my-module's add() callback, so the Y.MyModule object that was created
        // there is now available here as well.
        Y.MyModule.sayHello();
    });

A module's `add()` callback isn't executed until that module is attached to a YUI instance via `use()`. Each time a module is attached via `use()`, the module's `add()` callback will be executed, and will receive as an argument the same YUI instance that will later be passed to the `use()` callback.

## How does YUI know about a module?

`YUI` gives you a few options on how to tell it about your modules. The simpliest way is to include your modules on the page after the `YUI` seed file.

### Local Modules

If all of your modules are wrapped in a valid `YUI.add` call, `YUI` will know about them just because they are on the page. The calls to `YUI.add` tell the `YUI` seed all that it needs to know about your modules and registers them with the system.

    <script src="/path/to/yui-min.js"></script>
    <script src="/path/to/my/module1.js"></script>
    <script src="/path/to/my/module2.js"></script>
    <script src="/path/to/my/module3.js"></script>

Once available, they can be used as you would expect:

    YUI().use('module1', 'module2', 'module3', function(Y) {

    });

### Configured Modules

The local use case may not be good for you if you have several modules that you would like `YUI` to know about. In this case, you would want to tell `YUI` about your modules so that it can fetch them when they are required.

To do this, you need to use one of the various ways to configure `YUI` and tell it about your modules.

In this example, we will use the `YUI.GlobalConfig` to tell all `YUI` instances about our modules (Note: this must come after the YUI seed file in the page's source):

    YUI.GlobalConfig = {
        modules: {
            module1: '/path/to/my/module1.js',
            module2: '/path/to/my/module2.js',
            module3: {
                fullpath: '/path/to/my/module3.js',
                requires: [ 'node', 'event', 'dd', 'yql']
            }
        }
    };

Now that we have told `YUI` about our modules, we can simply use them:

    YUI().use('module1', 'module2', 'module3', function(Y) {

    });

The advantage of this approach is that we now have all of our modules information in one simple location that can be created by a build script and will be much easier to maintain.

### Structured Modules

In larger projects, you may need to structure your modules in a common way if you have multiple developers working on the code. In this case, you can follow `YUI`'s model on this and structure your code to get the most use out of Loader.

When creating a module like the ones above, you can create your built files like this:

    ourmodules/
        module1/
            module1.js
            module1-min.js
            module1-debug.js
            module1-coverage.js
        module2/
            module2.js
            module2-min.js
            module2-debug.js
            module2-coverage.js
        module3/
            module3.js
            module3-min.js
            module3-debug.js
            module3-coverage.js

Now that your files are structed in a parsable manner, `Loader` can handle them without much of a configuration.

#### Local Static Files

    YUI.GlobalConfig: {
        groups: {
            ourmodules: {
                base: '/ourmodules/',
                modules: {
                    module1: {},
                    module2: {},
                    module3: {
                        requires: [ 'node', 'event', 'dd', 'yql']
                    }
                }
            }
        }
    };

By default, when `Loader` is attempting to fetch a static module, it will create a url using a few config options: `base` and the `modulename` that was requested.

    /<base>/<modulename>/<modulename>(-<filter>).js
    /ourmodules/module1/module1.js
    /ourmodules/module2/module2.js

Now when you `use` your modules, `Loader` will find them and load them dynamically.

#### Using a ComboHandler

There are several combo handlers for different languages, so we won't discuss them here. Basically a combo handler is an entry point on your server that accepts a query string of a list of files. The server then combines all those files and returns the output. This allows you to ask for multiple files but only use a few HTTP requests to fetch them.

`YUI` has always had this support built in for it's core files, but you can have this with your modules too. Configuring `YUI` to use a custom combo handler is extremely easy, let's modify the above example to use a combo server that's located here: `/my-combo`

    YUI.GlobalConfig: {
        groups: {
            ourmodules: {
                base: '/ourmodules/',
                combine: true,
                comboBase: '/my-combo?',
                comboSep: ';', //Defaults to &
                root: '',
                modules: {
                    module1: {},
                    module2: {},
                    module3: {
                        requires: [ 'node', 'event', 'dd', 'yql']
                    }
                }
            }
        }
    };

When `Loader` is attempting to fetch a set of combined modules, it will create a url using these config options: `root`, `comboBase`, `comboSep` and the `<modulename>`'s that were requested.

    <comboBase><root><modulename>/<modulename>(-<filter>).js<comboSep><root><modulename>/<modulename>(-<filter>).js
    /my-combo?module1/module1.js&amp;module2/module2.js;/module2/module3.js

Now you have a flexible, scalable and dynamic module loading system that will let you build large scale applications or simple websites.

## Shifter

If you want to dynamically create the `-min`, `-debug`, `-coverage` files inside your project, take a look at our Node.js based build system tool called Shifter.

## Custom Aliases

`YUI` uses aliases under the hood as module "shortcuts", for example, when you `use` "node" `Loader` doesn't fetch a `node.js` file, it actually fetches several files under the hood that make up the "node" alias. You can use this too with your custom modules:

    YUI.GlobalConfig = {
        groups: {
            ourmodules: {
                modules: {
                    all: {
                        use: [ 'module1', 'module2', 'module3' ]
                    },
                    foo: {
                        requires: [ 'all' ]
                    }
                }
            }
        }
    };

This will create an alias called `all` for the modules: `'module1', 'module2', 'module3'`. You can then `use` that module as you normally would. You can even use that module as a requirement for other modules.

    YUI().use('all');
        //or
    YUI().use('foo');