#

Jump to Table of Contents

# Example: Packaging a YUI script with npm

This example will guide you through the recommended way to package a YUI module as an exportable package with `npm` on Node.js.

## Why Package?

Packaging up your scripts with `npm` makes them usable by others so they can benefit from all your hard work. There's nothing quite like having others use something you worked hard to create. So, why not make using your code as easy as possible?

## How to Create a Usable Package

There are 2 primary ways a Node.js user could use your YUI module, below we will discuss both ways as well as how to package up your code so they can both be available to your end user.

### Setting up the Package

First we need to set up the code so we can package it up all nice and neat.

We are going to use this simple version of a module in this example:

    YUI.add('my-module', function(Y) {
        Y.MyModule = function() {
            Y.log('Here');
        };
    });

This file will be saved as `module.js` in a directory all by itself.

Next we create a `package.json` file that describes our Node.js package:

    {
        "version": "0.1.0",
        "name": "my-yui-module",
        "description": "My YUI Module",
        "dependencies": {
            "yui": "*"
        },
        "main": "./index.js"
    }

Note that we are using `index.js` here as our main script and not `module.js`, `index.js` will be created below.

Your `index.js` file is the main file in your `npm` package, it's the file that executed when your module is `required`. We need to make a special `index.js` file that will load YUI and `use` our module.

### The All in One Package

In this example, we will export our module as a working YUI instance. So when the user `requires` our module they get all of YUI with it too. Here's the `index.js` file used in this case:

    var path = require('path');

    //setup our custom modules meta-data
    var meta = {
        'my-module': {
            requires: [ 'yql' ],
            //Give it a full path on the file system
            fullpath: path.join(__dirname, 'module.js')
        }
    };

    module.exports = {
        module: function() {
            var inst = require('yui').getInstance();
            inst.applyConfig({useSync: true, modules:  meta });
            return inst.use(Object.keys(meta));
        }
    };

This setup allows the user to do this:

    var mod = require('my-yui-module').module();
    mod.MyModule();
    mod.YQL('select * from ...');

At this point `mod` will be a YUI instance containing `my-module` and all of it's dependencies (`yql`, `jsonp`). This will allow you to create a module that the end user doesn't even have to that YUI is there. Making it easy for them to just `require` and run your module.

### Just Let Me Use It

The other type of user you want to deal with is the one that is already writing scripts with YUI on Node.js and they want to use your module too. In this case you need to make your modules metadata available so they can add it to their YUI instances. You can do this in your `index.js` to provide the metadata needed to load your module.

    var path = require('path');

    //setup our custom modules meta-data
    var meta = {
        'my-module': {
            requires: [ 'yql' ],
            //Give it a full path on the file system
            fullpath: path.join(__dirname, 'module.js')
        }
    };

    module.exports = {
        metadata: function() {
            return meta;
        }
    }

This will export the module metadata needed to allow `Loader` to load your module and use it as if it was a native module.

    var YUI = require('yui').YUI,
    var mod = require('my-yui-module');

    YUI({
        //Populating the modules config option
        //   with the metadata from the package
        modules: mod.metadata()
    }).use('my-module', function(Y) {
        Y.MyModule();
        Y.YQL('select * from ...');
    });

## Putting Them All Together

Now that we have them individually covered, let's put them together so you have one package that now works for both types of use cases. Here is the complete `index.js` file.

    var path = require('path');

    //setup our custom modules meta-data
    var meta = {
        'my-module': {
            requires: [ 'yql' ],
            //Give it a full path on the file system
            fullpath: path.join(__dirname, 'module.js')
        }
    };

    module.exports = {
        /**
        * Calling this method will create and return a YUI instance
        * with the modules in the meta data attached.
        * @method module
        * @return YUI
        */
        module: function() {
            var inst = require('yui').getInstance();
            inst.applyConfig({useSync: true, modules:  meta });
            return inst.use(Object.keys(meta));
        },
        /**
        * Calling this method will return the modules meta data
        * so that it can be passed to the YUI constructor.
        * @method metadata
        * @return Object
        */
        metadata: function() {
            return meta;
        }
    }

Now that we have our `index.js` file ready to go, we can now include our package and use it both ways.

    #!/usr/bin/env node

    var mod = require('my-yui-module');
    mod.MyModule();
    mod.YQL('select * from ...');

    // OR

    var YUI = require('yui').YUI;

    YUI({
        modules: mod.metadata()
    }).use('my-module', function(Y) {
        Y.MyModule();
        Y.YQL('select * from ...');
    });

Using this method to setup your YUI module, you can now publish your module to `npm` and share it with others.