The Yepnope conditional loader

Introduction

I’ve been quite interested in this for a while, so now I thought I’d write about Yepnope.

For anyone that doesn’t know what Yepnope is:

“yepnope is an asynchronous conditional resource loader that’s super-fast, and allows you to load only the scripts that your users need.”

You basically use it to load certain scripts, only if they are needed. It works even better when you combine it with Modernizr, if you don’t know what that is, you should check it out.

An better explanation of using Yepnope would be this: When you have a script that works with a new HTML5 technology, such as JSON, but you may also have another “polyfill” script for older browsers to support/mimic this feature. This polyfill will only get loaded if you browser needs it. The term polyfill, in programming terms, means to fill the gap of the missing technology with code that will give you that functionality.

Below is a simple example of this:

yepnope({
    test: window.JSON,
    nope: 'json2.js',
    complete: function () {
        var data = window.JSON.parse('{ "json" : "string" }');
    }
});

Even from this example, you should get an idea of how you would use it.

Using Yepnope

I love the API, its really simple as easy to understand. You can tell from the fact that the Yepnope website is only one page! Another good thing about it is that Yepnope can be called in different ways. You can pass a String, an Array, an Object, or even Array of Objects! Crazy I know. See below for some examples:


yepnope('load.js'); //String

yepnope(['load1.js','load2.js']); //Array

//Object
yepnope({
    test : Modernizr.geolocation,
    yep  : ['load.js'],
    nope : ['polyfill.js']
});

//Array of Objects
yepnope([{
    test : Modernizr.geolocation,
    yep  : ['1.js'],
    nope : ['polyfill.js']
  },
  {
    test : Modernizr.json,
    yep  : ['script.js'],
    nope : ['json2.js']
}]);

Anything that is within an object is also known as a ‘test’ object. Below is an example of what can be in a test object:

yepnope({
    test :  /* truthy test */
    yep  : /* Scripts to load if test passes, Can be String, Array, Object, Array of Objects */
    nope : /* Scripts to load if test fails, Can be String, Array, Object, Array of Objects */
    both : /* Scripts to load everytime, Can be String, Array, Object, Array of Objects */
    load :  /* Scripts to load everytime, Can be String, Array, Object, Array of Objects */
    callback : /* Callback function for when each script is loaded */
    complete : /* Callback function for when all the scripts are loaded */
});

An important thing to note is, that any scripts passed in yep, nope, load and both, can be in any of the following formats:

yep: 'json2.js' //string

yep: ['json2.js', 'othercode.js'] //array

//object
yep: {
    'json-js' : 'json.js'
}

The great thing about passing an object of resources is that you can give them a name, making it easier to refer to them in the callback function as shown below;

    callback : function( url, result, key ) {
        if( key === 'json-js' ) {
            runApp();
        }
    }

Now the best way of explaining all of the above is to show you, so here you go. Below you will see that I’m passing an array of test objects to Yepnope, each showing how advanced a test can get:

yepnope([{
    test : window.JSON,
    nope : 'json2.js',
    complete : function() {
        var str = window.JSON.parse('{"name":"tom"}');
    }
},
{
    test : Modernizr.cssgradients,
    nope : ['gradients-polyfill.js', 'support.js']

},
{
    test : Modernizr.canvas
    nope : {
        'canvas-css' : 'canvas-polyfill.css',
        'canvas-js'  : 'canvas-polyfill.js'
    },
    callback : function( url, result, key ) {
        if( key === 'canvas-js' ) {
            runApp();
        }
    }
},{
    test : Modernizr.fontface
    nope : {
        'fontface-css' : 'fontface-polyfill.css',
        'fontface-js'  : 'fontface-polyfill.js',
        'fontface-code-js'  : 'fontface-code.js'},
    callback : {
        'fontcase-js'  : function () {
            //fontface-polyfill.js has loaded
        },
        'fontface-code-js'  : function () {
            //fontface-code.js has loaded
        }

}]);

Plugins – Prefixes and Filters

Yepnope comes with some nice Plugins, and they come in the form of Prefixes and Filters. You use prefixes in front of your script/css links. Below is an example of two Prefix plugins that come with Yepnope.

One is the Css Prefix plugin, which forces the type of the file to be “text/css”:

yepnope('css!mystyles.php?version=1532'); // loads as a style!

There is also the IE Prefix Plugin, the files provided only get load for IE6 or 7:

yepnope({ load: ['normal.js', 'ie6!ie7!ie-patch.js'] // ie6 or ie7 only (on patch) });

You can also create your own Prefix / Filter plugins if you so wish. To create your own Prefix or Filter plugins, you would do something like:

yepnope.addPrefix('bypass', function (resourceObj) {
    resourceObj.bypass = true;
    return resourceObj;
});

yepnope.addFilter(function (resourceObj) {
    resourceObj.bypass = true;
    return resourceObj;
});

As you can see they basically look the same. The noticeable difference is that with Prefix plugins you need to use a Prefix on the files, whereas the Filter when its included a page will be used on all files included using Yepnope.

I’ve create my own Prefix plugins, to give a better example of this.

The following Prefix plugin for Yepnope is to check if the browser is a Mobile Device (its not perfect but you get the idea):

/*! Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk)
* Mobile Prefix for Yepnope JS
* Licensed under the MIT License (http://www.webmuse.co.uk/license).
*/
(function(yepnope){

    var isMobile = nav.match(/ipad/i) ? true :
        (nav.match(/ipod/i) ? true :
        (nav.match(/iphone/i) ? true :
        (nav.match(/Opera Mini/i) ? true :
        (nav.match(/Opera Mobi/i) ? true :
        (nav.match(/Fennec/i) ? true :
        (nav.match(/android/i) ? true : false ))))));

    yepnope.addPrefix('mobile', function(resourceObj) {

        if( !isMobile ) {
            resourceObj.bypass = true;
        }

        return resourceObj;
    });

})(this.yepnope);

And you would use it like:

yepnope({
    load: 'mobile!script.js'
});

The second is a Prefix Plugin for adding your website address to the scripts, meaning you don’t have to type them out each time (for websites that need an absolute path):

/*! Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk)
* Website Prefix for Yepnope JS
* Licensed under the MIT License (http://www.webmuse.co.uk/license).
*/
(function(yepnope){

    yepnope.addPrefix('mysite', function(resourceObj) {

        resourceObj.url = 'http://www.mysite.com/' + resourceObj.url;

        return resourceObj;
    });

})(this.yepnope);

And then you would use it something like:

yepnope([
    'mysite!script.js',
    'mysite!script2.js'
]);

I also created a Filter plugin for HTTPS, essentially replacing the protocol if needed:

/*! Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk)
* Website HTTPS Filter for Yepnope JS
* Licensed under the MIT License (http://www.webmuse.co.uk/license).
*/
(function(yepnope){

yepnope.addFilter(function(resourceObj) {

    if( !resourceObj.url.indexOf('https://') && window.location.protocol == 'https:' ) {
        resourceObj.url = resourceObj.url.replace('http://', 'https://');
    }

    return resourceObj;
});

})(this.yepnope);

Summary

Yepnope is very powerful. I love how flexible it is when it comes to loading different scripts. If you haven’t used it I recommend it, you might be surprised at what it can do.

This entry was posted in Blog. Bookmark the permalink.

Comments are closed.