2.23.2012

Creating a module for nodejs

For this post, we are going to create a module for nodes to check the browser type, we are going to check the agent to guess if its touch, tablet, mobile, etc... its not 100% sure because we are only checking the agent but its a start... at the end we are going to upload to npm :)

Version en espaƱol

First lets create our directories, the module will be called "node-bowser", the structure of the files/folders will be like this:

node-bowser
  • lib
    • node-bowser.js
  • test
    • main.js
    • test.js
  • index.js
  • license
  • package.json
  • Readme.md
We won't use dependencies for the module but we are going to use vows for development, lets create the "package.json":

{
  "name": "node-bowser",
  "description": "bad! browser detection for mobile, tablet and touch",
  "version": "0.1.0",
  "author": "Ipseitycloud, Ivan Torres ",
  "keywords": ["browser detection ua user-agent mobile table touch"],
  "main" : "lib/node-bowser.js",
  "directories" : { "lib" : "./lib" },
  "devDependencies": {
      "vows" : "0.6.1"
  },
  "repository" : {"type": "git" , "url": "http://github.com/pinguxx/node-bowser.git" },
  "engines": { "node": "> 0.2.0" }
}


We are declaring all the necessary stuff for our module, name, description, author, keywords, which is our main file, code directories, dependencies for development (if we need prod dependencies we can put as dependencies without the dev), the repository if we have one and the node version this will work.

Lets fill out our "index.js" usually we just use this to expose the real module, looks like this:

module.exports = require('./lib/node-bowser');

We are only exporting whatever we got from the file "lib/node-bowser.js", lets see how this file looks:

var NBOWSER;
module.exports = NBOWSER = function(req){
    this._agent = req.header ? req.header('user-agent') : req.headers['user-agent'].toLowerCase();
    this._ismobile = (/iphone|ipod|android|blackberry|opera mini|opera mobi|skyfire|maemo|windows phone|palm|iemobile|symbian|symbianos|fennec/i.test(this._agent));
    this._istablet = (/ipad|android 3|sch-i800|playbook|xoom|tablet|kindle|gt-p1000|sgh-t849|shw-m180s|a510|a511|a100|dell streak|silk/i.test(this._agent));
};
NBOWSER.prototype.isMobile = function(){
    return this._ismobile;
};
NBOWSER.prototype.isTablet = function(){
    return this._istablet;
};
NBOWSER.prototype.isTouch = function(){
    return (/iphone|ipad|ipod|android/i.test(this._agent));
};
NBOWSER.prototype.isDesktop = function(){
    return !(this._ismobile || this._istablet);
};

Line1: We are creating our object var NBOWSER that holds all the functionality that we are going to export


2: we export the object that is the function we define here


3-5: our local variables... first we get the agent from req, could be a regular request object or express req, then lets check if this is mobile or table against our list of browsers that we currently support, we should update this frequently


6-11: this functions are just to know if the agent is mobile or tablet

12-14: in this function we check if the agent is touch, for now we are only checking for iOS and android

15: in this function we check we don't have mobile or tablet then we suppose to have a desktop browser... this is all our functionality, easy right?, lets do some testing with vows


Lets create our test folder and our first file "test.js"

/**
 *
 * node-bowser testing
 *
*/
var vows = require('vows'),
    assert = require('assert'),
    nbowser = require('../lib/node-bowser.js');

exports.test = vows.describe('check user agent').addBatch({
    'check mobile' : {
        topic : function(){
            var req = {headers : {'user-agent' : "iphone"}};
            return new nbowser(req);
        },
        'result its iphone' : function(bowser){
            assert.isTrue(bowser.isMobile());
        },
        'and its not desktop' : function(bowser){
            assert.isFalse(bowser.isDesktop());
        }
    },
    'check tablet' : {
        topic : function(){
            var req = {headers : {'user-agent' : "ipad"}};
            return new nbowser(req);
        },
        'result its tablet' : function(bowser){
            assert.isTrue(bowser.isTablet());
        },
        'and its not desktop' : function(bowser){
            assert.isFalse(bowser.isDesktop());
        }
    },
    'check touch' : {
        topic : function(){
            var req = {headers : {'user-agent' : "iphone"}};
            return new nbowser(req);
        },
        'result its touch' : function(bowser){
            assert.isTrue(bowser.isTouch());
        },
        'and its not desktop' : function(bowser){
            assert.isFalse(bowser.isDesktop());
        }
    },
    'check android' : {
        topic : function(){
            var req = {headers : {'user-agent' : "android"}};
            return new nbowser(req);
        },
        'result its android' : function(bowser){
            assert.isTrue(bowser.isMobile());
        },
        'and its not desktop' : function(bowser){
            assert.isFalse(bowser.isDesktop());
        }
    },
    'check android tablet' : {
        topic : function(){
            var req = {headers : {'user-agent' : "xoom"}};
            return new nbowser(req);
        },
        'result its android tablet' : function(bowser){
            assert.isTrue(bowser.isTablet());
        },
        'and its not desktop' : function(bowser){
            assert.isFalse(bowser.isDesktop());
        }
    }
});

Line 6-8:  load the modules needed


10: declare the suite and add the test cases


11-15: Create a new topic were we generate an object of type request and we add an imaginary agent of type "iphone", then we create our node-bowser object and we return it so the others test get it and test it


16-22: we check the agent is iphone and its not desktop


23...: All the rest of the testing are similar, we just send different agents and check for other things, any doubt let me know in the comments

Our main help us to run the test suite and its quite simple:

#!/usr/bin/env node
/**
 * Test runner
 *
*/
var nbowser = require('./test');
nbowser.test.run();


Here we are just getting the test described in the test file and run them.


License file only have the license used in this case AGPL


The "readme.md" that have a description of the module that we are going to put in github, its a good practice to describe in the readme the functionality so they can actually use it, check the readme in github


Good the module is ready, now lets add this to npm repository, but first lets install npm, its very easy just run this command in the console:

curl http://npmjs.org/install.sh | sh


If you install node in windows it now comes with npm if dont for some reason, check the info


Once we have npm, we have to create first our user:

npm adduser


It will ask for name, password and email, any problem ask me or check the documentation

Before publishing it, we need to check that its actually working as expected and it can be installed locally without problems if not publishing it will be problematic... to test it, go to your root folder of the module and do in the console:
npm install . -g


If everything its ok lets test it, go to another dir and install it:

cd ../some-other-folder
npm install ../my-package

And we use it in any dummy node program, if everything goes ok then we publish it.

In our root folder of the module run this:

npm publish

After some seconds we have a success... and we are set you can see your module in " npmjs.org ", for more information check the documentation for
 developers


We are set, now tell the world about your module and start using it


Fork the code

https://github.com/pinguxx/node-bowser

No comments:

Post a Comment